diff --git a/.golangci.yml b/.golangci.yml index 4b715a8d41..fc451adcff 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -41,6 +41,7 @@ linters: - govet - ineffassign - misspell + - modernize - revive - staticcheck - unused @@ -74,6 +75,12 @@ linters: # tab width in spaces. Default to 1. tab-width: 1 + modernize: + disable: + - any + - stringsbuilder + - omitzero + - waitgroup nakedret: # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 max-func-lines: 30 diff --git a/cmd/ec2geninfo/main.go b/cmd/ec2geninfo/main.go index 3717422802..797046bcd5 100644 --- a/cmd/ec2geninfo/main.go +++ b/cmd/ec2geninfo/main.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "regexp" + "slices" "text/template" "github.com/aws/aws-sdk-go-v2/aws" @@ -157,11 +158,8 @@ func getEC2Instances(region string, instances map[string]InstanceInfo) (map[stri cbrSupported := false if inst.SupportedUsageClasses != nil { - for _, usageClass := range inst.SupportedUsageClasses { - if usageClass == types.UsageClassTypeCapacityBlock { - cbrSupported = true - break - } + if slices.Contains(inst.SupportedUsageClasses, types.UsageClassTypeCapacityBlock) { + cbrSupported = true } } diff --git a/integration/tests/crud/creategetdelete_test.go b/integration/tests/crud/creategetdelete_test.go index 1309befc3f..a3c6fa6d75 100644 --- a/integration/tests/crud/creategetdelete_test.go +++ b/integration/tests/crud/creategetdelete_test.go @@ -492,8 +492,8 @@ var _ = Describe("(Integration) Create, Get, Scale & Delete", func() { Expect(js).To(ContainElement(HavePrefix("AWS_SESSION_OBJECT="))) for _, envVar := range js { - if strings.HasPrefix(envVar, "AWS_SESSION_OBJECT=") { - err := json.Unmarshal([]byte(strings.TrimPrefix(envVar, "AWS_SESSION_OBJECT=")), &so) + if after, ok := strings.CutPrefix(envVar, "AWS_SESSION_OBJECT="); ok { + err := json.Unmarshal([]byte(after), &so) Expect(err).ShouldNot(HaveOccurred()) } } diff --git a/integration/tests/dry_run/dry_run_test.go b/integration/tests/dry_run/dry_run_test.go index 0c125ebb86..ae09a0c910 100644 --- a/integration/tests/dry_run/dry_run_test.go +++ b/integration/tests/dry_run/dry_run_test.go @@ -167,7 +167,7 @@ var _ = Describe("(Integration) [Dry-Run test]", func() { parseOutput := func(output []byte) (*api.ClusterConfig, *api.ClusterConfig) { actual, err := eks.ParseConfig(output) Expect(err).NotTo(HaveOccurred()) - defaultConfig, err := eks.ParseConfig([]byte(fmt.Sprintf(defaultClusterConfig, params.ClusterName))) + defaultConfig, err := eks.ParseConfig(fmt.Appendf(nil, defaultClusterConfig, params.ClusterName)) Expect(err).NotTo(HaveOccurred()) return actual, defaultConfig } diff --git a/pkg/actions/accessentry/creator_test.go b/pkg/actions/accessentry/creator_test.go index 86ff4cb792..e048331ba0 100644 --- a/pkg/actions/accessentry/creator_test.go +++ b/pkg/actions/accessentry/creator_test.go @@ -28,11 +28,10 @@ var _ = Describe("Access Entry", func() { s.CreateStackStub = func(ctx context.Context, stackName string, r builder.ResourceSetReader, tags map[string]string, parameters map[string]string, errorCh chan error) error { defer close(errorCh) prefix := fmt.Sprintf("eksctl-%s-accessentry-", ae.clusterName) - idx := strings.Index(stackName, prefix) - if idx < 0 { + _, suffix, ok := strings.Cut(stackName, prefix) + if !ok { return fmt.Errorf("expected stack name to have prefix %q", prefix) } - suffix := stackName[idx+len(prefix):] _, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(suffix) if err != nil { return fmt.Errorf("expected stack name to have a base32-encoded suffix: %w", err) diff --git a/pkg/actions/accessentry/migrator_test.go b/pkg/actions/accessentry/migrator_test.go index 0a8cb5c888..79da4a7fe6 100644 --- a/pkg/actions/accessentry/migrator_test.go +++ b/pkg/actions/accessentry/migrator_test.go @@ -59,11 +59,10 @@ var _ = Describe("Migrate Access Entry", func() { s.CreateStackStub = func(ctx context.Context, stackName string, r builder.ResourceSetReader, tags map[string]string, parameters map[string]string, errorCh chan error) error { defer close(errorCh) prefix := fmt.Sprintf("eksctl-%s-accessentry-", clusterName) - idx := strings.Index(stackName, prefix) - if idx < 0 { + _, suffix, ok := strings.Cut(stackName, prefix) + if !ok { return fmt.Errorf("expected stack name to have prefix %q", prefix) } - suffix := stackName[idx+len(prefix):] _, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(suffix) if err != nil { return fmt.Errorf("expected stack name to have a base32-encoded suffix: %w", err) diff --git a/pkg/actions/addon/create.go b/pkg/actions/addon/create.go index cda675569b..51ea5976af 100644 --- a/pkg/actions/addon/create.go +++ b/pkg/actions/addon/create.go @@ -319,7 +319,7 @@ func (a *Manager) patchAWSNodeSA(ctx context.Context) error { return nil } - _, err = serviceAccounts.Patch(ctx, "aws-node", types.JSONPatchType, []byte(fmt.Sprintf(`[{"op": "remove", "path": "/metadata/managedFields/%d"}]`, managerIndex)), metav1.PatchOptions{}) + _, err = serviceAccounts.Patch(ctx, "aws-node", types.JSONPatchType, fmt.Appendf(nil, `[{"op": "remove", "path": "/metadata/managedFields/%d"}]`, managerIndex), metav1.PatchOptions{}) if err != nil { return fmt.Errorf("failed to patch sa: %w", err) } @@ -387,7 +387,7 @@ func (a *Manager) patchAWSNodeDaemonSet(ctx context.Context) error { } } - _, err = daemonSets.Patch(ctx, "aws-node", types.JSONPatchType, []byte(fmt.Sprintf(`[{"op": "remove", "path": "/metadata/managedFields/%d"}]`, managerIndex)), metav1.PatchOptions{}) + _, err = daemonSets.Patch(ctx, "aws-node", types.JSONPatchType, fmt.Appendf(nil, `[{"op": "remove", "path": "/metadata/managedFields/%d"}]`, managerIndex), metav1.PatchOptions{}) if err != nil { return fmt.Errorf("failed to patch daemon set: %w", err) } diff --git a/pkg/actions/anywhere/anywhere.go b/pkg/actions/anywhere/anywhere.go index 0736ccc135..da533e5bbc 100644 --- a/pkg/actions/anywhere/anywhere.go +++ b/pkg/actions/anywhere/anywhere.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "os/exec" + "slices" "github.com/weaveworks/eksctl/pkg/version" ) @@ -26,10 +27,8 @@ func IsAnywhereCommand(args []string) (bool, error) { // if they have any args/flags before the anywhere command we should error // e.g. eksctl --foo=bar anywhere should error - for _, arg := range args { - if arg == "anywhere" { - return false, fmt.Errorf("flags cannot be placed before the anywhere command") - } + if slices.Contains(args, "anywhere") { + return false, fmt.Errorf("flags cannot be placed before the anywhere command") } return false, nil diff --git a/pkg/actions/capability/creator.go b/pkg/actions/capability/creator.go index b632aaa8d9..d20e360a87 100644 --- a/pkg/actions/capability/creator.go +++ b/pkg/actions/capability/creator.go @@ -6,6 +6,7 @@ import ( "encoding/base32" "errors" "fmt" + "maps" "strings" "time" @@ -128,9 +129,7 @@ func (c *Creator) createCapabilityStack(ctx context.Context, capability *api.Cap api.ClusterNameTag: c.clusterName, api.CapabilityNameTag: capability.Name, } - for k, v := range capability.Tags { - tags[k] = v - } + maps.Copy(tags, capability.Tags) if err := c.stackCreator.CreateStack(ctx, stackName, rs, tags, nil, stackErrCh); err != nil { return err } @@ -154,9 +153,7 @@ func (c *Creator) createIAMRoleStack(ctx context.Context, capability *api.Capabi api.CapabilityIAMRoleTag: capability.Name, } - for k, v := range capability.Tags { - tags[k] = v - } + maps.Copy(tags, capability.Tags) stackCh := make(chan error) if err := c.stackCreator.CreateStack(ctx, stackName, rs, tags, nil, stackCh); err != nil { diff --git a/pkg/actions/karpenter/create_test.go b/pkg/actions/karpenter/create_test.go index e3fe4c0a68..5ee6d3b7af 100644 --- a/pkg/actions/karpenter/create_test.go +++ b/pkg/actions/karpenter/create_test.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net" + "slices" awseks "github.com/aws/aws-sdk-go-v2/service/eks" ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" @@ -451,12 +452,7 @@ var _ = Describe("Create", func() { Cluster: fakeCluster, }, nil) p.MockEC2().On("CreateTags", mock.Anything, mock.MatchedBy(func(input *ec2.CreateTagsInput) bool { - for _, r := range input.Resources { - if r == "sg-cluster-1234" { - return true - } - } - return false + return slices.Contains(input.Resources, "sg-cluster-1234") })).Return(nil, errors.New("tag failed")) }) It("errors", func() { diff --git a/pkg/actions/nodegroup/delete_test.go b/pkg/actions/nodegroup/delete_test.go index fe6ed33e0d..ec149a7eda 100644 --- a/pkg/actions/nodegroup/delete_test.go +++ b/pkg/actions/nodegroup/delete_test.go @@ -77,7 +77,6 @@ var _ = Describe("Delete", func() { deleteNgTaskRuns atomic.Uint32 ) for _, stack := range dt.stacks { - stack := stack deleteNgTasks = append(deleteNgTasks, &taskfakes.FakeTask{ DescribeStub: func() string { return "delete " + stack.NodeGroupName diff --git a/pkg/actions/nodegroup/drain.go b/pkg/actions/nodegroup/drain.go index 93f1d9f63f..7e2b46005d 100644 --- a/pkg/actions/nodegroup/drain.go +++ b/pkg/actions/nodegroup/drain.go @@ -43,7 +43,6 @@ func (d *Drainer) Drain(ctx context.Context, input *DrainInput) error { g, ctx := errgroup.WithContext(ctx) for _, nodegroup := range input.NodeGroups { - nodegroup := nodegroup g.Go(func() error { nodeGroupDrainer := drain.NewNodeGroupDrainer(d.ClientSet, nodegroup, input.MaxGracePeriod, input.NodeDrainWaitPeriod, input.PodEvictionWaitPeriod, input.Undo, input.DisableEviction, input.Parallel) return nodeGroupDrainer.Drain(ctx, sem) diff --git a/pkg/actions/podidentityassociation/creator.go b/pkg/actions/podidentityassociation/creator.go index ef43fb3ce7..7baeef4158 100644 --- a/pkg/actions/podidentityassociation/creator.go +++ b/pkg/actions/podidentityassociation/creator.go @@ -46,7 +46,6 @@ func (c *Creator) CreateTasks(ctx context.Context, podIdentityAssociations []api Parallel: true, } for _, pia := range podIdentityAssociations { - pia := pia piaCreationTasks := &tasks.TaskTree{ Parallel: false, IsSubTask: true, diff --git a/pkg/actions/podidentityassociation/deleter.go b/pkg/actions/podidentityassociation/deleter.go index 11679010b9..71cefcca54 100644 --- a/pkg/actions/podidentityassociation/deleter.go +++ b/pkg/actions/podidentityassociation/deleter.go @@ -118,7 +118,6 @@ func (d *Deleter) DeleteTasks(ctx context.Context, podIDs []Identifier) (*tasks. } for _, podID := range podIDs { - podID := podID piaDeletionTasks := &tasks.TaskTree{ Parallel: false, IsSubTask: true, diff --git a/pkg/addons/default/addons.go b/pkg/addons/default/addons.go index ae2a99578a..1422fff636 100644 --- a/pkg/addons/default/addons.go +++ b/pkg/addons/default/addons.go @@ -3,6 +3,7 @@ package defaultaddons import ( "context" "fmt" + "slices" "github.com/aws/aws-sdk-go-v2/service/eks" @@ -66,10 +67,8 @@ func supportsMultiArch(podSec corev1.PodSpec) bool { for _, nodeSelectorTerm := range podSec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms { for _, me := range nodeSelectorTerm.MatchExpressions { if me.Key == corev1.LabelArchStable && me.Operator == corev1.NodeSelectorOpIn { - for _, val := range me.Values { - if val == "arm64" { - return true - } + if slices.Contains(me.Values, "arm64") { + return true } } } diff --git a/pkg/apis/eksctl.io/v1alpha5/nodegroups.go b/pkg/apis/eksctl.io/v1alpha5/nodegroups.go index 81d2074f38..72d85002d7 100644 --- a/pkg/apis/eksctl.io/v1alpha5/nodegroups.go +++ b/pkg/apis/eksctl.io/v1alpha5/nodegroups.go @@ -1,6 +1,9 @@ package v1alpha5 -import "fmt" +import ( + "fmt" + "slices" +) // HasInstanceType returns whether some node in the group fulfils the type check func HasInstanceType(nodeGroup *NodeGroup, hasType func(string) bool) bool { @@ -8,10 +11,8 @@ func HasInstanceType(nodeGroup *NodeGroup, hasType func(string) bool) bool { return true } if nodeGroup.InstancesDistribution != nil { - for _, instanceType := range nodeGroup.InstancesDistribution.InstanceTypes { - if hasType(instanceType) { - return true - } + if slices.ContainsFunc(nodeGroup.InstancesDistribution.InstanceTypes, hasType) { + return true } } return false @@ -22,12 +23,7 @@ func HasInstanceTypeManaged(nodeGroup *ManagedNodeGroup, hasType func(string) bo if hasType(nodeGroup.InstanceType) { return true } - for _, instanceType := range nodeGroup.InstanceTypes { - if hasType(instanceType) { - return true - } - } - return false + return slices.ContainsFunc(nodeGroup.InstanceTypes, hasType) } // ClusterHasInstanceType checks all nodegroups and managed nodegroups for a specific instance type diff --git a/pkg/apis/eksctl.io/v1alpha5/partitions.go b/pkg/apis/eksctl.io/v1alpha5/partitions.go index 88096b4da4..69b77f670f 100644 --- a/pkg/apis/eksctl.io/v1alpha5/partitions.go +++ b/pkg/apis/eksctl.io/v1alpha5/partitions.go @@ -1,6 +1,9 @@ package v1alpha5 -import "fmt" +import ( + "fmt" + "slices" +) // Partitions. const ( @@ -153,10 +156,8 @@ var Partitions = partitions{ func (p partitions) partitionFromRegion(region string) *partition { for _, pt := range p { - for _, r := range pt.regions { - if r == region { - return &pt - } + if slices.Contains(pt.regions, region) { + return &pt } } return nil diff --git a/pkg/apis/eksctl.io/v1alpha5/types.go b/pkg/apis/eksctl.io/v1alpha5/types.go index 95b46517c7..f014bb0dfd 100644 --- a/pkg/apis/eksctl.io/v1alpha5/types.go +++ b/pkg/apis/eksctl.io/v1alpha5/types.go @@ -7,6 +7,7 @@ import ( "encoding/json" "errors" "fmt" + "slices" "strings" "time" @@ -1214,10 +1215,8 @@ func NewClusterIAM() *ClusterIAM { // AppendAvailabilityZone appends a new AZ to the set func (c *ClusterConfig) AppendAvailabilityZone(newAZ string) { - for _, az := range c.AvailabilityZones { - if az == newAZ { - return - } + if slices.Contains(c.AvailabilityZones, newAZ) { + return } c.AvailabilityZones = append(c.AvailabilityZones, newAZ) } diff --git a/pkg/apis/eksctl.io/v1alpha5/validation.go b/pkg/apis/eksctl.io/v1alpha5/validation.go index b6cf69653f..1085132b2b 100644 --- a/pkg/apis/eksctl.io/v1alpha5/validation.go +++ b/pkg/apis/eksctl.io/v1alpha5/validation.go @@ -385,10 +385,8 @@ func validateCloudWatchLogging(clusterConfig *ClusterConfig) error { } } if logRetentionDays := clusterConfig.CloudWatch.ClusterLogging.LogRetentionInDays; logRetentionDays != 0 { - for _, v := range LogRetentionInDaysValues { - if v == logRetentionDays { - return nil - } + if slices.Contains(LogRetentionInDaysValues, logRetentionDays) { + return nil } return fmt.Errorf("invalid value %d for logRetentionInDays; supported values are %v", logRetentionDays, LogRetentionInDaysValues) } @@ -468,14 +466,7 @@ func (c *ClusterConfig) ValidateVPCConfig() error { return errors.New("vpc.hostnameType is not supported with a pre-existing VPC") } var hostnameType ec2types.HostnameType - found := false - for _, h := range hostnameType.Values() { - if h == ec2types.HostnameType(c.VPC.HostnameType) { - found = true - break - } - } - if !found { + if !slices.Contains(hostnameType.Values(), ec2types.HostnameType(c.VPC.HostnameType)) { return fmt.Errorf("invalid value %q for vpc.hostnameType; supported values are %v", c.VPC.HostnameType, hostnameType.Values()) } } @@ -1614,12 +1605,7 @@ func validateNodeGroupKubeletExtraConfig(kubeletConfig *InlineDocument) error { } func isSupportedAMIFamily(imageFamily string) bool { - for _, image := range SupportedAMIFamilies() { - if imageFamily == image { - return true - } - } - return false + return slices.Contains(SupportedAMIFamilies(), imageFamily) } func supportedAMIFamiliesForOS(isOSImage func(string) bool) []string { diff --git a/pkg/az/az.go b/pkg/az/az.go index 5ae6d7e320..6289a33c11 100644 --- a/pkg/az/az.go +++ b/pkg/az/az.go @@ -4,7 +4,8 @@ import ( "context" "fmt" "math/rand" - gostrings "strings" + "slices" + "strings" "time" "github.com/aws/aws-sdk-go-v2/aws" @@ -15,7 +16,6 @@ import ( api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/awsapi" "github.com/weaveworks/eksctl/pkg/utils/nodes" - "github.com/weaveworks/eksctl/pkg/utils/strings" ) var zoneIDsToAvoid = map[string][]string{ @@ -115,7 +115,7 @@ func FilterBasedOnAvailability(ctx context.Context, zones []string, np []api.Nod if len(noSupport) == 0 { filteredList = append(filteredList, zone) } else { - logger.Info("skipping %s from selection because it doesn't support the following instance type(s): %s", zone, gostrings.Join(noSupport, ",")) + logger.Info("skipping %s from selection because it doesn't support the following instance type(s): %s", zone, strings.Join(noSupport, ",")) } } return filteredList, nil @@ -162,7 +162,7 @@ func filterZones(region string, zones []ec2types.AvailabilityZone) []string { var filteredZones []string azsToAvoid := zoneIDsToAvoid[region] for _, z := range zones { - if !strings.Contains(azsToAvoid, *z.ZoneId) { + if !slices.Contains(azsToAvoid, *z.ZoneId) { filteredZones = append(filteredZones, *z.ZoneName) } } diff --git a/pkg/cfn/builder/auto_mode.go b/pkg/cfn/builder/auto_mode.go index 4c7af29db5..aeb43fde29 100644 --- a/pkg/cfn/builder/auto_mode.go +++ b/pkg/cfn/builder/auto_mode.go @@ -3,6 +3,7 @@ package builder import ( _ "embed" "errors" + "maps" api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" @@ -42,9 +43,7 @@ func AddAutoModeResources(clusterTemplate *gfn.Template, permissionsBoundary api } clusterTemplate.Resources[resourceName] = resource } - for key, output := range template.Outputs { - clusterTemplate.Outputs[key] = output - } + maps.Copy(clusterTemplate.Outputs, template.Outputs) return AutoModeRefs{ NodeRole: gfnt.MakeFnGetAttString("AutoModeNodeRole", "Arn"), }, nil diff --git a/pkg/cfn/builder/beta.go b/pkg/cfn/builder/beta.go index 1c05aef5ef..124b462699 100644 --- a/pkg/cfn/builder/beta.go +++ b/pkg/cfn/builder/beta.go @@ -4,6 +4,7 @@ import ( "context" _ "embed" "fmt" + "maps" "os" "strings" @@ -44,12 +45,8 @@ func addBetaResources(stsAPI awsapi.STS, stackName string, clusterTemplate *gfn. if err != nil { return err } - for resourceName, resource := range template.Resources { - clusterTemplate.Resources[resourceName] = resource - } - for key, output := range template.Outputs { - clusterTemplate.Outputs[key] = output - } + maps.Copy(clusterTemplate.Resources, template.Resources) + maps.Copy(clusterTemplate.Outputs, template.Outputs) customResource := clusterTemplate.Resources["ControlPlane"].(*gfn.CustomResource) if g.AccessConfig != nil { customResource.Properties["AccessConfig"] = g.AccessConfig diff --git a/pkg/cfn/builder/managed_launch_template_test.go b/pkg/cfn/builder/managed_launch_template_test.go index 9c56454c21..bed13acaa9 100644 --- a/pkg/cfn/builder/managed_launch_template_test.go +++ b/pkg/cfn/builder/managed_launch_template_test.go @@ -60,7 +60,7 @@ var _ = Describe("ManagedNodeGroup builder", func() { if !m.hasUserData { return "", nil } - userData := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`/etc/eks/bootstrap.sh %s`, clusterConfig.Metadata.Name))) + userData := base64.StdEncoding.EncodeToString(fmt.Appendf(nil, `/etc/eks/bootstrap.sh %s`, clusterConfig.Metadata.Name)) return userData, nil } diff --git a/pkg/cfn/builder/nodegroup_test.go b/pkg/cfn/builder/nodegroup_test.go index df8f244bb3..b702d37f41 100644 --- a/pkg/cfn/builder/nodegroup_test.go +++ b/pkg/cfn/builder/nodegroup_test.go @@ -1081,7 +1081,7 @@ var _ = Describe("Unmanaged NodeGroup Template Builder", func() { ng.PropagateASGTags = api.Enabled() ng.Labels = map[string]string{} ng.Taints = []api.NodeGroupTaint{} - for i := 0; i < builder.MaximumTagNumber+1; i++ { + for i := range builder.MaximumTagNumber + 1 { ng.Labels[fmt.Sprintf("%d", i)] = "test" } }) diff --git a/pkg/cfn/builder/vpc_endpoint_test.go b/pkg/cfn/builder/vpc_endpoint_test.go index 7a2d9ee2b2..91596140e2 100644 --- a/pkg/cfn/builder/vpc_endpoint_test.go +++ b/pkg/cfn/builder/vpc_endpoint_test.go @@ -543,7 +543,7 @@ func mockDescribeRouteTablesSame(provider *mockprovider.MockProvider, subnetIDs func makeZones(region string, count int) []string { var ret []string - for i := 0; i < count; i++ { + for i := range count { ret = append(ret, fmt.Sprintf("%s%c", region, 'a'+i)) } return ret diff --git a/pkg/cfn/manager/api.go b/pkg/cfn/manager/api.go index f00b132ff0..7ac176cc6c 100644 --- a/pkg/cfn/manager/api.go +++ b/pkg/cfn/manager/api.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "regexp" + "slices" "strconv" "strings" "time" @@ -276,10 +277,7 @@ func (c *StackCollection) PropagateManagedNodeGroupTagsToASG(ngName string, ngTa var chunkedASGTags [][]asTypes.Tag chunkSize := builder.MaximumCreatedTagNumberPerCall for start := 0; start < len(asgTags); start += chunkSize { - end := start + chunkSize - if end > len(asgTags) { - end = len(asgTags) - } + end := min(start+chunkSize, len(asgTags)) chunkedASGTags = append(chunkedASGTags, asgTags[start:end]) } // ...then create all of them in a loop @@ -532,12 +530,7 @@ func (c *StackCollection) ListStacksWithStatuses(ctx context.Context, statusFilt // StackStatusIsNotTransitional will return true when stack status is non-transitional func (*StackCollection) StackStatusIsNotTransitional(s *Stack) bool { - for _, state := range nonTransitionalReadyStackStatuses() { - if s.StackStatus == state { - return true - } - } - return false + return slices.Contains(nonTransitionalReadyStackStatuses(), s.StackStatus) } func nonTransitionalReadyStackStatuses() []types.StackStatus { diff --git a/pkg/cfn/manager/api_test.go b/pkg/cfn/manager/api_test.go index d6e3b6d574..91fc1984f7 100644 --- a/pkg/cfn/manager/api_test.go +++ b/pkg/cfn/manager/api_test.go @@ -70,7 +70,7 @@ var _ = Describe("StackCollection", func() { It("cannot propagate tags in chunks of 25", func() { // populate the createOrUpdateTagsSliceInput for easier generation of chunks createOrUpdateTagsSliceInput := []asTypes.Tag{} - for i := 0; i < 30; i++ { + for i := range 30 { tagKey, tagValue := fmt.Sprintf("tag_key_%d", i), fmt.Sprintf("tag_value_%d", i) ngTags[tagKey] = tagValue createOrUpdateTagsSliceInput = append(createOrUpdateTagsSliceInput, asTypes.Tag{ @@ -111,7 +111,7 @@ var _ = Describe("StackCollection", func() { }) It("cannot propagate if too many tags", func() { // fill parameters - for i := 0; i < builder.MaximumTagNumber+1; i++ { + for i := range builder.MaximumTagNumber + 1 { ngTags[fmt.Sprintf("tag_key_%d", i)] = fmt.Sprintf("tag_value_%d", i) } diff --git a/pkg/cfn/manager/nodegroup.go b/pkg/cfn/manager/nodegroup.go index ddb88f6c8e..1437ee07b2 100644 --- a/pkg/cfn/manager/nodegroup.go +++ b/pkg/cfn/manager/nodegroup.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "maps" "strings" ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" @@ -85,7 +86,6 @@ func (t *UnmanagedNodeGroupTask) Create(ctx context.Context, options CreateNodeG taskTree := &tasks.TaskTree{Parallel: true, Limit: options.Parallelism} for _, ng := range t.NodeGroups { - ng := ng createAccessEntryInStack := ng.IAM.InstanceRoleARN == "" createNodeGroupTask := &tasks.GenericTask{ Description: fmt.Sprintf("create nodegroup %q", ng.NameString()), @@ -228,9 +228,7 @@ func (c *StackCollection) propagateManagedNodeGroupTagsToASGTask(ctx context.Con }) // add nodegroup tags - for k, v := range ng.Tags { - tags[k] = v - } + maps.Copy(tags, ng.Tags) return propagateFunc(ng.Name, tags, asgNames, errorCh) } diff --git a/pkg/cloudconfig/cloudconfig.go b/pkg/cloudconfig/cloudconfig.go index 857bdb35ef..f8d3c98b65 100644 --- a/pkg/cloudconfig/cloudconfig.go +++ b/pkg/cloudconfig/cloudconfig.go @@ -103,7 +103,7 @@ func (c *CloudConfig) Encode() (string, error) { return "", err } - data = append([]byte(fmt.Sprintln(header)), data...) + data = append(fmt.Appendln(nil, header), data...) return encodeUserData(data) } diff --git a/pkg/ctl/cmdutils/configfile.go b/pkg/ctl/cmdutils/configfile.go index 0710d96bc6..6fa168f457 100644 --- a/pkg/ctl/cmdutils/configfile.go +++ b/pkg/ctl/cmdutils/configfile.go @@ -20,7 +20,6 @@ import ( "github.com/weaveworks/eksctl/pkg/ctl/cmdutils/filter" "github.com/weaveworks/eksctl/pkg/eks" "github.com/weaveworks/eksctl/pkg/utils/names" - utilstrings "github.com/weaveworks/eksctl/pkg/utils/strings" ) // AddConfigFileFlag adds common --config-file flag @@ -467,7 +466,7 @@ func validateZonesAndNodeZones(cmd *cobra.Command) error { nodeZones := strings.Split(strings.Trim(nodeZonesFlag.Value.String(), "[]"), ",") zones := strings.Split(strings.Trim(zonesFlag.Value.String(), "[]"), ",") for _, zone := range nodeZones { - if !utilstrings.Contains(zones, zone) { + if !slices.Contains(zones, zone) { return fmt.Errorf("node-zones %s must be a subset of zones %s; %q was not found in zones", nodeZones, zones, zone) } } @@ -1168,7 +1167,7 @@ func validateSupportedConfigFields(obj interface{}, supportedFields []string, un t := v.Type() for fieldNumber := 0; fieldNumber < v.NumField(); fieldNumber++ { if !emptyConfigField(v.Field(fieldNumber)) { - if !contains(supportedFields, t.Field(fieldNumber).Name) { + if !slices.Contains(supportedFields, t.Field(fieldNumber).Name) { unsupportedFields = append(unsupportedFields, t.Field(fieldNumber).Name) } } @@ -1193,12 +1192,3 @@ func emptyConfigField(v reflect.Value) bool { } return false } - -func contains(supportedFields []string, fieldName string) bool { - for _, f := range supportedFields { - if f == fieldName { - return true - } - } - return false -} diff --git a/pkg/ctl/cmdutils/filter/nodegroup_filter.go b/pkg/ctl/cmdutils/filter/nodegroup_filter.go index 94e4ef39fc..983d07480d 100644 --- a/pkg/ctl/cmdutils/filter/nodegroup_filter.go +++ b/pkg/ctl/cmdutils/filter/nodegroup_filter.go @@ -2,6 +2,7 @@ package filter import ( "context" + "slices" "strings" "github.com/aws/aws-sdk-go-v2/service/eks" @@ -198,12 +199,7 @@ func (f *NodeGroupFilter) findAllNodeGroups(ctx context.Context, eksAPI awsapi.E } func nodeExists(stacks []string, stackName string) bool { - for _, s := range stacks { - if s == stackName { - return true - } - } - return false + return slices.Contains(stacks, stackName) } func stackExists(stacks []manager.NodeGroupStack, stackName string) bool { diff --git a/pkg/ctl/mcp/stdio_test.go b/pkg/ctl/mcp/stdio_test.go index 6224606129..6c6a7889b1 100644 --- a/pkg/ctl/mcp/stdio_test.go +++ b/pkg/ctl/mcp/stdio_test.go @@ -254,8 +254,7 @@ func TestStdioServerMultipleRequests(t *testing.T) { // Parse and verify each response - we don't need to check specific values // Just verify we can parse the response - responseLines := strings.Split(strings.TrimSpace(response), "\n") - for _, line := range responseLines { + for line := range strings.Lines(strings.TrimSpace(response)) { if line == "" { continue } diff --git a/pkg/ctl/mcp/tools.go b/pkg/ctl/mcp/tools.go index 2700594e5f..a29df35113 100644 --- a/pkg/ctl/mcp/tools.go +++ b/pkg/ctl/mcp/tools.go @@ -210,8 +210,7 @@ func createToolHandler(cmd *cobra.Command) server.ToolHandlerFunc { case "stringSlice", "stringArray", "intSlice", "intArray": // Handle arrays as comma-separated values if value := request.GetString(name, ""); value != "" { - values := strings.Split(value, ",") - for _, v := range values { + for v := range strings.SplitSeq(value, ",") { args = append(args, "--"+name, strings.TrimSpace(v)) } } diff --git a/pkg/drain/evictor/evictor.go b/pkg/drain/evictor/evictor.go index 112069f531..f82379bbb2 100644 --- a/pkg/drain/evictor/evictor.go +++ b/pkg/drain/evictor/evictor.go @@ -112,11 +112,7 @@ func (d *Evictor) makeDeleteOptions(pod corev1.Pod) metav1.DeleteOptions { gracePeriodSeconds := int64(corev1.DefaultTerminationGracePeriodSeconds) if pod.Spec.TerminationGracePeriodSeconds != nil { - if *pod.Spec.TerminationGracePeriodSeconds < int64(d.maxGracePeriodSeconds) { - gracePeriodSeconds = *pod.Spec.TerminationGracePeriodSeconds - } else { - gracePeriodSeconds = int64(d.maxGracePeriodSeconds) - } + gracePeriodSeconds = min(*pod.Spec.TerminationGracePeriodSeconds, int64(d.maxGracePeriodSeconds)) } deleteOptions.GracePeriodSeconds = &gracePeriodSeconds diff --git a/pkg/drain/nodegroup.go b/pkg/drain/nodegroup.go index 5024dfcfc4..d82d2c641e 100644 --- a/pkg/drain/nodegroup.go +++ b/pkg/drain/nodegroup.go @@ -141,7 +141,6 @@ func (n *NodeGroupDrainer) Drain(ctx context.Context, sem *semaphore.Weighted) e g, ctx := errgroup.WithContext(ctx) for _, node := range sets.List(newPendingNodes) { - node := node g.Go(func() error { if err := sem.Acquire(ctx, 1); err != nil { return fmt.Errorf("failed to acquire semaphore: %w", err) diff --git a/pkg/drain/nodegroup_test.go b/pkg/drain/nodegroup_test.go index f70fc41e63..89ed11f2e4 100644 --- a/pkg/drain/nodegroup_test.go +++ b/pkg/drain/nodegroup_test.go @@ -245,7 +245,7 @@ var _ = Describe("Drain", func() { }, } - for i := 0; i < 2; i++ { + for i := range 2 { fakeEvictor.GetPodsForEvictionReturnsOnCall(i, &evictor.PodDeleteList{ Items: []evictor.PodDelete{ { diff --git a/pkg/eks/api.go b/pkg/eks/api.go index e8427d19f9..721a81e7f2 100644 --- a/pkg/eks/api.go +++ b/pkg/eks/api.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "os" + "slices" "strings" "time" @@ -265,12 +266,7 @@ func readConfig(configFile string, reader io.Reader) ([]byte, error) { // IsSupportedRegion check if given region is supported func (c *ClusterProvider) IsSupportedRegion() bool { - for _, supportedRegion := range api.SupportedRegions() { - if c.AWSProvider.Region() == supportedRegion { - return true - } - } - return false + return slices.Contains(api.SupportedRegions(), c.AWSProvider.Region()) } // GetCredentialsEnv returns the AWS credentials for env usage diff --git a/pkg/eks/fargate.go b/pkg/eks/fargate.go index 585fadf457..001f60b2f6 100644 --- a/pkg/eks/fargate.go +++ b/pkg/eks/fargate.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "slices" "time" ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" @@ -63,11 +64,9 @@ func (t *fargateProfilesTask) Do(errCh chan error) error { // Check if the target Fargate Profile already exists func targetFargateProfileExists(target string, profiles []string, clusterName string) bool { - for _, profileName := range profiles { - if target == profileName { - logger.Info("Fargate profile %q already exists on EKS cluster %q", target, clusterName) - return true - } + if slices.Contains(profiles, target) { + logger.Info("Fargate profile %q already exists on EKS cluster %q", target, clusterName) + return true } return false } diff --git a/pkg/eks/tasks_test.go b/pkg/eks/tasks_test.go index e34e2fcf40..7727d83102 100644 --- a/pkg/eks/tasks_test.go +++ b/pkg/eks/tasks_test.go @@ -161,7 +161,6 @@ var _ = Describe("ClusterTasksForNodeGroups", func() { } for _, tc := range testCases { - tc := tc // capture range variable It("returns the expected tasks", func() { provider := mockprovider.NewMockProvider() cfg := &v1alpha5.ClusterConfig{ diff --git a/pkg/eks/versions_manager.go b/pkg/eks/versions_manager.go index 5690836933..b46555ff95 100644 --- a/pkg/eks/versions_manager.go +++ b/pkg/eks/versions_manager.go @@ -78,12 +78,7 @@ func (cvm *ClusterVersionsManager) SupportedVersions() []string { } func (cvm *ClusterVersionsManager) IsSupportedVersion(version string) bool { - for _, v := range cvm.SupportedVersions() { - if version == v { - return true - } - } - return false + return slices.Contains(cvm.SupportedVersions(), version) } func (cvm *ClusterVersionsManager) DeprecatedVersions() []string { @@ -91,12 +86,7 @@ func (cvm *ClusterVersionsManager) DeprecatedVersions() []string { } func (cvm *ClusterVersionsManager) IsDeprecatedVersion(version string) bool { - for _, v := range cvm.DeprecatedVersions() { - if version == v { - return true - } - } - return false + return slices.Contains(cvm.DeprecatedVersions(), version) } func (cvm *ClusterVersionsManager) DefaultVersion() string { diff --git a/pkg/fargate/coredns/coredns.go b/pkg/fargate/coredns/coredns.go index 55837d9063..b5d54baeb9 100644 --- a/pkg/fargate/coredns/coredns.go +++ b/pkg/fargate/coredns/coredns.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "slices" "strings" "time" @@ -33,10 +34,8 @@ const ( // EKS' coredns deployment should be scheduled onto Fargate. func IsSchedulableOnFargate(profiles []*api.FargateProfile) bool { for _, profile := range profiles { - for _, selector := range profile.Selectors { - if selectsCoreDNS(selector) { - return true - } + if slices.ContainsFunc(profile.Selectors, selectsCoreDNS) { + return true } } return false diff --git a/pkg/fargate/delete.go b/pkg/fargate/delete.go index 430dd1e02a..874294d22e 100644 --- a/pkg/fargate/delete.go +++ b/pkg/fargate/delete.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "slices" "time" "github.com/aws/aws-sdk-go-v2/service/eks" @@ -61,7 +62,7 @@ func (c *Client) waitForDeletion(ctx context.Context, name string) error { if err != nil { return err } - if !contains(names, name) { + if !slices.Contains(names, name) { return nil } @@ -84,12 +85,3 @@ func deleteRequest(clusterName string, profileName string) *eks.DeleteFargatePro logger.Debug("Fargate profile: delete request: sending: %#v", request) return request } - -func contains(array []string, target string) bool { - for _, value := range array { - if value == target { - return true - } - } - return false -} diff --git a/pkg/fargate/fargate_test.go b/pkg/fargate/fargate_test.go index 2a61601369..32a3247a8d 100644 --- a/pkg/fargate/fargate_test.go +++ b/pkg/fargate/fargate_test.go @@ -262,7 +262,7 @@ func mockForCreateFargateProfileWithWait(numRetries int) *mocksv2.EKS { mockClient := mocksv2.EKS{} mockCreateFargateProfile(&mockClient) // Simulate a couple calls to AWS' API before the profile actually gets created: - for i := 0; i < numRetries; i++ { + for range numRetries { mockDescribeFargateProfile(&mockClient, "default", "CREATING") } mockDescribeFargateProfile(&mockClient, "default", "ACTIVE") // At this point, the profile has been created. @@ -522,7 +522,7 @@ func mockForDeleteFargateProfileWithWait(name string, numRetries int) *mocksv2.E mockClient := mocksv2.EKS{} mockDeleteFargateProfile(&mockClient, name) // Simulate a couple calls to AWS' API before the profile actually gets deleted: - for i := 0; i < numRetries; i++ { + for range numRetries { mockListFargateProfiles(&mockClient, name, "default") } mockListFargateProfiles(&mockClient, "default") // At this point, the profile has been deleted. diff --git a/pkg/kubernetes/namespace.go b/pkg/kubernetes/namespace.go index d63973b35e..02ef9d5361 100644 --- a/pkg/kubernetes/namespace.go +++ b/pkg/kubernetes/namespace.go @@ -37,7 +37,7 @@ func NewNamespaceYAML(name string) []byte { }, "\n") - return []byte(fmt.Sprintf(nsFmt, name)) + return fmt.Appendf(nil, nsFmt, name) } // CheckNamespaceExists check if a namespace with a given name already exists, and diff --git a/pkg/managed/service.go b/pkg/managed/service.go index e587b2f551..cdedde7b38 100644 --- a/pkg/managed/service.go +++ b/pkg/managed/service.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "maps" "github.com/aws/aws-sdk-go-v2/service/eks" ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" @@ -91,9 +92,7 @@ func (m *Service) UpdateLabels(ctx context.Context, nodeGroupName string, labels return err } - for k, v := range labelsToAdd { - newLabels[k] = v - } + maps.Copy(newLabels, labelsToAdd) for _, k := range labelsToRemove { delete(newLabels, k) diff --git a/pkg/outposts/outposts.go b/pkg/outposts/outposts.go index aab423a766..b6d733a90d 100644 --- a/pkg/outposts/outposts.go +++ b/pkg/outposts/outposts.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "slices" "strings" "sync" @@ -132,10 +133,8 @@ func (o *Service) ValidateInstanceType(ctx context.Context, instanceType string) if err != nil { return fmt.Errorf("error retrieving instance types for Outpost: %w", err) } - for _, it := range instanceTypes { - if it == ec2types.InstanceType(instanceType) { - return nil - } + if slices.Contains(instanceTypes, ec2types.InstanceType(instanceType)) { + return nil } return fmt.Errorf("instance type %q does not exist in Outpost %q", instanceType, o.OutpostID) } diff --git a/pkg/outposts/outposts_test.go b/pkg/outposts/outposts_test.go index 090bfc6231..2482af3638 100644 --- a/pkg/outposts/outposts_test.go +++ b/pkg/outposts/outposts_test.go @@ -71,7 +71,7 @@ var _ = Describe("Outposts Service", func() { By("fetching the smallest available instance type") count := 5 doneCh = runAssertion(count, func(wg *sync.WaitGroup) { - for i := 0; i < count; i++ { + for range count { go func() { defer GinkgoRecover() defer wg.Done() diff --git a/pkg/utils/kubeconfig/kubeconfig.go b/pkg/utils/kubeconfig/kubeconfig.go index d52005033f..d29f3ca844 100644 --- a/pkg/utils/kubeconfig/kubeconfig.go +++ b/pkg/utils/kubeconfig/kubeconfig.go @@ -3,6 +3,7 @@ package kubeconfig import ( "encoding/json" "fmt" + "maps" "os" "os/exec" "path" @@ -395,15 +396,9 @@ func getConfigAccess(explicitPath string) clientcmd.ConfigAccess { return interface{}(pathOptions).(clientcmd.ConfigAccess) } func merge(existing *clientcmdapi.Config, tomerge *clientcmdapi.Config) *clientcmdapi.Config { - for k, v := range tomerge.Clusters { - existing.Clusters[k] = v - } - for k, v := range tomerge.AuthInfos { - existing.AuthInfos[k] = v - } - for k, v := range tomerge.Contexts { - existing.Contexts[k] = v - } + maps.Copy(existing.Clusters, tomerge.Clusters) + maps.Copy(existing.AuthInfos, tomerge.AuthInfos) + maps.Copy(existing.Contexts, tomerge.Contexts) return existing } diff --git a/pkg/utils/kubeconfig/kubeconfig_test.go b/pkg/utils/kubeconfig/kubeconfig_test.go index 2f29c20fe0..52f24623d3 100644 --- a/pkg/utils/kubeconfig/kubeconfig_test.go +++ b/pkg/utils/kubeconfig/kubeconfig_test.go @@ -342,8 +342,8 @@ var _ = Describe("Kubeconfig", func() { var wg sync.WaitGroup multiplier := 3 iters := 10 - for i := 0; i < multiplier; i++ { - for k := 0; k < iters; k++ { + for range multiplier { + for range iters { wg.Add(1) go func() { defer wg.Done() diff --git a/pkg/utils/names/names.go b/pkg/utils/names/names.go index c57a807879..7f2ad72099 100644 --- a/pkg/utils/names/names.go +++ b/pkg/utils/names/names.go @@ -67,7 +67,7 @@ func useNameOrGenerate(a, b string, generate func() string) string { // characters in the provided set. func RandomName(length int, chars string) string { randomName := make([]byte, length) - for i := 0; i < length; i++ { + for i := range length { randomName[i] = chars[r.Intn(len(chars))] } return string(randomName) diff --git a/pkg/utils/strings/strings.go b/pkg/utils/strings/strings.go index 85682a5d76..2b69a6edac 100644 --- a/pkg/utils/strings/strings.go +++ b/pkg/utils/strings/strings.go @@ -1,6 +1,9 @@ package strings -import "strings" +import ( + "slices" + "strings" +) // Pointer returns a pointer to the provided string. func Pointer(s string) *string { @@ -97,11 +100,8 @@ func ToValuesArray(in []*string) []string { } // Contains returns true if the value is contained in the string list. +// +// Deprecated: use [slices.Contains] instead. func Contains(list []string, value string) bool { - for _, v := range list { - if v == value { - return true - } - } - return false + return slices.Contains(list, value) } diff --git a/pkg/utils/tasks/tasks.go b/pkg/utils/tasks/tasks.go index a7fc346eb1..dc21f81ed9 100644 --- a/pkg/utils/tasks/tasks.go +++ b/pkg/utils/tasks/tasks.go @@ -231,7 +231,6 @@ func runInErrorGroup(tasks []Task, limit int, errs chan error) { var eg errgroup.Group eg.SetLimit(limit) for _, t := range tasks { - t := t eg.Go(func() error { if ok := doSingleTask(errs, t); !ok { logger.Debug("failed task: %s (will continue until other parallel tasks are completed)", t.Describe()) diff --git a/pkg/vpc/vpc.go b/pkg/vpc/vpc.go index 9e00226601..d74398a2c3 100644 --- a/pkg/vpc/vpc.go +++ b/pkg/vpc/vpc.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "errors" "fmt" + "maps" "net" "slices" "strings" @@ -171,7 +172,7 @@ func SplitInto(parent *net.IPNet, size, networkLength int) ([]*net.IPNet, error) return nil, errors.New("CIDR block size must be between a /16 netmask and /28 netmask") } var subnets []*net.IPNet - for i := 0; i < size; i++ { + for i := range size { ip4 := parent.IP.To4() if ip4 == nil { return nil, fmt.Errorf("unexpected IP address type: %s", parent) @@ -492,9 +493,7 @@ func ImportSubnets(ctx context.Context, ec2API awsapi.EC2, spec *api.ClusterConf // as subnetMapping will be populated / altered within ImportSubnet, // we want to keep an unchanged copy for local against remote VPC config validation localSubnetConfig := api.AZSubnetMapping{} - for k, v := range subnetMapping { - localSubnetConfig[k] = v - } + maps.Copy(localSubnetConfig, subnetMapping) for _, sn := range subnets { if spec.VPC.ID == "" {