diff --git a/cmd/eksctl-anywhere/cmd/deletecluster.go b/cmd/eksctl-anywhere/cmd/deletecluster.go index c4d21cd51d9bd..c6068fb7e789f 100644 --- a/cmd/eksctl-anywhere/cmd/deletecluster.go +++ b/cmd/eksctl-anywhere/cmd/deletecluster.go @@ -161,7 +161,7 @@ func (dc *deleteClusterOptions) deleteCluster(ctx context.Context) error { deleteWorkload := workload.NewDelete(deps.Provider, deps.Writer, deps.ClusterManager, deps.ClusterDeleter) err = deleteWorkload.Run(ctx, cluster, clusterSpec) } else if features.UseControllerViaCLIWorkflow().IsActive() && clusterSpec.Cluster.IsSelfManaged() { - deleteManagement := management.NewDelete(deps.Bootstrapper, deps.Provider, deps.Writer, deps.ClusterManager, deps.ClusterDeleter, deps.GitOpsFlux) + deleteManagement := management.NewDelete(deps.Bootstrapper, deps.Provider, deps.Writer, deps.ClusterManager, deps.GitOpsFlux) err = deleteManagement.Run(ctx, cluster, clusterSpec) } else { err = deleteCluster.Run(ctx, cluster, clusterSpec, dc.forceCleanup, dc.managementKubeconfig) diff --git a/pkg/clustermanager/deleter.go b/pkg/clustermanager/deleter.go index e6ea09ebe660f..9e5b6d6291e9d 100644 --- a/pkg/clustermanager/deleter.go +++ b/pkg/clustermanager/deleter.go @@ -7,11 +7,9 @@ import ( "github.com/go-logr/logr" "github.com/pkg/errors" - "sigs.k8s.io/cluster-api/api/v1beta1" "github.com/aws/eks-anywhere/pkg/clients/kubernetes" "github.com/aws/eks-anywhere/pkg/cluster" - "github.com/aws/eks-anywhere/pkg/constants" "github.com/aws/eks-anywhere/pkg/retrier" "github.com/aws/eks-anywhere/pkg/types" ) @@ -101,37 +99,3 @@ func (a Deleter) Run(ctx context.Context, spec *cluster.Spec, managementCluster return nil } - -// DeleteCAPICluster deletes the CAPI cluster in the bootstrap cluster and waits -// until the changes are fully reconciled. -func (a Deleter) DeleteCAPICluster(ctx context.Context, cluster string, bootstrapCluster types.Cluster) error { - var client kubernetes.Client - a.log.V(3).Info("Deleting cluster spec") - err := retrier.New( - a.deleteClusterTimeout, - retrier.WithRetryPolicy(retrier.BackOffPolicy(a.retryBackOff)), - ).Retry(func() error { - var err error - client, err = a.clientFactory.BuildClientFromKubeconfig(bootstrapCluster.KubeconfigFile) - if err != nil { - return errors.Wrap(err, "building client to delete cluster") - } - - capiCluster := &v1beta1.Cluster{} - - if err := client.Get(ctx, cluster, constants.EksaSystemNamespace, capiCluster); err != nil { - return errors.Wrapf(err, "getting capi cluster") - } - - if err := client.Delete(ctx, capiCluster); err != nil { - return errors.Wrapf(err, "deleting cluster") - } - - return nil - }) - if err != nil { - return err - } - - return nil -} diff --git a/pkg/workflows/interfaces/interfaces.go b/pkg/workflows/interfaces/interfaces.go index 2c00105a885a3..efd0d4dbf5444 100644 --- a/pkg/workflows/interfaces/interfaces.go +++ b/pkg/workflows/interfaces/interfaces.go @@ -110,5 +110,4 @@ type EksaInstaller interface { // ClusterDeleter deletes the cluster. type ClusterDeleter interface { Run(ctx context.Context, spec *cluster.Spec, managementCluster types.Cluster) error - DeleteCAPICluster(ctx context.Context, cluster string, bootstrapCluster types.Cluster) error } diff --git a/pkg/workflows/management/create_delete_bootstrap.go b/pkg/workflows/management/create_delete_bootstrap.go index 186107a2e9383..9a4216a7ba1c7 100644 --- a/pkg/workflows/management/create_delete_bootstrap.go +++ b/pkg/workflows/management/create_delete_bootstrap.go @@ -39,7 +39,7 @@ type deleteBootstrapClusterForDeleteTask struct{} func (s *deleteBootstrapClusterForDeleteTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { logger.Info("Deleting bootstrap cluster") - if err := commandContext.Bootstrapper.DeleteBootstrapCluster(ctx, commandContext.BootstrapCluster, constants.Delete, true); err != nil { + if err := commandContext.Bootstrapper.DeleteBootstrapCluster(ctx, commandContext.BootstrapCluster, constants.Delete, false); err != nil { commandContext.SetError(err) } diff --git a/pkg/workflows/management/create_install_capi.go b/pkg/workflows/management/create_install_capi.go index 53d43703eb6d6..cf19d21488b78 100644 --- a/pkg/workflows/management/create_install_capi.go +++ b/pkg/workflows/management/create_install_capi.go @@ -56,7 +56,8 @@ func (s *installCAPIComponentsForDeleteTask) Run(ctx context.Context, commandCon } logger.Info("Installing cluster-api providers on bootstrap cluster") - if err := commandContext.ClusterManager.InstallCAPI(ctx, commandContext.ClusterSpec, commandContext.BootstrapCluster, commandContext.Provider); err != nil { + managementComponents := cluster.ManagementComponentsFromBundles(commandContext.ClusterSpec.Bundles) + if err := commandContext.ClusterManager.InstallCAPI(ctx, managementComponents, commandContext.ClusterSpec, commandContext.BootstrapCluster, commandContext.Provider); err != nil { commandContext.SetError(err) return &deleteManagementCluster{} } diff --git a/pkg/workflows/management/delete.go b/pkg/workflows/management/delete.go index 28716c7007291..21bfe00564ec5 100644 --- a/pkg/workflows/management/delete.go +++ b/pkg/workflows/management/delete.go @@ -17,7 +17,6 @@ type Delete struct { provider providers.Provider writer filewriter.FileWriter clusterManager interfaces.ClusterManager - clusterDeleter interfaces.ClusterDeleter gitopsManager interfaces.GitOpsManager } @@ -26,7 +25,6 @@ func NewDelete(bootstrapper interfaces.Bootstrapper, provider providers.Provider, writer filewriter.FileWriter, clusterManager interfaces.ClusterManager, - clusterDeleter interfaces.ClusterDeleter, gitopsManager interfaces.GitOpsManager, ) *Delete { return &Delete{ @@ -34,7 +32,6 @@ func NewDelete(bootstrapper interfaces.Bootstrapper, provider: provider, writer: writer, clusterManager: clusterManager, - clusterDeleter: clusterDeleter, gitopsManager: gitopsManager, } } @@ -48,7 +45,6 @@ func (c *Delete) Run(ctx context.Context, workload *types.Cluster, clusterSpec * ClusterManager: c.clusterManager, ClusterSpec: clusterSpec, WorkloadCluster: workload, - ClusterDeleter: c.clusterDeleter, GitOpsManager: c.gitopsManager, } diff --git a/pkg/workflows/management/delete_cluster.go b/pkg/workflows/management/delete_cluster.go index feff7adbb1177..462fd3990721c 100644 --- a/pkg/workflows/management/delete_cluster.go +++ b/pkg/workflows/management/delete_cluster.go @@ -12,7 +12,7 @@ type deleteManagementCluster struct{} func (s *deleteManagementCluster) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { logger.Info("Deleting management cluster") - err := commandContext.ClusterDeleter.DeleteCAPICluster(ctx, commandContext.ClusterSpec.Cluster.Name, *commandContext.BootstrapCluster) + err := commandContext.ClusterManager.DeleteCluster(ctx, commandContext.BootstrapCluster, commandContext.WorkloadCluster, commandContext.Provider, commandContext.ClusterSpec) if err != nil { commandContext.SetError(err) return &workflows.CollectMgmtClusterDiagnosticsTask{} diff --git a/pkg/workflows/management/delete_test.go b/pkg/workflows/management/delete_test.go new file mode 100644 index 0000000000000..8b7c11e9be553 --- /dev/null +++ b/pkg/workflows/management/delete_test.go @@ -0,0 +1,325 @@ +package management_test + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/golang/mock/gomock" + + "github.com/aws/eks-anywhere/internal/test" + "github.com/aws/eks-anywhere/pkg/api/v1alpha1" + "github.com/aws/eks-anywhere/pkg/bootstrapper" + "github.com/aws/eks-anywhere/pkg/cluster" + "github.com/aws/eks-anywhere/pkg/constants" + "github.com/aws/eks-anywhere/pkg/features" + writermocks "github.com/aws/eks-anywhere/pkg/filewriter/mocks" + "github.com/aws/eks-anywhere/pkg/providers" + providermocks "github.com/aws/eks-anywhere/pkg/providers/mocks" + "github.com/aws/eks-anywhere/pkg/types" + "github.com/aws/eks-anywhere/pkg/workflows/interfaces/mocks" + "github.com/aws/eks-anywhere/pkg/workflows/management" +) + +type deleteTestSetup struct { + t *testing.T + provider *providermocks.MockProvider + clusterManager *mocks.MockClusterManager + datacenterConfig providers.DatacenterConfig + machineConfigs []providers.MachineConfig + ctx context.Context + clusterSpec *cluster.Spec + workloadCluster *types.Cluster + workload *management.Delete + writer *writermocks.MockFileWriter + bootstrapper *mocks.MockBootstrapper + gitopsManager *mocks.MockGitOpsManager + bootstrapCluster *types.Cluster +} + +func newDeleteTest(t *testing.T) *deleteTestSetup { + featureEnvVars := []string{} + mockCtrl := gomock.NewController(t) + provider := providermocks.NewMockProvider(mockCtrl) + writer := writermocks.NewMockFileWriter(mockCtrl) + manager := mocks.NewMockClusterManager(mockCtrl) + + datacenterConfig := &v1alpha1.VSphereDatacenterConfig{} + machineConfigs := []providers.MachineConfig{&v1alpha1.VSphereMachineConfig{}} + bootstrapper := mocks.NewMockBootstrapper(mockCtrl) + gitopsManager := mocks.NewMockGitOpsManager(mockCtrl) + + workload := management.NewDelete( + bootstrapper, + provider, + writer, + manager, + gitopsManager, + ) + + for _, e := range featureEnvVars { + t.Setenv(e, "true") + } + + return &deleteTestSetup{ + t: t, + provider: provider, + datacenterConfig: datacenterConfig, + machineConfigs: machineConfigs, + workload: workload, + ctx: context.Background(), + clusterSpec: test.NewClusterSpec(func(s *cluster.Spec) { + s.Cluster.Name = "workload" + s.Cluster.Spec.DatacenterRef.Kind = v1alpha1.VSphereDatacenterKind + s.ManagementCluster = &types.Cluster{Name: "management"} + s.GitOpsConfig = &v1alpha1.GitOpsConfig{} + }), + workloadCluster: &types.Cluster{Name: "workload"}, + clusterManager: manager, + writer: writer, + bootstrapper: bootstrapper, + gitopsManager: gitopsManager, + bootstrapCluster: &types.Cluster{}, + } +} + +func (c *deleteTestSetup) expectSetup(err error) { + c.provider.EXPECT().SetupAndValidateDeleteCluster(c.ctx, c.workloadCluster, c.clusterSpec).Return(err) +} + +func (c *deleteTestSetup) expectDeleteManagementCluster(err error) { + c.clusterManager.EXPECT().DeleteCluster(c.ctx, c.bootstrapCluster, c.workloadCluster, c.provider, c.clusterSpec).Return(err) +} + +func (c *deleteTestSetup) expectCleanupGitRepo(err error) { + c.gitopsManager.EXPECT().CleanupGitRepo(c.ctx, c.clusterSpec).Return(err) +} + +func (c *deleteTestSetup) expectBootstrapOpts(err error) { + c.provider.EXPECT().BootstrapClusterOpts(c.clusterSpec).Return([]bootstrapper.BootstrapClusterOption{}, err) +} + +func (c *deleteTestSetup) expectCreateBootstrap(err error) { + c.bootstrapper.EXPECT().CreateBootstrapCluster(c.ctx, c.clusterSpec, gomock.Any()).Return(&types.Cluster{}, err) +} + +func (c *deleteTestSetup) run() error { + return c.workload.Run(c.ctx, c.workloadCluster, c.clusterSpec) +} + +func (c *deleteTestSetup) expectWrite() { + c.writer.EXPECT().Write(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil) +} + +func (c *deleteTestSetup) expectSaveLogsWorkload() { + c.clusterManager.EXPECT().SaveLogsWorkloadCluster(c.ctx, c.provider, c.clusterSpec, c.workloadCluster) +} + +func (c *deleteTestSetup) expectSaveLogsManagement() { + c.clusterManager.EXPECT().SaveLogsManagementCluster(c.ctx, c.clusterSpec, c.bootstrapCluster) + c.expectWrite() +} + +func (c *deleteTestSetup) expectDeleteBootstrap(err error) { + c.bootstrapper.EXPECT().DeleteBootstrapCluster(c.ctx, c.bootstrapCluster, constants.Delete, false).Return(err) + if err == nil { + c.writer.EXPECT().CleanUp() + } +} + +func (c *deleteTestSetup) expectPreCAPI(err error) { + c.provider.EXPECT().PreCAPIInstallOnBootstrap(c.ctx, c.bootstrapCluster, c.clusterSpec).Return(err) +} + +func (c *deleteTestSetup) expectInstallCAPI(err error) { + c.clusterManager.EXPECT().InstallCAPI(c.ctx, gomock.Any(), c.clusterSpec, c.bootstrapCluster, c.provider).Return(err) +} + +func (c *deleteTestSetup) expectMoveCAPI(err error) { + c.clusterManager.EXPECT().MoveCAPI(c.ctx, c.workloadCluster, c.bootstrapCluster, c.workloadCluster.Name, c.clusterSpec, gomock.Any()).Return(err) +} + +func (c *deleteTestSetup) expectPostDelete(err error) { + c.provider.EXPECT().PostClusterDeleteValidate(c.ctx, c.bootstrapCluster).Return(err) +} + +func TestDeleteRunSuccess(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) + test.expectDeleteManagementCluster(nil) + test.expectPostDelete(nil) + test.expectCleanupGitRepo(nil) + test.expectDeleteBootstrap(nil) + + err := test.run() + if err != nil { + t.Fatalf("Delete.Run() err = %v, want err = nil", err) + } +} + +func TestDeleteRunFailSetup(t *testing.T) { + features.ClearCache() + os.Setenv(features.UseControllerForCli, "true") + test := newDeleteTest(t) + test.expectSetup(fmt.Errorf("Failure")) + test.expectWrite() + + err := test.run() + if err == nil { + t.Fatalf("Delete.Run() err = %v, want err = nil", err) + } +} + +func TestDeleteRunFailBootstrapOpts(t *testing.T) { + features.ClearCache() + os.Setenv(features.UseControllerForCli, "true") + test := newDeleteTest(t) + test.expectSetup(nil) + test.expectBootstrapOpts(fmt.Errorf("")) + test.expectWrite() + + err := test.run() + if err == nil { + t.Fatalf("Delete.Run() err = %v, want err = nil", err) + } +} + +func TestDeleteRunFailCreateBootstrap(t *testing.T) { + features.ClearCache() + os.Setenv(features.UseControllerForCli, "true") + test := newDeleteTest(t) + test.expectSetup(nil) + test.expectBootstrapOpts(nil) + test.expectCreateBootstrap(fmt.Errorf("")) + test.expectWrite() + + err := test.run() + if err == nil { + t.Fatalf("Delete.Run() err = %v, want err = nil", err) + } +} + +func TestDeleteRunFailPreCAPI(t *testing.T) { + features.ClearCache() + os.Setenv(features.UseControllerForCli, "true") + test := newDeleteTest(t) + test.expectSetup(nil) + test.expectBootstrapOpts(nil) + test.expectCreateBootstrap(nil) + test.expectPreCAPI(fmt.Errorf("")) + test.expectSaveLogsManagement() + + err := test.run() + if err == nil { + t.Fatalf("Delete.Run() err = %v, want err = nil", err) + } +} + +func TestDeleteRunFailInstallCAPI(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(fmt.Errorf("")) + test.expectDeleteManagementCluster(fmt.Errorf("")) + test.expectSaveLogsManagement() + + err := test.run() + if err == nil { + t.Fatalf("Delete.Run() err = %v, want err = nil", err) + } +} + +func TestDeleteRunFailMoveCAPI(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(fmt.Errorf("")) + test.expectSaveLogsWorkload() + 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") + test := newDeleteTest(t) + test.expectSetup(nil) + test.expectBootstrapOpts(nil) + test.expectCreateBootstrap(nil) + test.expectPreCAPI(nil) + test.expectInstallCAPI(nil) + test.expectMoveCAPI(nil) + test.expectDeleteManagementCluster(nil) + test.expectPostDelete(fmt.Errorf("")) + test.expectSaveLogsManagement() + + err := test.run() + if err == nil { + t.Fatalf("Delete.Run() err = %v, want err = nil", err) + } +} + +func TestDeleteRunFailCleanupGit(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) + test.expectDeleteManagementCluster(nil) + test.expectPostDelete(nil) + test.expectCleanupGitRepo(fmt.Errorf("")) + test.expectSaveLogsWorkload() + test.expectSaveLogsManagement() + + err := test.run() + if err == nil { + t.Fatalf("Delete.Run() err = %v, want err = nil", err) + } +} + +func TestDeleteRunFailDeleteBootstrap(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) + test.expectDeleteManagementCluster(nil) + test.expectPostDelete(nil) + test.expectCleanupGitRepo(nil) + test.expectDeleteBootstrap(fmt.Errorf("")) + test.expectSaveLogsManagement() + + err := test.run() + if err == nil { + t.Fatalf("Delete.Run() err = %v, want err = nil", err) + } +}