From 167de782d4f37ec37e29ecb9636ea3977dacaa93 Mon Sep 17 00:00:00 2001 From: Tanvir Tatla Date: Thu, 28 Mar 2024 12:06:50 -0700 Subject: [PATCH] Use Cluster Mover in create and delete workflows --- Makefile | 2 +- cmd/eksctl-anywhere/cmd/createcluster.go | 4 +- cmd/eksctl-anywhere/cmd/deletecluster.go | 3 +- pkg/clustermanager/cluster_manager.go | 14 ++++ pkg/task/task.go | 1 + pkg/workflows/create_prep.go | 17 +---- pkg/workflows/create_prep_test.go | 45 +----------- pkg/workflows/interfaces/interfaces.go | 5 ++ pkg/workflows/interfaces/mocks/clients.go | 39 +++++++++- pkg/workflows/management/create.go | 4 + .../management/create_install_eksa.go | 23 +++++- pkg/workflows/management/create_test.go | 32 ++++---- pkg/workflows/management/create_workload.go | 8 +- pkg/workflows/management/delete.go | 4 + .../management/delete_install_eksa.go | 57 ++++++--------- pkg/workflows/management/delete_test.go | 73 +++++++++++-------- pkg/workflows/workload/createcluster.go | 8 +- 17 files changed, 191 insertions(+), 148 deletions(-) diff --git a/Makefile b/Makefile index 747f5ba5d233..a02bec980b18 100644 --- a/Makefile +++ b/Makefile @@ -568,7 +568,7 @@ mocks: ## Generate mocks ${MOCKGEN} -destination=pkg/bootstrapper/mocks/bootstrapper.go -package=mocks "github.com/aws/eks-anywhere/pkg/bootstrapper" ClusterClient ${MOCKGEN} -destination=pkg/git/providers/github/mocks/github.go -package=mocks "github.com/aws/eks-anywhere/pkg/git/providers/github" GithubClient ${MOCKGEN} -destination=pkg/git/mocks/git.go -package=mocks "github.com/aws/eks-anywhere/pkg/git" Client,ProviderClient - ${MOCKGEN} -destination=pkg/workflows/interfaces/mocks/clients.go -package=mocks "github.com/aws/eks-anywhere/pkg/workflows/interfaces" Bootstrapper,ClusterManager,GitOpsManager,Validator,CAPIManager,EksdInstaller,EksdUpgrader,PackageInstaller,ClusterUpgrader,ClusterCreator,ClientFactory,EksaInstaller,ClusterDeleter + ${MOCKGEN} -destination=pkg/workflows/interfaces/mocks/clients.go -package=mocks "github.com/aws/eks-anywhere/pkg/workflows/interfaces" Bootstrapper,ClusterManager,GitOpsManager,Validator,CAPIManager,EksdInstaller,EksdUpgrader,PackageInstaller,ClusterUpgrader,ClusterCreator,ClientFactory,EksaInstaller,ClusterDeleter,ClusterMover ${MOCKGEN} -destination=pkg/git/gogithub/mocks/client.go -package=mocks "github.com/aws/eks-anywhere/pkg/git/gogithub" Client ${MOCKGEN} -destination=pkg/git/gitclient/mocks/client.go -package=mocks "github.com/aws/eks-anywhere/pkg/git/gitclient" GoGit ${MOCKGEN} -destination=pkg/validations/mocks/docker.go -package=mocks "github.com/aws/eks-anywhere/pkg/validations" DockerExecutable diff --git a/cmd/eksctl-anywhere/cmd/createcluster.go b/cmd/eksctl-anywhere/cmd/createcluster.go index 57d3e4e76b57..6452dafc6892 100644 --- a/cmd/eksctl-anywhere/cmd/createcluster.go +++ b/cmd/eksctl-anywhere/cmd/createcluster.go @@ -190,7 +190,8 @@ func (cc *createClusterOptions) createCluster(cmd *cobra.Command, _ []string) er WithCreateClusterDefaulter(createCLIConfig). WithClusterApplier(). WithKubeconfigWriter(clusterSpec.Cluster). - WithClusterCreator(clusterSpec.Cluster) + WithClusterCreator(clusterSpec.Cluster). + WithClusterMover() if cc.timeoutOptions.noTimeouts { factory.WithNoTimeouts() @@ -274,6 +275,7 @@ func (cc *createClusterOptions) createCluster(cmd *cobra.Command, _ []string) er deps.PackageInstaller, deps.ClusterCreator, deps.EksaInstaller, + deps.ClusterMover, ) err = createMgmtCluster.Run(ctx, clusterSpec, createValidations) diff --git a/cmd/eksctl-anywhere/cmd/deletecluster.go b/cmd/eksctl-anywhere/cmd/deletecluster.go index 00e0465b3225..0893eb995d14 100644 --- a/cmd/eksctl-anywhere/cmd/deletecluster.go +++ b/cmd/eksctl-anywhere/cmd/deletecluster.go @@ -126,6 +126,7 @@ func (dc *deleteClusterOptions) deleteCluster(ctx context.Context) error { WithEksdInstaller(). WithEKSAInstaller(). WithUnAuthKubeClient(). + WithClusterMover(). Build(ctx) if err != nil { return err @@ -154,7 +155,7 @@ func (dc *deleteClusterOptions) deleteCluster(ctx context.Context) error { deleteWorkload := workload.NewDelete(deps.Provider, deps.Writer, deps.ClusterManager, deps.ClusterDeleter, deps.GitOpsFlux) err = deleteWorkload.Run(ctx, cluster, clusterSpec) } else { - deleteManagement := management.NewDelete(deps.Bootstrapper, deps.Provider, deps.Writer, deps.ClusterManager, deps.GitOpsFlux, deps.ClusterDeleter, deps.EksdInstaller, deps.EksaInstaller, deps.UnAuthKubeClient) + deleteManagement := management.NewDelete(deps.Bootstrapper, deps.Provider, deps.Writer, deps.ClusterManager, deps.GitOpsFlux, deps.ClusterDeleter, deps.EksdInstaller, deps.EksaInstaller, deps.UnAuthKubeClient, deps.ClusterMover) err = deleteManagement.Run(ctx, cluster, clusterSpec) } cleanup(deps, &err) diff --git a/pkg/clustermanager/cluster_manager.go b/pkg/clustermanager/cluster_manager.go index d14dbe3aea7d..84c69ac1271f 100644 --- a/pkg/clustermanager/cluster_manager.go +++ b/pkg/clustermanager/cluster_manager.go @@ -693,6 +693,20 @@ func (c *ClusterManager) ResumeCAPIWorkloadClusters(ctx context.Context, managem return nil } +func (c *ClusterManager) AllowDeleteWhilePaused(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec) error { + return c.allowDeleteWhilePaused(ctx, cluster, clusterSpec.Cluster) +} + +func (c *ClusterManager) allowDeleteWhilePaused(ctx context.Context, clusterCreds *types.Cluster, cluster *v1alpha1.Cluster) error { + allowDelete := map[string]string{v1alpha1.AllowDeleteWhenPausedAnnotation: "true"} + + if err := c.clusterClient.UpdateAnnotationInNamespace(ctx, cluster.ResourceType(), cluster.Name, allowDelete, clusterCreds, cluster.Namespace); err != nil { + return fmt.Errorf("updating paused annotation in cluster reconciliation: %v", err) + } + + return nil +} + func (c *ClusterManager) PauseEKSAControllerReconcile(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec, provider providers.Provider) error { if clusterSpec.Cluster.IsSelfManaged() { return c.pauseEksaReconcileForManagementAndWorkloadClusters(ctx, cluster, clusterSpec, provider) diff --git a/pkg/task/task.go b/pkg/task/task.go index 6f2e46d9cc55..24ac57991786 100644 --- a/pkg/task/task.go +++ b/pkg/task/task.go @@ -52,6 +52,7 @@ type CommandContext struct { OriginalError error BackupClusterStateDir string ForceCleanup bool + ClusterMover interfaces.ClusterMover } func (c *CommandContext) SetError(err error) { diff --git a/pkg/workflows/create_prep.go b/pkg/workflows/create_prep.go index bba782c31513..8e3b76d8c21c 100644 --- a/pkg/workflows/create_prep.go +++ b/pkg/workflows/create_prep.go @@ -7,22 +7,11 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/aws/eks-anywhere/pkg/workflows/interfaces" + "github.com/aws/eks-anywhere/pkg/clients/kubernetes" ) // CreateNamespaceIfNotPresent creates the namespace on the cluster if it does not already exist. -func CreateNamespaceIfNotPresent(ctx context.Context, namespace, kubeconfig string, clientFactory interfaces.ClientFactory) error { - client, err := clientFactory.BuildClientFromKubeconfig(kubeconfig) - if err != nil { - return err - } - - if err := client.Get(ctx, namespace, "", &corev1.Namespace{}); err != nil && !errors.IsNotFound(err) { - return err - } else if err == nil { - return nil - } - +func CreateNamespaceIfNotPresent(ctx context.Context, namespace string, client kubernetes.Client) error { ns := &corev1.Namespace{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", @@ -33,7 +22,7 @@ func CreateNamespaceIfNotPresent(ctx context.Context, namespace, kubeconfig stri }, } - if err = client.Create(ctx, ns); err != nil { + if err := client.Create(ctx, ns); err != nil && !errors.IsAlreadyExists(err) { return err } diff --git a/pkg/workflows/create_prep_test.go b/pkg/workflows/create_prep_test.go index a5df25c1bc92..c3857f08a3df 100644 --- a/pkg/workflows/create_prep_test.go +++ b/pkg/workflows/create_prep_test.go @@ -50,14 +50,11 @@ func newNamespace(name string) *corev1.Namespace { func TestCreateNamespaceNotExistsSuccess(t *testing.T) { test := newCreatePrepTest(t) - kubeconfig := "testpath" namespace := "test-ns" - test.clientFactory.EXPECT().BuildClientFromKubeconfig(kubeconfig).Return(test.client, nil) - test.client.EXPECT().Get(test.ctx, namespace, "", &corev1.Namespace{}).Return(apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: ""}, "")) test.client.EXPECT().Create(test.ctx, newNamespace(namespace)).Return(nil) - err := workflows.CreateNamespaceIfNotPresent(test.ctx, namespace, kubeconfig, test.clientFactory) + err := workflows.CreateNamespaceIfNotPresent(test.ctx, namespace, test.client) if err != nil { t.Fatalf("Expected nil, but got %v", err) } @@ -65,57 +62,23 @@ func TestCreateNamespaceNotExistsSuccess(t *testing.T) { func TestCreateNamespaceAlreadyExistsSuccess(t *testing.T) { test := newCreatePrepTest(t) - kubeconfig := "testpath" namespace := "default" - test.clientFactory.EXPECT().BuildClientFromKubeconfig(kubeconfig).Return(test.client, nil) - test.client.EXPECT().Get(test.ctx, namespace, "", &corev1.Namespace{}).Return(nil) + test.client.EXPECT().Create(test.ctx, newNamespace(namespace)).Return(apierrors.NewAlreadyExists(schema.GroupResource{Group: "", Resource: ""}, "")) - err := workflows.CreateNamespaceIfNotPresent(test.ctx, namespace, kubeconfig, test.clientFactory) + err := workflows.CreateNamespaceIfNotPresent(test.ctx, namespace, test.client) if err != nil { t.Fatalf("Expected nil, but got %v", err) } } -func TestCreateNamespaceBuildClientFail(t *testing.T) { - test := newCreatePrepTest(t) - kubeconfig := "testpath" - namespace := "test-ns" - - test.clientFactory.EXPECT().BuildClientFromKubeconfig(kubeconfig).Return(test.client, fmt.Errorf("")) - - err := workflows.CreateNamespaceIfNotPresent(test.ctx, namespace, kubeconfig, test.clientFactory) - - if err == nil { - t.Fatalf("Expected error, but got nil") - } -} - -func TestCreateNamespaceGetNamespaceFail(t *testing.T) { - test := newCreatePrepTest(t) - kubeconfig := "testpath" - namespace := "test-ns" - - test.clientFactory.EXPECT().BuildClientFromKubeconfig(kubeconfig).Return(test.client, nil) - test.client.EXPECT().Get(test.ctx, namespace, "", &corev1.Namespace{}).Return(fmt.Errorf("")) - - err := workflows.CreateNamespaceIfNotPresent(test.ctx, namespace, kubeconfig, test.clientFactory) - - if err == nil { - t.Fatalf("Expected error, but got nil") - } -} - func TestCreateNamespaceFail(t *testing.T) { test := newCreatePrepTest(t) - kubeconfig := "testpath" namespace := "test-ns" - test.clientFactory.EXPECT().BuildClientFromKubeconfig(kubeconfig).Return(test.client, nil) - test.client.EXPECT().Get(test.ctx, namespace, "", &corev1.Namespace{}).Return(apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: ""}, "")) test.client.EXPECT().Create(test.ctx, newNamespace(namespace)).Return(fmt.Errorf("")) - err := workflows.CreateNamespaceIfNotPresent(test.ctx, namespace, kubeconfig, test.clientFactory) + err := workflows.CreateNamespaceIfNotPresent(test.ctx, namespace, test.client) if err == nil { t.Fatalf("Expected error, but got nil") diff --git a/pkg/workflows/interfaces/interfaces.go b/pkg/workflows/interfaces/interfaces.go index 60adf204d0e6..7b31d1bfb947 100644 --- a/pkg/workflows/interfaces/interfaces.go +++ b/pkg/workflows/interfaces/interfaces.go @@ -98,3 +98,8 @@ type EksaInstaller interface { type ClusterDeleter interface { Run(ctx context.Context, spec *cluster.Spec, managementCluster types.Cluster) error } + +// ClusterMover moves the EKS-A cluster. +type ClusterMover interface { + Move(ctx context.Context, spec *cluster.Spec, srcClient, dstClient kubernetes.Client) error +} diff --git a/pkg/workflows/interfaces/mocks/clients.go b/pkg/workflows/interfaces/mocks/clients.go index be9f7cb42185..07e0e277411d 100644 --- a/pkg/workflows/interfaces/mocks/clients.go +++ b/pkg/workflows/interfaces/mocks/clients.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/aws/eks-anywhere/pkg/workflows/interfaces (interfaces: Bootstrapper,ClusterManager,GitOpsManager,Validator,CAPIManager,EksdInstaller,EksdUpgrader,PackageInstaller,ClusterUpgrader,ClusterCreator,ClientFactory,EksaInstaller,ClusterDeleter) +// Source: github.com/aws/eks-anywhere/pkg/workflows/interfaces (interfaces: Bootstrapper,ClusterManager,GitOpsManager,Validator,CAPIManager,EksdInstaller,EksdUpgrader,PackageInstaller,ClusterUpgrader,ClusterCreator,ClientFactory,EksaInstaller,ClusterDeleter,ClusterMover) // Package mocks is a generated GoMock package. package mocks @@ -892,3 +892,40 @@ func (mr *MockClusterDeleterMockRecorder) Run(arg0, arg1, arg2 interface{}) *gom mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockClusterDeleter)(nil).Run), arg0, arg1, arg2) } + +// MockClusterMover is a mock of ClusterMover interface. +type MockClusterMover struct { + ctrl *gomock.Controller + recorder *MockClusterMoverMockRecorder +} + +// MockClusterMoverMockRecorder is the mock recorder for MockClusterMover. +type MockClusterMoverMockRecorder struct { + mock *MockClusterMover +} + +// NewMockClusterMover creates a new mock instance. +func NewMockClusterMover(ctrl *gomock.Controller) *MockClusterMover { + mock := &MockClusterMover{ctrl: ctrl} + mock.recorder = &MockClusterMoverMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockClusterMover) EXPECT() *MockClusterMoverMockRecorder { + return m.recorder +} + +// Move mocks base method. +func (m *MockClusterMover) Move(arg0 context.Context, arg1 *cluster.Spec, arg2, arg3 kubernetes.Client) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Move", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// Move indicates an expected call of Move. +func (mr *MockClusterMoverMockRecorder) Move(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Move", reflect.TypeOf((*MockClusterMover)(nil).Move), arg0, arg1, arg2, arg3) +} diff --git a/pkg/workflows/management/create.go b/pkg/workflows/management/create.go index 9b8e4ab60bb3..23b1425d9f81 100644 --- a/pkg/workflows/management/create.go +++ b/pkg/workflows/management/create.go @@ -22,6 +22,7 @@ type Create struct { packageInstaller interfaces.PackageInstaller clusterCreator interfaces.ClusterCreator eksaInstaller interfaces.EksaInstaller + clusterMover interfaces.ClusterMover } // NewCreate builds a new create construct. @@ -32,6 +33,7 @@ func NewCreate(bootstrapper interfaces.Bootstrapper, packageInstaller interfaces.PackageInstaller, clusterCreator interfaces.ClusterCreator, eksaInstaller interfaces.EksaInstaller, + mover interfaces.ClusterMover, ) *Create { return &Create{ bootstrapper: bootstrapper, @@ -44,6 +46,7 @@ func NewCreate(bootstrapper interfaces.Bootstrapper, packageInstaller: packageInstaller, clusterCreator: clusterCreator, eksaInstaller: eksaInstaller, + clusterMover: mover, } } @@ -62,6 +65,7 @@ func (c *Create) Run(ctx context.Context, clusterSpec *cluster.Spec, validator i PackageInstaller: c.packageInstaller, ClusterCreator: c.clusterCreator, EksaInstaller: c.eksaInstaller, + ClusterMover: c.clusterMover, } return task.NewTaskRunner(&setupAndValidateCreate{}, c.writer).RunTask(ctx, commandContext) diff --git a/pkg/workflows/management/create_install_eksa.go b/pkg/workflows/management/create_install_eksa.go index 93a91627bd5e..b24674f6b44d 100644 --- a/pkg/workflows/management/create_install_eksa.go +++ b/pkg/workflows/management/create_install_eksa.go @@ -58,15 +58,32 @@ func (s *installEksaComponentsOnWorkloadTask) Run(ctx context.Context, commandCo commandContext.ClusterSpec.Cluster.AddManagedByCLIAnnotation() commandContext.ClusterSpec.Cluster.SetManagementComponentsVersion(commandContext.ClusterSpec.EKSARelease.Spec.Version) + srcClient, err := commandContext.ClientFactory.BuildClientFromKubeconfig(commandContext.BootstrapCluster.KubeconfigFile) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + + dstClient, err := commandContext.ClientFactory.BuildClientFromKubeconfig(commandContext.WorkloadCluster.KubeconfigFile) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + if commandContext.ClusterSpec.Cluster.Namespace != "" { - if err := workflows.CreateNamespaceIfNotPresent(ctx, commandContext.ClusterSpec.Cluster.Namespace, commandContext.WorkloadCluster.KubeconfigFile, commandContext.ClientFactory); err != nil { + if err := workflows.CreateNamespaceIfNotPresent(ctx, commandContext.ClusterSpec.Cluster.Namespace, dstClient); err != nil { commandContext.SetError(err) return &workflows.CollectMgmtClusterDiagnosticsTask{} } } - logger.Info("Applying cluster spec to workload cluster") - if err = commandContext.ClusterCreator.Run(ctx, commandContext.ClusterSpec, *commandContext.WorkloadCluster); err != nil { + logger.Info("Moving cluster spec to workload cluster") + if err = commandContext.ClusterMover.Move(ctx, commandContext.ClusterSpec, srcClient, dstClient); err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + + if err = commandContext.ClusterManager.ResumeEKSAControllerReconcile(ctx, commandContext.WorkloadCluster, commandContext.ClusterSpec, commandContext.Provider); err != nil { commandContext.SetError(err) return &workflows.CollectMgmtClusterDiagnosticsTask{} } diff --git a/pkg/workflows/management/create_test.go b/pkg/workflows/management/create_test.go index 4884b57be875..4a2bc6cc1316 100644 --- a/pkg/workflows/management/create_test.go +++ b/pkg/workflows/management/create_test.go @@ -49,6 +49,7 @@ type createTestSetup struct { workflow *management.Create client *clientmocks.MockClient clientFactory *mocks.MockClientFactory + mover *mocks.MockClusterMover } func newCreateTest(t *testing.T) *createTestSetup { @@ -71,6 +72,7 @@ func newCreateTest(t *testing.T) *createTestSetup { validator := mocks.NewMockValidator(mockCtrl) client := clientmocks.NewMockClient(mockCtrl) clientFactory := mocks.NewMockClientFactory(mockCtrl) + mover := mocks.NewMockClusterMover(mockCtrl) workflow := management.NewCreate( bootstrapper, @@ -83,6 +85,7 @@ func newCreateTest(t *testing.T) *createTestSetup { packageInstaller, clusterCreator, eksaInstaller, + mover, ) for _, e := range featureEnvVars { @@ -119,6 +122,7 @@ func newCreateTest(t *testing.T) *createTestSetup { managementComponents: managementComponents, clusterSpec: clusterSpec, client: client, + mover: mover, } } @@ -231,9 +235,13 @@ func (c *createTestSetup) expectInstallEksaComponentsWorkload(err1, err2, err3 e c.eksdInstaller.EXPECT().InstallEksdManifest( c.ctx, c.clusterSpec, c.workloadCluster), - c.clientFactory.EXPECT().BuildClientFromKubeconfig(c.workloadCluster.KubeconfigFile).Return(c.client, err3), + c.clientFactory.EXPECT().BuildClientFromKubeconfig(c.bootstrapCluster.KubeconfigFile).Return(c.client, nil), - c.clusterCreator.EXPECT().Run(c.ctx, c.clusterSpec, *c.workloadCluster).Return(err2), + c.clientFactory.EXPECT().BuildClientFromKubeconfig(c.workloadCluster.KubeconfigFile).Return(c.client, nil), + + c.mover.EXPECT().Move(c.ctx, c.clusterSpec, c.client, c.client).Return(err2), + + c.clusterManager.EXPECT().ResumeEKSAControllerReconcile(c.ctx, c.workloadCluster, c.clusterSpec, c.provider).Return(err3).MaxTimes(1), ) } @@ -747,7 +755,7 @@ func TestCreateEKSAWorkloadFailure(t *testing.T) { } } -func TestCreateEKSAWorkloadNamespaceFailure(t *testing.T) { +func TestCreateEKSAResumeWorkloadFailure(t *testing.T) { test := newCreateTest(t) test.expectSetup() test.expectPreflightValidationsToPass() @@ -755,25 +763,11 @@ func TestCreateEKSAWorkloadNamespaceFailure(t *testing.T) { test.expectCAPIInstall(nil, nil, nil) test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil) test.expectCreateWorkload(nil, nil, nil, nil, nil, nil) - test.expectCreateNamespace() test.expectInstallResourcesOnManagementTask(nil) test.expectPauseReconcile(nil) test.expectMoveManagement(nil) - gomock.InOrder( - - test.eksdInstaller.EXPECT().InstallEksdCRDs(test.ctx, test.clusterSpec, test.workloadCluster), - - test.eksaInstaller.EXPECT().Install( - test.ctx, logger.Get(), test.workloadCluster, test.managementComponents, test.clusterSpec), - - test.provider.EXPECT().InstallCustomProviderComponents( - test.ctx, test.workloadCluster.KubeconfigFile), - - test.eksdInstaller.EXPECT().InstallEksdManifest( - test.ctx, test.clusterSpec, test.workloadCluster), - - test.clientFactory.EXPECT().BuildClientFromKubeconfig(test.workloadCluster.KubeconfigFile).Return(test.client, fmt.Errorf("")), - ) + test.expectInstallEksaComponentsWorkload(nil, nil, fmt.Errorf("test")) + test.expectCreateNamespace() test.clusterManager.EXPECT().SaveLogsManagementCluster(test.ctx, test.clusterSpec, test.bootstrapCluster) diff --git a/pkg/workflows/management/create_workload.go b/pkg/workflows/management/create_workload.go index e3289a297816..bc8f5fc946b3 100644 --- a/pkg/workflows/management/create_workload.go +++ b/pkg/workflows/management/create_workload.go @@ -18,8 +18,14 @@ func (s *createWorkloadClusterTask) Run(ctx context.Context, commandContext *tas commandContext.ClusterSpec.Cluster.AddManagedByCLIAnnotation() commandContext.ClusterSpec.Cluster.SetManagementComponentsVersion(commandContext.ClusterSpec.EKSARelease.Spec.Version) + client, err := commandContext.ClientFactory.BuildClientFromKubeconfig(commandContext.BootstrapCluster.KubeconfigFile) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + if commandContext.ClusterSpec.Cluster.Namespace != "" { - if err := workflows.CreateNamespaceIfNotPresent(ctx, commandContext.ClusterSpec.Cluster.Namespace, commandContext.BootstrapCluster.KubeconfigFile, commandContext.ClientFactory); err != nil { + if err := workflows.CreateNamespaceIfNotPresent(ctx, commandContext.ClusterSpec.Cluster.Namespace, client); err != nil { commandContext.SetError(err) return &workflows.CollectMgmtClusterDiagnosticsTask{} } diff --git a/pkg/workflows/management/delete.go b/pkg/workflows/management/delete.go index a8af5e4b38aa..9ed7adf86484 100644 --- a/pkg/workflows/management/delete.go +++ b/pkg/workflows/management/delete.go @@ -22,6 +22,7 @@ type Delete struct { eksdInstaller interfaces.EksdInstaller eksaInstaller interfaces.EksaInstaller clientFactory interfaces.ClientFactory + clusterMover interfaces.ClusterMover } // NewDelete builds a new delete construct. @@ -34,6 +35,7 @@ func NewDelete(bootstrapper interfaces.Bootstrapper, eksdInstaller interfaces.EksdInstaller, eksaInstaller interfaces.EksaInstaller, clientFactory interfaces.ClientFactory, + mover interfaces.ClusterMover, ) *Delete { return &Delete{ bootstrapper: bootstrapper, @@ -45,6 +47,7 @@ func NewDelete(bootstrapper interfaces.Bootstrapper, eksdInstaller: eksdInstaller, eksaInstaller: eksaInstaller, clientFactory: clientFactory, + clusterMover: mover, } } @@ -62,6 +65,7 @@ func (c *Delete) Run(ctx context.Context, workload *types.Cluster, clusterSpec * EksdInstaller: c.eksdInstaller, EksaInstaller: c.eksaInstaller, ClientFactory: c.clientFactory, + ClusterMover: c.clusterMover, } return task.NewTaskRunner(&setupAndValidateDelete{}, c.writer).RunTask(ctx, commandContext) diff --git a/pkg/workflows/management/delete_install_eksa.go b/pkg/workflows/management/delete_install_eksa.go index b7dd96e6c93c..30f447113985 100644 --- a/pkg/workflows/management/delete_install_eksa.go +++ b/pkg/workflows/management/delete_install_eksa.go @@ -3,15 +3,9 @@ package management import ( "context" - "github.com/pkg/errors" - - "github.com/aws/eks-anywhere/pkg/clients/kubernetes" - "github.com/aws/eks-anywhere/pkg/cluster" "github.com/aws/eks-anywhere/pkg/logger" "github.com/aws/eks-anywhere/pkg/task" - "github.com/aws/eks-anywhere/pkg/types" "github.com/aws/eks-anywhere/pkg/workflows" - "github.com/aws/eks-anywhere/pkg/workflows/interfaces" ) type installEksaComponentsOnBootstrapForDeleteTask struct{} @@ -24,16 +18,34 @@ func (s *installEksaComponentsOnBootstrapForDeleteTask) Run(ctx context.Context, return &workflows.CollectDiagnosticsTask{} } - commandContext.ClusterSpec.Cluster.PauseReconcile() - commandContext.ClusterSpec.Cluster.AllowDeleteWhilePaused() - commandContext.ClusterSpec.Cluster.SetFinalizers([]string{"clusters.anywhere.eks.amazonaws.com/finalizer"}) - commandContext.ClusterSpec.Cluster.AddManagedByCLIAnnotation() - err = applyClusterSpecOnBootstrapForDeleteTask(ctx, commandContext.ClusterSpec, commandContext.BootstrapCluster, commandContext.ClientFactory) + srcClient, err := commandContext.ClientFactory.BuildClientFromKubeconfig(commandContext.WorkloadCluster.KubeconfigFile) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + + dstClient, err := commandContext.ClientFactory.BuildClientFromKubeconfig(commandContext.BootstrapCluster.KubeconfigFile) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + + if err := workflows.CreateNamespaceIfNotPresent(ctx, commandContext.ClusterSpec.Cluster.Namespace, dstClient); err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + + err = commandContext.ClusterMover.Move(ctx, commandContext.ClusterSpec, srcClient, dstClient) if err != nil { commandContext.SetError(err) return &workflows.CollectDiagnosticsTask{} } + if err = commandContext.ClusterManager.AllowDeleteWhilePaused(ctx, commandContext.BootstrapCluster, commandContext.ClusterSpec); err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + return &deleteManagementCluster{} } @@ -48,26 +60,3 @@ func (s *installEksaComponentsOnBootstrapForDeleteTask) Restore(ctx context.Cont func (s *installEksaComponentsOnBootstrapForDeleteTask) Checkpoint() *task.CompletedTask { return nil } - -func applyClusterSpecOnBootstrapForDeleteTask(ctx context.Context, spec *cluster.Spec, cluster *types.Cluster, clientFactory interfaces.ClientFactory) error { - if err := workflows.CreateNamespaceIfNotPresent(ctx, spec.Cluster.Namespace, cluster.KubeconfigFile, clientFactory); err != nil { - return errors.Wrapf(err, "creating namespace on bootstrap") - } - - client, err := clientFactory.BuildClientFromKubeconfig(cluster.KubeconfigFile) - if err != nil { - return errors.Wrap(err, "building client to apply cluster spec changes") - } - - for _, obj := range spec.ClusterAndChildren() { - if err := client.ApplyServerSide(ctx, - "eks-a-cli", - obj, - kubernetes.ApplyServerSideOptions{ForceOwnership: true}, - ); err != nil { - return errors.Wrapf(err, "applying cluster spec") - } - } - - return nil -} diff --git a/pkg/workflows/management/delete_test.go b/pkg/workflows/management/delete_test.go index 32c2cac65325..034f286b1b99 100644 --- a/pkg/workflows/management/delete_test.go +++ b/pkg/workflows/management/delete_test.go @@ -8,9 +8,6 @@ import ( "github.com/golang/mock/gomock" corev1 "k8s.io/api/core/v1" - apierrors "k8s.io/apimachinery/pkg/api/errors" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" "github.com/aws/eks-anywhere/internal/test" "github.com/aws/eks-anywhere/pkg/api/v1alpha1" @@ -48,6 +45,7 @@ type deleteTestSetup struct { clientFactory *mocks.MockClientFactory managementComponents *cluster.ManagementComponents client *clientmocks.MockClient + mover *mocks.MockClusterMover } func newDeleteTest(t *testing.T) *deleteTestSetup { @@ -73,6 +71,7 @@ func newDeleteTest(t *testing.T) *deleteTestSetup { s.GitOpsConfig = &v1alpha1.GitOpsConfig{} }) managementComponents := cluster.ManagementComponentsFromBundles(clusterSpec.Bundles) + mover := mocks.NewMockClusterMover(mockCtrl) workload := management.NewDelete( bootstrapper, @@ -84,6 +83,7 @@ func newDeleteTest(t *testing.T) *deleteTestSetup { eksdInstaller, eksaInstaller, clientFactory, + mover, ) for _, e := range featureEnvVars { @@ -110,6 +110,7 @@ func newDeleteTest(t *testing.T) *deleteTestSetup { clientFactory: clientFactory, managementComponents: managementComponents, client: client, + mover: mover, } } @@ -166,7 +167,7 @@ func (c *deleteTestSetup) expectMoveCAPI(err1, err2 error) { c.clusterManager.EXPECT().MoveCAPI(c.ctx, c.workloadCluster, c.bootstrapCluster, c.workloadCluster.Name, c.clusterSpec, gomock.Any()).Return(err2) } -func (c *deleteTestSetup) expectInstallEksaComponentsBootstrap(err1, err2, err3, err4, err5 error) { +func (c *deleteTestSetup) expectInstallEksaComponentsBootstrap(err1, err2, err3, err4, err5, err6 error) { gomock.InOrder( c.eksdInstaller.EXPECT().InstallEksdCRDs(c.ctx, c.clusterSpec, c.bootstrapCluster).Return(err1).AnyTimes(), @@ -179,7 +180,15 @@ func (c *deleteTestSetup) expectInstallEksaComponentsBootstrap(err1, err2, err3, c.eksdInstaller.EXPECT().InstallEksdManifest( c.ctx, c.clusterSpec, c.bootstrapCluster).Return(err4).AnyTimes(), - c.clientFactory.EXPECT().BuildClientFromKubeconfig(c.bootstrapCluster.KubeconfigFile).Return(c.client, err5).AnyTimes(), + c.clientFactory.EXPECT().BuildClientFromKubeconfig(c.workloadCluster.KubeconfigFile).Return(c.client, nil).AnyTimes(), + + c.clientFactory.EXPECT().BuildClientFromKubeconfig(c.bootstrapCluster.KubeconfigFile).Return(c.client, nil).AnyTimes(), + + c.client.EXPECT().Create(c.ctx, gomock.AssignableToTypeOf(&corev1.Namespace{})).AnyTimes(), + + c.mover.EXPECT().Move(c.ctx, c.clusterSpec, c.client, c.client).Return(err5).AnyTimes(), + + c.clusterManager.EXPECT().AllowDeleteWhilePaused(c.ctx, c.bootstrapCluster, c.clusterSpec).Return(err6).AnyTimes(), ) } @@ -195,19 +204,6 @@ func (c *deleteTestSetup) expectApplyOnBootstrap(err error) { c.client.EXPECT().ApplyServerSide(c.ctx, "eks-a-cli", gomock.Any(), gomock.Any()).Return(err).AnyTimes() } -func (c *deleteTestSetup) expectCreateNamespace() { - n := c.clusterSpec.Cluster.Namespace - ns := &corev1.Namespace{ - TypeMeta: v1.TypeMeta{ - APIVersion: "v1", - Kind: "Namespace", - }, - ObjectMeta: v1.ObjectMeta{Name: n}, - } - c.client.EXPECT().Get(c.ctx, n, "", &corev1.Namespace{}).Return(apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: ""}, "")) - c.client.EXPECT().Create(c.ctx, ns) -} - func TestDeleteRunSuccess(t *testing.T) { features.ClearCache() os.Setenv(features.UseControllerForCli, "true") @@ -218,12 +214,11 @@ func TestDeleteRunSuccess(t *testing.T) { test.expectPreCAPI(nil) test.expectInstallCAPI(nil) test.expectMoveCAPI(nil, nil) - test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, nil) + test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, nil, nil) test.expectApplyOnBootstrap(nil) test.expectDeleteCluster(nil, nil) test.expectCleanupGitRepo(nil) test.expectDeleteBootstrap(nil) - test.expectCreateNamespace() err := test.run() if err != nil { @@ -355,7 +350,7 @@ func TestDeleteRunFailResumeReconcile(t *testing.T) { test.expectPreCAPI(nil) test.expectInstallCAPI(nil) test.expectMoveCAPI(nil, nil) - test.expectInstallEksaComponentsBootstrap(fmt.Errorf(""), nil, nil, nil, nil) + test.expectInstallEksaComponentsBootstrap(fmt.Errorf(""), nil, nil, nil, nil, nil) test.expectSaveLogsManagement() test.expectSaveLogsWorkload() err := test.run() @@ -374,7 +369,7 @@ func TestDeleteRunFailAddAnnotation(t *testing.T) { test.expectPreCAPI(nil) test.expectInstallCAPI(nil) test.expectMoveCAPI(nil, nil) - test.expectInstallEksaComponentsBootstrap(nil, fmt.Errorf(""), nil, nil, nil) + test.expectInstallEksaComponentsBootstrap(nil, fmt.Errorf(""), nil, nil, nil, nil) test.expectSaveLogsManagement() test.expectSaveLogsWorkload() @@ -394,7 +389,7 @@ func TestDeleteRunFailProviderInstall(t *testing.T) { test.expectPreCAPI(nil) test.expectInstallCAPI(nil) test.expectMoveCAPI(nil, nil) - test.expectInstallEksaComponentsBootstrap(nil, nil, fmt.Errorf(""), nil, nil) + test.expectInstallEksaComponentsBootstrap(nil, nil, fmt.Errorf(""), nil, nil, nil) test.expectSaveLogsManagement() test.expectSaveLogsWorkload() @@ -414,7 +409,7 @@ func TestDeleteRunFailEksdInstall(t *testing.T) { test.expectPreCAPI(nil) test.expectInstallCAPI(nil) test.expectMoveCAPI(nil, nil) - test.expectInstallEksaComponentsBootstrap(nil, nil, nil, fmt.Errorf(""), nil) + test.expectInstallEksaComponentsBootstrap(nil, nil, nil, fmt.Errorf(""), nil, nil) test.expectSaveLogsManagement() test.expectSaveLogsWorkload() @@ -434,7 +429,7 @@ func TestDeleteRunFailBuildClient(t *testing.T) { test.expectPreCAPI(nil) test.expectInstallCAPI(nil) test.expectMoveCAPI(nil, nil) - test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, fmt.Errorf("")) + test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, fmt.Errorf(""), nil) test.expectSaveLogsManagement() test.expectSaveLogsWorkload() @@ -444,6 +439,25 @@ func TestDeleteRunFailBuildClient(t *testing.T) { } } +func TestDeleteRunFailAllowDeleteWhilePaused(t *testing.T) { + features.ClearCache() + os.Setenv(features.UseControllerForCli, "true") + test := newDeleteTest(t) + test.expectSetup(nil) + test.expectBootstrapOpts(nil) + test.expectCreateBootstrap(nil) + test.expectPreCAPI(nil) + test.expectInstallCAPI(nil) + test.expectMoveCAPI(nil, nil) + test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, nil, fmt.Errorf("")) + test.expectSaveLogsManagement() + + err := test.run() + if err == nil { + t.Fatalf("Delete.Run() err = %v, want err = nil", err) + } +} + func TestDeleteRunFailPostDelete(t *testing.T) { features.ClearCache() os.Setenv(features.UseControllerForCli, "true") @@ -454,8 +468,7 @@ func TestDeleteRunFailPostDelete(t *testing.T) { test.expectPreCAPI(nil) test.expectInstallCAPI(nil) test.expectMoveCAPI(nil, nil) - test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, nil) - test.expectCreateNamespace() + test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, nil, nil) test.expectApplyOnBootstrap(nil) test.expectDeleteCluster(nil, fmt.Errorf("")) test.expectSaveLogsManagement() @@ -476,8 +489,7 @@ func TestDeleteRunFailCleanupGit(t *testing.T) { test.expectPreCAPI(nil) test.expectInstallCAPI(nil) test.expectMoveCAPI(nil, nil) - test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, nil) - test.expectCreateNamespace() + test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, nil, nil) test.expectApplyOnBootstrap(nil) test.expectDeleteCluster(nil, nil) test.expectCleanupGitRepo(fmt.Errorf("")) @@ -500,9 +512,8 @@ func TestDeleteRunFailDeleteBootstrap(t *testing.T) { test.expectPreCAPI(nil) test.expectInstallCAPI(nil) test.expectMoveCAPI(nil, nil) - test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, nil) + test.expectInstallEksaComponentsBootstrap(nil, nil, nil, nil, nil, nil) test.expectApplyOnBootstrap(nil) - test.expectCreateNamespace() test.expectDeleteCluster(nil, nil) test.expectCleanupGitRepo(nil) test.expectDeleteBootstrap(fmt.Errorf("")) diff --git a/pkg/workflows/workload/createcluster.go b/pkg/workflows/workload/createcluster.go index b6bca3394383..0c93e91b4dec 100644 --- a/pkg/workflows/workload/createcluster.go +++ b/pkg/workflows/workload/createcluster.go @@ -15,8 +15,14 @@ type createCluster struct{} func (c *createCluster) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { logger.Info("Creating workload cluster") + client, err := commandContext.ClientFactory.BuildClientFromKubeconfig(commandContext.ManagementCluster.KubeconfigFile) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + if commandContext.ClusterSpec.Cluster.Namespace != "" { - if err := workflows.CreateNamespaceIfNotPresent(ctx, commandContext.ClusterSpec.Cluster.Namespace, commandContext.ManagementCluster.KubeconfigFile, commandContext.ClientFactory); err != nil { + if err := workflows.CreateNamespaceIfNotPresent(ctx, commandContext.ClusterSpec.Cluster.Namespace, client); err != nil { commandContext.SetError(err) return &workflows.CollectMgmtClusterDiagnosticsTask{} }