From 083ff19ccdc9bf54eba494ef6fe42ad49be9da35 Mon Sep 17 00:00:00 2001 From: Steffen Windoffer Date: Tue, 13 Oct 2026 14:49:30 +0200 Subject: [PATCH] Make update-authentication-mode idempotent and fix its log line Skip the UpdateClusterConfig call when the cluster's authentication mode already matches the desired mode: the EKS API rejects no-op updates with InvalidParameterException ("Unsupported authentication mode update from X to X"), which broke idempotent re-runs from CI/GitOps pipelines. The cluster description is already cached on the cluster provider, so no extra API call is needed. Also log the authentication mode resolved from the cluster config instead of the --authentication-mode flag, which is empty when the mode comes from a config file via -f. Signed-off-by: Steffen Windoffer --- pkg/ctl/utils/export_test.go | 2 + pkg/ctl/utils/update_authentication_mode.go | 18 ++++- .../utils/update_authentication_mode_test.go | 77 +++++++++++++++++++ 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/pkg/ctl/utils/export_test.go b/pkg/ctl/utils/export_test.go index 4514fb513b..29a27c8f2a 100644 --- a/pkg/ctl/utils/export_test.go +++ b/pkg/ctl/utils/export_test.go @@ -3,3 +3,5 @@ package utils func ValidateLoggingFlags(toEnable, toDisable []string) error { return validateLoggingFlags(toEnable, toDisable) } + +var UpdateAuthenticationModeForCluster = updateAuthenticationModeForCluster diff --git a/pkg/ctl/utils/update_authentication_mode.go b/pkg/ctl/utils/update_authentication_mode.go index c4d1bfc2b0..8b17d0926d 100644 --- a/pkg/ctl/utils/update_authentication_mode.go +++ b/pkg/ctl/utils/update_authentication_mode.go @@ -13,6 +13,7 @@ import ( api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" "github.com/weaveworks/eksctl/pkg/ctl/cmdutils" + "github.com/weaveworks/eksctl/pkg/eks" "github.com/weaveworks/eksctl/pkg/eks/waiter" ) @@ -51,12 +52,23 @@ func doUpdateAuthenticationMode(cmd *cmdutils.Cmd, authenticationMode string) er return err } + return updateAuthenticationModeForCluster(ctx, clusterProvider, cmd.ClusterConfig) +} + +func updateAuthenticationModeForCluster(ctx context.Context, clusterProvider *eks.ClusterProvider, clusterConfig *api.ClusterConfig) error { + authenticationMode := clusterConfig.AccessConfig.AuthenticationMode + clusterName := clusterConfig.Metadata.Name + + if cluster := clusterProvider.GetClusterState(); cluster.AccessConfig != nil && cluster.AccessConfig.AuthenticationMode == authenticationMode { + logger.Info("authentication mode is already %s on cluster %s, skipping update", authenticationMode, clusterName) + return nil + } + logger.Info("setting cluster's authentication mode to %s", authenticationMode) - clusterName := cmd.ClusterConfig.Metadata.Name output, err := clusterProvider.AWSProvider.EKS().UpdateClusterConfig(ctx, &awseks.UpdateClusterConfigInput{ Name: &clusterName, AccessConfig: &ekstypes.UpdateAccessConfigRequest{ - AuthenticationMode: cmd.ClusterConfig.AccessConfig.AuthenticationMode, + AuthenticationMode: authenticationMode, }, }) if err != nil { @@ -79,7 +91,7 @@ func doUpdateAuthenticationMode(cmd *cmdutils.Cmd, authenticationMode string) er return fmt.Errorf("failed to update cluster authentication mode: %s", e.UpdateError) case nil: - logger.Info("authentication mode was successfully updated to %s on cluster %s", cmd.ClusterConfig.AccessConfig.AuthenticationMode, clusterName) + logger.Info("authentication mode was successfully updated to %s on cluster %s", authenticationMode, clusterName) return nil default: diff --git a/pkg/ctl/utils/update_authentication_mode_test.go b/pkg/ctl/utils/update_authentication_mode_test.go index f9de0d1564..87150bb325 100644 --- a/pkg/ctl/utils/update_authentication_mode_test.go +++ b/pkg/ctl/utils/update_authentication_mode_test.go @@ -1,8 +1,19 @@ package utils_test import ( + "context" + + "github.com/aws/aws-sdk-go-v2/aws" + awseks "github.com/aws/aws-sdk-go-v2/service/eks" + ekstypes "github.com/aws/aws-sdk-go-v2/service/eks/types" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/stretchr/testify/mock" + + api "github.com/weaveworks/eksctl/pkg/apis/eksctl.io/v1alpha5" + "github.com/weaveworks/eksctl/pkg/ctl/utils" + "github.com/weaveworks/eksctl/pkg/eks" + "github.com/weaveworks/eksctl/pkg/testutils/mockprovider" ) var _ = Describe("update authentication mode", func() { @@ -37,4 +48,70 @@ var _ = Describe("update authentication mode", func() { args: []string{"--authentication-mode", "CONFIG_MAP", "--config-file", "../../../examples/01-simple-cluster.yaml"}, }), ) + + Describe("updating the cluster", func() { + const clusterName = "test" + + makeClusterProvider := func(currentMode ekstypes.AuthenticationMode) (*mockprovider.MockProvider, *eks.ClusterProvider) { + provider := mockprovider.NewMockProvider() + return provider, &eks.ClusterProvider{ + AWSProvider: provider, + Status: &eks.ProviderStatus{ + ClusterInfo: &eks.ClusterInfo{ + Cluster: &ekstypes.Cluster{ + Name: aws.String(clusterName), + AccessConfig: &ekstypes.AccessConfigResponse{ + AuthenticationMode: currentMode, + }, + }, + }, + }, + } + } + + makeClusterConfig := func(desiredMode ekstypes.AuthenticationMode) *api.ClusterConfig { + clusterConfig := api.NewClusterConfig() + clusterConfig.Metadata.Name = clusterName + clusterConfig.AccessConfig.AuthenticationMode = desiredMode + return clusterConfig + } + + When("the cluster already has the desired authentication mode", func() { + It("skips the update", func() { + provider, clusterProvider := makeClusterProvider(ekstypes.AuthenticationModeApiAndConfigMap) + + err := utils.UpdateAuthenticationModeForCluster(context.Background(), clusterProvider, makeClusterConfig(ekstypes.AuthenticationModeApiAndConfigMap)) + Expect(err).NotTo(HaveOccurred()) + provider.MockEKS().AssertNotCalled(GinkgoT(), "UpdateClusterConfig", mock.Anything, mock.Anything) + }) + }) + + When("the cluster has a different authentication mode", func() { + It("updates the cluster with the desired mode", func() { + provider, clusterProvider := makeClusterProvider(ekstypes.AuthenticationModeConfigMap) + + updateID := aws.String("update-1") + provider.MockEKS().On("UpdateClusterConfig", mock.Anything, mock.MatchedBy(func(input *awseks.UpdateClusterConfigInput) bool { + return *input.Name == clusterName && input.AccessConfig.AuthenticationMode == ekstypes.AuthenticationModeApiAndConfigMap + })).Return(&awseks.UpdateClusterConfigOutput{ + Update: &ekstypes.Update{ + Id: updateID, + }, + }, nil).Once() + provider.MockEKS().On("DescribeUpdate", mock.Anything, mock.MatchedBy(func(input *awseks.DescribeUpdateInput) bool { + return *input.UpdateId == *updateID + }), mock.Anything).Return(&awseks.DescribeUpdateOutput{ + Update: &ekstypes.Update{ + Id: updateID, + Type: ekstypes.UpdateTypeAccessConfigUpdate, + Status: ekstypes.UpdateStatusSuccessful, + }, + }, nil).Once() + + err := utils.UpdateAuthenticationModeForCluster(context.Background(), clusterProvider, makeClusterConfig(ekstypes.AuthenticationModeApiAndConfigMap)) + Expect(err).NotTo(HaveOccurred()) + provider.MockEKS().AssertExpectations(GinkgoT()) + }) + }) + }) })