From 2fe5f7792ce136c6d2249758daf0a5452442a507 Mon Sep 17 00:00:00 2001 From: Mitali Paygude Date: Thu, 30 Nov 2023 02:11:26 -0800 Subject: [PATCH] Create management cluster using controller behind feature flag --- cmd/eksctl-anywhere/cmd/createcluster.go | 17 + pkg/clustermanager/cluster_manager.go | 56 ++ pkg/clustermanager/cluster_manager_test.go | 25 + pkg/providers/cloudstack/cloudstack.go | 2 +- pkg/providers/cloudstack/cloudstack_test.go | 20 + pkg/providers/docker/docker.go | 2 +- pkg/providers/docker/docker_test.go | 18 + pkg/providers/mocks/providers.go | 24 +- pkg/providers/nutanix/provider.go | 3 +- pkg/providers/nutanix/provider_test.go | 2 +- pkg/providers/provider.go | 2 +- pkg/providers/snow/snow.go | 3 +- pkg/providers/snow/snow_test.go | 6 + pkg/providers/tinkerbell/create.go | 5 +- pkg/providers/tinkerbell/tinkerbell_test.go | 56 +- pkg/providers/vsphere/vsphere.go | 4 +- pkg/providers/vsphere/vsphere_test.go | 22 +- pkg/workflows/create.go | 2 +- pkg/workflows/create_test.go | 2 +- pkg/workflows/interfaces/interfaces.go | 2 + pkg/workflows/interfaces/mocks/clients.go | 29 + pkg/workflows/management/create.go | 60 ++ .../create_ install_eksa_components.go | 98 ++ pkg/workflows/management/create_cluster.go | 96 ++ pkg/workflows/management/create_gitops.go | 33 + .../management/create_install_capi.go | 45 + .../management/create_install_resources.go | 33 + pkg/workflows/management/create_move_capi.go | 35 + pkg/workflows/management/create_test.go | 858 ++++++++++++++++++ pkg/workflows/management/delete_bootstrap.go | 35 + .../management/install_curated_packages.go | 26 + pkg/workflows/management/upgrade.go | 4 +- .../upgrade_management_components_test.go | 8 +- pkg/workflows/management/validate.go | 54 +- .../management/write_cluster_config.go | 25 + .../testdata/cluster-name-checkpoint.yaml | 1 - 36 files changed, 1637 insertions(+), 76 deletions(-) create mode 100644 pkg/workflows/management/create.go create mode 100644 pkg/workflows/management/create_ install_eksa_components.go create mode 100644 pkg/workflows/management/create_cluster.go create mode 100644 pkg/workflows/management/create_gitops.go create mode 100644 pkg/workflows/management/create_install_capi.go create mode 100644 pkg/workflows/management/create_install_resources.go create mode 100644 pkg/workflows/management/create_move_capi.go create mode 100644 pkg/workflows/management/create_test.go create mode 100644 pkg/workflows/management/delete_bootstrap.go create mode 100644 pkg/workflows/management/install_curated_packages.go diff --git a/cmd/eksctl-anywhere/cmd/createcluster.go b/cmd/eksctl-anywhere/cmd/createcluster.go index 5f8735e8944c5..a98dd9997642f 100644 --- a/cmd/eksctl-anywhere/cmd/createcluster.go +++ b/cmd/eksctl-anywhere/cmd/createcluster.go @@ -23,6 +23,7 @@ import ( "github.com/aws/eks-anywhere/pkg/validations/createvalidations" "github.com/aws/eks-anywhere/pkg/workflow/management" "github.com/aws/eks-anywhere/pkg/workflows" + newManagementWorkflow "github.com/aws/eks-anywhere/pkg/workflows/management" "github.com/aws/eks-anywhere/pkg/workflows/workload" ) @@ -269,6 +270,22 @@ func (cc *createClusterOptions) createCluster(cmd *cobra.Command, _ []string) er ) err = createWorkloadCluster.Run(ctx, clusterSpec, createValidations) + } else if clusterSpec.Cluster.IsSelfManaged() && features.UseControllerViaCLIWorkflow().IsActive() { + + logger.Info("Using the new workflow using the controller for management cluster create") + + createMgmtCluster := newManagementWorkflow.NewCreate( + deps.Bootstrapper, + deps.Provider, + deps.ClusterManager, + deps.GitOpsFlux, + deps.Writer, + deps.EksdInstaller, + deps.PackageInstaller, + deps.ClusterApplier, + ) + + err = createMgmtCluster.Run(ctx, clusterSpec, createValidations) } else { err = createCluster.Run(ctx, clusterSpec, createValidations, cc.forceClean) } diff --git a/pkg/clustermanager/cluster_manager.go b/pkg/clustermanager/cluster_manager.go index 9c0e2b19ee2e4..2a2c6ddd40c32 100644 --- a/pkg/clustermanager/cluster_manager.go +++ b/pkg/clustermanager/cluster_manager.go @@ -450,6 +450,46 @@ func (c *ClusterManager) CreateWorkloadCluster(ctx context.Context, managementCl return workloadCluster, nil } +// GetWorkloadCluster gets workload cluster. +func (c *ClusterManager) GetWorkloadCluster(ctx context.Context, managementCluster *types.Cluster, clusterSpec *cluster.Spec, provider providers.Provider) (*types.Cluster, error) { + clusterName := clusterSpec.Cluster.Name + + workloadCluster := &types.Cluster{ + Name: clusterName, + } + + logger.V(3).Info("Waiting for workload kubeconfig generation", "cluster", clusterName) + + // Use a buffer to cache the kubeconfig. + var buf bytes.Buffer + + if err := c.getWorkloadClusterKubeconfig(ctx, clusterName, managementCluster, &buf); err != nil { + return nil, fmt.Errorf("waiting for workload kubeconfig: %v", err) + } + + rawKubeconfig := buf.Bytes() + + // The Docker provider wants to update the kubeconfig to patch the server address before + // we write it to disk. This is to ensure we can communicate with the cluster even when + // hosted inside a Docker Desktop VM. + if err := provider.UpdateKubeConfig(&rawKubeconfig, clusterName); err != nil { + return nil, err + } + + kubeconfigFile, err := c.writer.Write( + kubeconfig.FormatWorkloadClusterKubeconfigFilename(clusterName), + rawKubeconfig, + filewriter.PersistentFile, + filewriter.Permission0600, + ) + if err != nil { + return nil, fmt.Errorf("writing workload kubeconfig: %v", err) + } + workloadCluster.KubeconfigFile = kubeconfigFile + + return workloadCluster, nil +} + func (c *ClusterManager) waitUntilControlPlaneAvailable( ctx context.Context, clusterSpec *cluster.Spec, @@ -1166,6 +1206,22 @@ func (c *ClusterManager) CreateEKSAResources(ctx context.Context, cluster *types return c.ApplyReleases(ctx, clusterSpec, cluster) } +// CreateEKSAReleaseBundle applies the eks-a release bundle to the cluster. +func (c *ClusterManager) CreateEKSAReleaseBundle(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec) error { + if clusterSpec.Cluster.Namespace != "" { + if err := c.clusterClient.CreateNamespaceIfNotPresent(ctx, cluster.KubeconfigFile, clusterSpec.Cluster.Namespace); err != nil { + return err + } + } + + clusterSpec.Cluster.AddManagedByCLIAnnotation() + + if err := c.ApplyBundles(ctx, clusterSpec, cluster); err != nil { + return err + } + return c.ApplyReleases(ctx, clusterSpec, cluster) +} + func (c *ClusterManager) ApplyBundles(ctx context.Context, clusterSpec *cluster.Spec, cluster *types.Cluster) error { bundleObj, err := yaml.Marshal(clusterSpec.Bundles) if err != nil { diff --git a/pkg/clustermanager/cluster_manager_test.go b/pkg/clustermanager/cluster_manager_test.go index 9f35826273fb4..55107c882f22e 100644 --- a/pkg/clustermanager/cluster_manager_test.go +++ b/pkg/clustermanager/cluster_manager_test.go @@ -345,6 +345,31 @@ func TestClusterManagerCreateWorkloadClusterSuccess(t *testing.T) { } } +func TestClusterManagerGetWorkloadClusterSuccess(t *testing.T) { + ctx := context.Background() + clusterName := "cluster-name" + clusterSpec := test.NewClusterSpec(func(s *cluster.Spec) { + s.Cluster.Name = clusterName + s.Cluster.Spec.ControlPlaneConfiguration.Count = 3 + s.Cluster.Spec.WorkerNodeGroupConfigurations[0].Count = ptr.Int(3) + }) + + mgmtCluster := &types.Cluster{ + Name: clusterName, + KubeconfigFile: "mgmt-kubeconfig", + } + + c, m := newClusterManager(t) + kubeconfig := []byte("content") + m.client.EXPECT().GetWorkloadKubeconfig(ctx, clusterName, mgmtCluster).Return(kubeconfig, nil) + m.provider.EXPECT().UpdateKubeConfig(&kubeconfig, clusterName) + m.writer.EXPECT().Write(clusterName+"-eks-a-cluster.kubeconfig", gomock.Any(), gomock.Not(gomock.Nil())) + + if _, err := c.GetWorkloadCluster(ctx, mgmtCluster, clusterSpec, m.provider); err != nil { + t.Errorf("ClusterManager.GetWorkloadCluster() error = %v, wantErr nil", err) + } +} + func TestClusterManagerCreateWorkloadClusterErrorGetKubeconfig(t *testing.T) { tt := newTest(t) tt.clusterSpec.Cluster.Name = tt.clusterName diff --git a/pkg/providers/cloudstack/cloudstack.go b/pkg/providers/cloudstack/cloudstack.go index 84233600d9e0b..4ccc5dc3ac840 100644 --- a/pkg/providers/cloudstack/cloudstack.go +++ b/pkg/providers/cloudstack/cloudstack.go @@ -74,7 +74,7 @@ func (p *cloudstackProvider) PreCAPIInstallOnBootstrap(ctx context.Context, clus return p.UpdateSecrets(ctx, cluster, nil) } -func (p *cloudstackProvider) PostBootstrapSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { +func (p *cloudstackProvider) PostCAPIInstallSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { return nil } diff --git a/pkg/providers/cloudstack/cloudstack_test.go b/pkg/providers/cloudstack/cloudstack_test.go index b079db7c97d05..f69615bf7df2e 100644 --- a/pkg/providers/cloudstack/cloudstack_test.go +++ b/pkg/providers/cloudstack/cloudstack_test.go @@ -952,6 +952,26 @@ func TestPreCAPIInstallOnBootstrap(t *testing.T) { } } +func TestPostCAPIInstallSetup(t *testing.T) { + mockCtrl := gomock.NewController(t) + ctx := context.Background() + kubectl := mocks.NewMockProviderKubectlClient(mockCtrl) + cluster := &types.Cluster{} + clusterSpec := givenClusterSpec(t, testClusterConfigMainFilename) + clusterConfig := &v1alpha1.Cluster{} + datacenterConfig := givenDatacenterConfig(t, testClusterConfigMainFilename) + validator := givenWildcardValidator(mockCtrl, clusterSpec) + provider := newProviderWithKubectl(t, datacenterConfig, clusterSpec.Cluster, kubectl, validator) + + if provider == nil { + t.Fatalf("provider object is nil") + } + + if err := provider.PostCAPIInstallSetup(ctx, clusterConfig, cluster); err != nil { + t.Fatalf("provider.PostCAPIInstallSetup() err = %v, want err = nil", err) + } +} + func TestSetupAndValidateSSHAuthorizedKeyEmptyCP(t *testing.T) { ctx := context.Background() clusterSpec := givenClusterSpec(t, testClusterConfigMainFilename) diff --git a/pkg/providers/docker/docker.go b/pkg/providers/docker/docker.go index c4bf36d48bb9e..b5cc5dac4afcc 100644 --- a/pkg/providers/docker/docker.go +++ b/pkg/providers/docker/docker.go @@ -83,7 +83,7 @@ func (p *provider) PreCAPIInstallOnBootstrap(ctx context.Context, cluster *types return nil } -func (p *provider) PostBootstrapSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { +func (p *provider) PostCAPIInstallSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { return nil } diff --git a/pkg/providers/docker/docker_test.go b/pkg/providers/docker/docker_test.go index 22f7b01dc919c..26ed2e7677438 100644 --- a/pkg/providers/docker/docker_test.go +++ b/pkg/providers/docker/docker_test.go @@ -1011,3 +1011,21 @@ func TestTemplateBuilder_CertSANs(t *testing.T) { test.AssertContentToFile(t, string(data), tc.Output) } } + +func TestPostCAPIInstallsetup(t *testing.T) { + mockCtrl := gomock.NewController(t) + ctx := context.Background() + client := dockerMocks.NewMockProviderClient(mockCtrl) + kubectl := dockerMocks.NewMockProviderKubectlClient(mockCtrl) + provider := docker.NewProvider(&v1alpha1.DockerDatacenterConfig{}, client, kubectl, test.FakeNow) + clusterObj := &types.Cluster{Name: "node"} + + if provider == nil { + t.Fatalf("provider object is nil") + } + + err := provider.PostCAPIInstallSetup(ctx, &v1alpha1.Cluster{}, clusterObj) + if err != nil { + t.Fatalf("failed to setup PostCAPIInstallSetup: %v", err) + } +} diff --git a/pkg/providers/mocks/providers.go b/pkg/providers/mocks/providers.go index 893d5c7f3e83a..cd281571e31cc 100644 --- a/pkg/providers/mocks/providers.go +++ b/pkg/providers/mocks/providers.go @@ -255,32 +255,32 @@ func (mr *MockProviderMockRecorder) PostBootstrapDeleteForUpgrade(arg0, arg1 int return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostBootstrapDeleteForUpgrade", reflect.TypeOf((*MockProvider)(nil).PostBootstrapDeleteForUpgrade), arg0, arg1) } -// PostBootstrapSetup mocks base method. -func (m *MockProvider) PostBootstrapSetup(arg0 context.Context, arg1 *v1alpha1.Cluster, arg2 *types.Cluster) error { +// PostBootstrapSetupUpgrade mocks base method. +func (m *MockProvider) PostBootstrapSetupUpgrade(arg0 context.Context, arg1 *v1alpha1.Cluster, arg2 *types.Cluster) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PostBootstrapSetup", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "PostBootstrapSetupUpgrade", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } -// PostBootstrapSetup indicates an expected call of PostBootstrapSetup. -func (mr *MockProviderMockRecorder) PostBootstrapSetup(arg0, arg1, arg2 interface{}) *gomock.Call { +// PostBootstrapSetupUpgrade indicates an expected call of PostBootstrapSetupUpgrade. +func (mr *MockProviderMockRecorder) PostBootstrapSetupUpgrade(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostBootstrapSetup", reflect.TypeOf((*MockProvider)(nil).PostBootstrapSetup), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostBootstrapSetupUpgrade", reflect.TypeOf((*MockProvider)(nil).PostBootstrapSetupUpgrade), arg0, arg1, arg2) } -// PostBootstrapSetupUpgrade mocks base method. -func (m *MockProvider) PostBootstrapSetupUpgrade(arg0 context.Context, arg1 *v1alpha1.Cluster, arg2 *types.Cluster) error { +// PostCAPIInstallSetup mocks base method. +func (m *MockProvider) PostCAPIInstallSetup(arg0 context.Context, arg1 *v1alpha1.Cluster, arg2 *types.Cluster) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PostBootstrapSetupUpgrade", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "PostCAPIInstallSetup", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } -// PostBootstrapSetupUpgrade indicates an expected call of PostBootstrapSetupUpgrade. -func (mr *MockProviderMockRecorder) PostBootstrapSetupUpgrade(arg0, arg1, arg2 interface{}) *gomock.Call { +// PostCAPIInstallSetup indicates an expected call of PostCAPIInstallSetup. +func (mr *MockProviderMockRecorder) PostCAPIInstallSetup(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostBootstrapSetupUpgrade", reflect.TypeOf((*MockProvider)(nil).PostBootstrapSetupUpgrade), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostCAPIInstallSetup", reflect.TypeOf((*MockProvider)(nil).PostCAPIInstallSetup), arg0, arg1, arg2) } // PostClusterDeleteValidate mocks base method. diff --git a/pkg/providers/nutanix/provider.go b/pkg/providers/nutanix/provider.go index e624a1e7df0dd..662fd468adc26 100644 --- a/pkg/providers/nutanix/provider.go +++ b/pkg/providers/nutanix/provider.go @@ -115,7 +115,8 @@ func (p *Provider) BootstrapSetup(ctx context.Context, clusterConfig *v1alpha1.C return nil } -func (p *Provider) PostBootstrapSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { +// PostCAPIInstallSetup defines steps to carry out post the CAPI installation. +func (p *Provider) PostCAPIInstallSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { // TODO(nutanix): figure out if we need something else here return nil } diff --git a/pkg/providers/nutanix/provider_test.go b/pkg/providers/nutanix/provider_test.go index 060f6e8d0a1e6..67ef683568a3f 100644 --- a/pkg/providers/nutanix/provider_test.go +++ b/pkg/providers/nutanix/provider_test.go @@ -138,7 +138,7 @@ func TestNutanixProviderBootstrapSetup(t *testing.T) { func TestNutanixProviderPostBootstrapSetup(t *testing.T) { provider := testDefaultNutanixProvider(t) - err := provider.PostBootstrapSetup(context.Background(), provider.clusterConfig, &types.Cluster{Name: "eksa-unit-test"}) + err := provider.PostCAPIInstallSetup(context.Background(), provider.clusterConfig, &types.Cluster{Name: "eksa-unit-test"}) assert.NoError(t, err) } diff --git a/pkg/providers/provider.go b/pkg/providers/provider.go index 9f37739d62bed..f9852a5e579a2 100644 --- a/pkg/providers/provider.go +++ b/pkg/providers/provider.go @@ -19,7 +19,7 @@ type Provider interface { GenerateCAPISpecForUpgrade(ctx context.Context, bootstrapCluster, workloadCluster *types.Cluster, currrentSpec, newClusterSpec *cluster.Spec) (controlPlaneSpec, workersSpec []byte, err error) // PreCAPIInstallOnBootstrap is called after the bootstrap cluster is setup but before CAPI resources are installed on it. This allows us to do provider specific configuration on the bootstrap cluster. PreCAPIInstallOnBootstrap(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec) error - PostBootstrapSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error + PostCAPIInstallSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error PostBootstrapDeleteForUpgrade(ctx context.Context, cluster *types.Cluster) error PostBootstrapSetupUpgrade(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error // PostWorkloadInit is called after the workload cluster is created and initialized with a CNI. This allows us to do provider specific configuration on the workload cluster. diff --git a/pkg/providers/snow/snow.go b/pkg/providers/snow/snow.go index 33335143d820b..f0d8654c84507 100644 --- a/pkg/providers/snow/snow.go +++ b/pkg/providers/snow/snow.go @@ -164,7 +164,8 @@ func (p *SnowProvider) PreCAPIInstallOnBootstrap(ctx context.Context, cluster *t return nil } -func (p *SnowProvider) PostBootstrapSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { +// PostCAPIInstallSetup defines steps to carry out post the CAPI installation. +func (p *SnowProvider) PostCAPIInstallSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { return nil } diff --git a/pkg/providers/snow/snow_test.go b/pkg/providers/snow/snow_test.go index 0f88321d48f3b..a786526fd1a55 100644 --- a/pkg/providers/snow/snow_test.go +++ b/pkg/providers/snow/snow_test.go @@ -599,6 +599,12 @@ func TestSetupAndValidateCreateClusterUnsupportedInstanceTypeError(t *testing.T) tt.Expect(err).To(MatchError(ContainSubstring("not supported in device [1.2.3.4]"))) } +func TestPostCAPIInstallSetup(t *testing.T) { + tt := newSnowTest(t) + err := tt.provider.PostCAPIInstallSetup(tt.ctx, test.Cluster(), tt.cluster) + tt.Expect(err).To(BeNil()) +} + func TestSetupAndValidateCreateClusterInstanceTypeVCPUError(t *testing.T) { tt := newSnowTest(t) instanceTypes := []aws.EC2InstanceType{ diff --git a/pkg/providers/tinkerbell/create.go b/pkg/providers/tinkerbell/create.go index d6207f97962a0..ad4ae3e9f0d3f 100644 --- a/pkg/providers/tinkerbell/create.go +++ b/pkg/providers/tinkerbell/create.go @@ -46,7 +46,8 @@ func (p *Provider) PreCAPIInstallOnBootstrap(ctx context.Context, cluster *types return nil } -func (p *Provider) PostBootstrapSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { +// PostCAPIInstallSetup defines steps to carry out post the CAPI installation. +func (p *Provider) PostCAPIInstallSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { return p.applyHardware(ctx, cluster) } @@ -231,7 +232,7 @@ func (p *Provider) readCSVToCatalogue() error { machineValidator := hardware.NewDefaultMachineValidator() // Translate all Machine instances from the p.machines source into Kubernetes object types. - // The PostBootstrapSetup() call invoked elsewhere in the program serializes the catalogue + // The PostCAPIInstallSetup() call invoked elsewhere in the program serializes the catalogue // and submits it to the clsuter. machines, err := hardware.NewNormalizedCSVReaderFromFile(p.hardwareCSVFile, p.BMCOptions) if err != nil { diff --git a/pkg/providers/tinkerbell/tinkerbell_test.go b/pkg/providers/tinkerbell/tinkerbell_test.go index 2ce1d8968375b..b814d2bf80064 100644 --- a/pkg/providers/tinkerbell/tinkerbell_test.go +++ b/pkg/providers/tinkerbell/tinkerbell_test.go @@ -593,7 +593,7 @@ func TestPostBootstrapSetupSuccess(t *testing.T) { t.Fatalf("failed to read hardware csv: %v", err) } - err := provider.PostBootstrapSetup(ctx, provider.clusterConfig, cluster) + err := provider.PostCAPIInstallSetup(ctx, provider.clusterConfig, cluster) if err != nil { t.Fatalf("failed PostBootstrapSetup: %v", err) } @@ -623,7 +623,7 @@ func TestPostBootstrapSetupWaitForRufioMachinesFail(t *testing.T) { t.Fatalf("failed to read hardware csv: %v", err) } - err := provider.PostBootstrapSetup(ctx, provider.clusterConfig, cluster) + err := provider.PostCAPIInstallSetup(ctx, provider.clusterConfig, cluster) assert.Error(t, err, "PostBootstrapSetup should fail") } @@ -1132,8 +1132,8 @@ func TestSetupAndValidateCreateWorkloadClusterSuccess(t *testing.T) { clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range machineConfigs { kubectl.EXPECT().SearchTinkerbellMachineConfig(ctx, config.Name, clusterSpec.ManagementCluster.KubeconfigFile, config.Namespace).Return([]*v1alpha1.TinkerbellMachineConfig{}, nil) @@ -1180,8 +1180,8 @@ func TestSetupAndValidateCreateWorkloadClusterDifferentNamespaceSuccess(t *testi clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range machineConfigs { kubectl.EXPECT().SearchTinkerbellMachineConfig(ctx, config.Name, clusterSpec.ManagementCluster.KubeconfigFile, config.Namespace).Return([]*v1alpha1.TinkerbellMachineConfig{}, nil) @@ -1226,8 +1226,8 @@ func TestSetupAndValidateCreateWorkloadClusterFailsIfMachineExists(t *testing.T) clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } idx := 0 @@ -1271,8 +1271,8 @@ func TestSetupAndValidateCreateWorkloadClusterFailsIfDatacenterExists(t *testing clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range machineConfigs { @@ -1309,8 +1309,8 @@ func TestSetupAndValidateCreateWorkloadClusterFailsIfDatacenterConfigError(t *te clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range machineConfigs { @@ -1346,8 +1346,8 @@ func TestSetupAndValidateCreateWorkloadClusterErrorUnprovisionedHardware(t *test clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range machineConfigs { kubectl.EXPECT().SearchTinkerbellMachineConfig(ctx, config.Name, clusterSpec.ManagementCluster.KubeconfigFile, config.Namespace).Return([]*v1alpha1.TinkerbellMachineConfig{}, nil) @@ -1384,8 +1384,8 @@ func TestSetupAndValidateCreateWorkloadClusterErrorProvisionedHardware(t *testin clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range machineConfigs { kubectl.EXPECT().SearchTinkerbellMachineConfig(ctx, config.Name, clusterSpec.ManagementCluster.KubeconfigFile, config.Namespace).Return([]*v1alpha1.TinkerbellMachineConfig{}, nil) @@ -1454,8 +1454,8 @@ func TestSetupAndValidateUpgradeWorkloadClusterErrorApplyHardware(t *testing.T) clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } cluster.KubeconfigFile = "kc.kubeconfig" @@ -1492,8 +1492,8 @@ func TestSetupAndValidateUpgradeWorkloadClusterErrorBMC(t *testing.T) { clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } cluster.KubeconfigFile = "kc.kubeconfig" @@ -1533,8 +1533,8 @@ func TestSetupAndValidateCreateWorkloadClusterErrorManagementCluster(t *testing. clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range machineConfigs { kubectl.EXPECT().SearchTinkerbellMachineConfig(ctx, config.Name, clusterSpec.ManagementCluster.KubeconfigFile, config.Namespace).Return([]*v1alpha1.TinkerbellMachineConfig{}, nil) @@ -1578,8 +1578,8 @@ func TestSetupAndValidateCreateWorkloadClusterErrorUnspecifiedTinkerbellIP(t *te clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range machineConfigs { kubectl.EXPECT().SearchTinkerbellMachineConfig(ctx, config.Name, clusterSpec.ManagementCluster.KubeconfigFile, config.Namespace).Return([]*v1alpha1.TinkerbellMachineConfig{}, nil) @@ -1619,8 +1619,8 @@ func TestSetupAndValidateCreateWorkloadClusterErrorManagementClusterTinkerbellIP clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range machineConfigs { kubectl.EXPECT().SearchTinkerbellMachineConfig(ctx, config.Name, clusterSpec.ManagementCluster.KubeconfigFile, config.Namespace).Return([]*v1alpha1.TinkerbellMachineConfig{}, nil) @@ -1663,8 +1663,8 @@ func TestSetupAndValidateCreateWorkloadClusterErrorDifferentTinkerbellIP(t *test clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range machineConfigs { kubectl.EXPECT().SearchTinkerbellMachineConfig(ctx, config.Name, clusterSpec.ManagementCluster.KubeconfigFile, config.Namespace).Return([]*v1alpha1.TinkerbellMachineConfig{}, nil) diff --git a/pkg/providers/vsphere/vsphere.go b/pkg/providers/vsphere/vsphere.go index 8503d19f69fc4..6880a99508fee 100644 --- a/pkg/providers/vsphere/vsphere.go +++ b/pkg/providers/vsphere/vsphere.go @@ -971,10 +971,10 @@ func (p *vsphereProvider) createSecret(ctx context.Context, cluster *types.Clust } func (p *vsphereProvider) PreCAPIInstallOnBootstrap(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec) error { - return nil + return p.UpdateSecrets(ctx, cluster, nil) } -func (p *vsphereProvider) PostBootstrapSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { +func (p *vsphereProvider) PostCAPIInstallSetup(ctx context.Context, clusterConfig *v1alpha1.Cluster, cluster *types.Cluster) error { return nil } diff --git a/pkg/providers/vsphere/vsphere_test.go b/pkg/providers/vsphere/vsphere_test.go index fbe0ee29a7c40..7eecf2f654466 100644 --- a/pkg/providers/vsphere/vsphere_test.go +++ b/pkg/providers/vsphere/vsphere_test.go @@ -1570,8 +1570,8 @@ func TestSetupAndValidateCreateWorkloadClusterSuccess(t *testing.T) { clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range clusterSpec.VSphereMachineConfigs { kubectl.EXPECT().SearchVsphereMachineConfig(ctx, config.Name, clusterSpec.ManagementCluster.KubeconfigFile, config.Namespace).Return([]*v1alpha1.VSphereMachineConfig{}, nil) @@ -1600,8 +1600,8 @@ func TestSetupAndValidateCreateWorkloadClusterFailsIfMachineExists(t *testing.T) clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } idx := 0 @@ -1634,8 +1634,8 @@ func TestSetupAndValidateSelfManagedClusterSkipMachineNameValidateSuccess(t *tes provider.ipValidator = ipValidator clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } kubectl.EXPECT().SearchVsphereMachineConfig(context.TODO(), gomock.Any(), gomock.Any(), gomock.Any()).Times(0) @@ -1664,8 +1664,8 @@ func TestSetupAndValidateCreateWorkloadClusterFailsIfDatacenterExists(t *testing clusterSpec.Cluster.SetManagedBy("management-cluster") clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } for _, config := range clusterSpec.VSphereMachineConfigs { @@ -1691,8 +1691,8 @@ func TestSetupAndValidateSelfManagedClusterSkipDatacenterNameValidateSuccess(t * provider.ipValidator = ipValidator clusterSpec.ManagementCluster = &types.Cluster{ - Name: "management-cluster", - KubeconfigFile: "kc.kubeconfig", + Name: "management-cluster", + KubeconfigFile: "kc.kubeconfig", } kubectl.EXPECT().SearchVsphereMachineConfig(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) @@ -1918,7 +1918,7 @@ func TestProviderBootstrapSetup(t *testing.T) { t.Fatalf("template execute error: %v", err) } - err = provider.PostBootstrapSetup(ctx, clusterConfig, &cluster) + err = provider.PostCAPIInstallSetup(ctx, clusterConfig, &cluster) if err != nil { t.Fatalf("BootstrapSetup error %v", err) } diff --git a/pkg/workflows/create.go b/pkg/workflows/create.go index 7843417a1e78e..05a47ee14e9a9 100644 --- a/pkg/workflows/create.go +++ b/pkg/workflows/create.go @@ -145,7 +145,7 @@ func (s *CreateBootStrapClusterTask) Run(ctx context.Context, commandContext *ta } logger.Info("Provider specific post-setup") - if err = commandContext.Provider.PostBootstrapSetup(ctx, commandContext.ClusterSpec.Cluster, bootstrapCluster); err != nil { + if err = commandContext.Provider.PostCAPIInstallSetup(ctx, commandContext.ClusterSpec.Cluster, bootstrapCluster); err != nil { commandContext.SetError(err) return &CollectMgmtClusterDiagnosticsTask{} } diff --git a/pkg/workflows/create_test.go b/pkg/workflows/create_test.go index 2a2975c1978b0..c589a5d9ac742 100644 --- a/pkg/workflows/create_test.go +++ b/pkg/workflows/create_test.go @@ -116,7 +116,7 @@ func (c *createTestSetup) expectCreateBootstrap() { c.clusterManager.EXPECT().InstallCAPI(c.ctx, c.clusterSpec, c.bootstrapCluster, c.provider), - c.provider.EXPECT().PostBootstrapSetup(c.ctx, c.clusterSpec.Cluster, c.bootstrapCluster), + c.provider.EXPECT().PostCAPIInstallSetup(c.ctx, c.clusterSpec.Cluster, c.bootstrapCluster), ) } diff --git a/pkg/workflows/interfaces/interfaces.go b/pkg/workflows/interfaces/interfaces.go index 53bf52cb2eea8..b7c8630769b10 100644 --- a/pkg/workflows/interfaces/interfaces.go +++ b/pkg/workflows/interfaces/interfaces.go @@ -21,6 +21,7 @@ type ClusterManager interface { BackupCAPIWaitForInfrastructure(ctx context.Context, cluster *types.Cluster, managementStatePath, clusterName string) error MoveCAPI(ctx context.Context, from, to *types.Cluster, clusterName string, clusterSpec *cluster.Spec, checkers ...types.NodeReadyChecker) error CreateWorkloadCluster(ctx context.Context, managementCluster *types.Cluster, clusterSpec *cluster.Spec, provider providers.Provider) (*types.Cluster, error) + GetWorkloadCluster(ctx context.Context, managementCluster *types.Cluster, clusterSpec *cluster.Spec, provider providers.Provider) (*types.Cluster, error) PauseCAPIWorkloadClusters(ctx context.Context, managementCluster *types.Cluster) error ResumeCAPIWorkloadClusters(ctx context.Context, managementCluster *types.Cluster) error RunPostCreateWorkloadCluster(ctx context.Context, managementCluster, workloadCluster *types.Cluster, clusterSpec *cluster.Spec) error @@ -34,6 +35,7 @@ type ClusterManager interface { InstallCustomComponents(ctx context.Context, clusterSpec *cluster.Spec, cluster *types.Cluster, provider providers.Provider) error CreateEKSANamespace(ctx context.Context, cluster *types.Cluster) error CreateEKSAResources(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec, datacenterConfig providers.DatacenterConfig, machineConfigs []providers.MachineConfig) error + CreateEKSAReleaseBundle(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec) error ApplyBundles(ctx context.Context, clusterSpec *cluster.Spec, cluster *types.Cluster) error ApplyReleases(ctx context.Context, clusterSpec *cluster.Spec, cluster *types.Cluster) error PauseEKSAControllerReconcile(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec, provider providers.Provider) error diff --git a/pkg/workflows/interfaces/mocks/clients.go b/pkg/workflows/interfaces/mocks/clients.go index 4e09d90db0327..64ca96cda33d8 100644 --- a/pkg/workflows/interfaces/mocks/clients.go +++ b/pkg/workflows/interfaces/mocks/clients.go @@ -181,6 +181,20 @@ func (mr *MockClusterManagerMockRecorder) CreateEKSANamespace(arg0, arg1 interfa return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEKSANamespace", reflect.TypeOf((*MockClusterManager)(nil).CreateEKSANamespace), arg0, arg1) } +// CreateEKSAReleaseBundle mocks base method. +func (m *MockClusterManager) CreateEKSAReleaseBundle(arg0 context.Context, arg1 *types.Cluster, arg2 *cluster.Spec) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateEKSAReleaseBundle", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateEKSAReleaseBundle indicates an expected call of CreateEKSAReleaseBundle. +func (mr *MockClusterManagerMockRecorder) CreateEKSAReleaseBundle(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateEKSAReleaseBundle", reflect.TypeOf((*MockClusterManager)(nil).CreateEKSAReleaseBundle), arg0, arg1, arg2) +} + // CreateEKSAResources mocks base method. func (m *MockClusterManager) CreateEKSAResources(arg0 context.Context, arg1 *types.Cluster, arg2 *cluster.Spec, arg3 providers.DatacenterConfig, arg4 []providers.MachineConfig) error { m.ctrl.T.Helper() @@ -268,6 +282,21 @@ func (mr *MockClusterManagerMockRecorder) GetCurrentClusterSpec(arg0, arg1, arg2 return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentClusterSpec", reflect.TypeOf((*MockClusterManager)(nil).GetCurrentClusterSpec), arg0, arg1, arg2) } +// GetWorkloadCluster mocks base method. +func (m *MockClusterManager) GetWorkloadCluster(arg0 context.Context, arg1 *types.Cluster, arg2 *cluster.Spec, arg3 providers.Provider) (*types.Cluster, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkloadCluster", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*types.Cluster) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkloadCluster indicates an expected call of GetWorkloadCluster. +func (mr *MockClusterManagerMockRecorder) GetWorkloadCluster(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkloadCluster", reflect.TypeOf((*MockClusterManager)(nil).GetWorkloadCluster), arg0, arg1, arg2, arg3) +} + // InstallAwsIamAuth mocks base method. func (m *MockClusterManager) InstallAwsIamAuth(arg0 context.Context, arg1, arg2 *types.Cluster, arg3 *cluster.Spec) error { m.ctrl.T.Helper() diff --git a/pkg/workflows/management/create.go b/pkg/workflows/management/create.go new file mode 100644 index 0000000000000..02e0460ce4e24 --- /dev/null +++ b/pkg/workflows/management/create.go @@ -0,0 +1,60 @@ +package management + +import ( + "context" + + "github.com/aws/eks-anywhere/pkg/cluster" + "github.com/aws/eks-anywhere/pkg/filewriter" + "github.com/aws/eks-anywhere/pkg/providers" + "github.com/aws/eks-anywhere/pkg/task" + "github.com/aws/eks-anywhere/pkg/workflows/interfaces" +) + +// Create is a schema for create cluster. +type Create struct { + bootstrapper interfaces.Bootstrapper + provider providers.Provider + clusterManager interfaces.ClusterManager + gitOpsManager interfaces.GitOpsManager + writer filewriter.FileWriter + eksdInstaller interfaces.EksdInstaller + packageInstaller interfaces.PackageInstaller + clusterCreator interfaces.ClusterCreator +} + +// NewCreate builds a new create construct. +func NewCreate(bootstrapper interfaces.Bootstrapper, provider providers.Provider, + clusterManager interfaces.ClusterManager, gitOpsManager interfaces.GitOpsManager, + writer filewriter.FileWriter, eksdInstaller interfaces.EksdInstaller, + packageInstaller interfaces.PackageInstaller, + clusterCreator interfaces.ClusterCreator, +) *Create { + return &Create{ + bootstrapper: bootstrapper, + provider: provider, + clusterManager: clusterManager, + gitOpsManager: gitOpsManager, + writer: writer, + eksdInstaller: eksdInstaller, + packageInstaller: packageInstaller, + clusterCreator: clusterCreator, + } +} + +// Run runs all the create management cluster tasks. +func (c *Create) Run(ctx context.Context, clusterSpec *cluster.Spec, validator interfaces.Validator) error { + commandContext := &task.CommandContext{ + Bootstrapper: c.bootstrapper, + Provider: c.provider, + ClusterManager: c.clusterManager, + GitOpsManager: c.gitOpsManager, + ClusterSpec: clusterSpec, + Writer: c.writer, + Validations: validator, + EksdInstaller: c.eksdInstaller, + PackageInstaller: c.packageInstaller, + ClusterCreator: c.clusterCreator, + } + + return task.NewTaskRunner(&setupAndValidateCreate{}, c.writer).RunTask(ctx, commandContext) +} diff --git a/pkg/workflows/management/create_ install_eksa_components.go b/pkg/workflows/management/create_ install_eksa_components.go new file mode 100644 index 0000000000000..8d58380a515af --- /dev/null +++ b/pkg/workflows/management/create_ install_eksa_components.go @@ -0,0 +1,98 @@ +package management + +import ( + "context" + + "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" +) + +type installEksaComponentsOnBootstrapTask struct{} + +func (s *installEksaComponentsOnBootstrapTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Installing EKS-A custom components on bootstrap cluster") + err := installEKSAComponents(ctx, commandContext, commandContext.BootstrapCluster) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectDiagnosticsTask{} + } + + return &createWorkloadClusterTask{} +} + +func (s *installEksaComponentsOnBootstrapTask) Name() string { + return "eksa-components-bootstrap-install" +} + +func (s *installEksaComponentsOnBootstrapTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *installEksaComponentsOnBootstrapTask) Checkpoint() *task.CompletedTask { + return nil +} + +type installEksaComponentsOnWorkloadTask struct{} + +func (s *installEksaComponentsOnWorkloadTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Installing EKS-A custom components on workload cluster") + + err := installEKSAComponents(ctx, commandContext, commandContext.WorkloadCluster) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectDiagnosticsTask{} + } + + logger.Info("Applying cluster spec to workload cluster") + if err = commandContext.ClusterCreator.Run(ctx, commandContext.ClusterSpec, *commandContext.WorkloadCluster); err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + + return &installGitOpsManagerTask{} +} + +func (s *installEksaComponentsOnWorkloadTask) Name() string { + return "eksa-components-workload-install" +} + +func (s *installEksaComponentsOnWorkloadTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *installEksaComponentsOnWorkloadTask) Checkpoint() *task.CompletedTask { + return nil +} + +func installEKSAComponents(ctx context.Context, commandContext *task.CommandContext, targetCluster *types.Cluster) error { + logger.Info("Installing EKS-A custom components (CRD and controller)") + err := commandContext.ClusterManager.InstallCustomComponents(ctx, commandContext.ClusterSpec, targetCluster, commandContext.Provider) + if err != nil { + commandContext.SetError(err) + return err + } + + logger.Info("Installing EKS-D components") + err = commandContext.EksdInstaller.InstallEksdCRDs(ctx, commandContext.ClusterSpec, targetCluster) + if err != nil { + commandContext.SetError(err) + return err + } + + logger.Info("Creating EKS-A CRDs instances") + err = commandContext.ClusterManager.CreateEKSAReleaseBundle(ctx, targetCluster, commandContext.ClusterSpec) + if err != nil { + commandContext.SetError(err) + return err + } + + err = commandContext.EksdInstaller.InstallEksdManifest(ctx, commandContext.ClusterSpec, targetCluster) + if err != nil { + commandContext.SetError(err) + return err + } + + return nil +} diff --git a/pkg/workflows/management/create_cluster.go b/pkg/workflows/management/create_cluster.go new file mode 100644 index 0000000000000..9b6d01584ce19 --- /dev/null +++ b/pkg/workflows/management/create_cluster.go @@ -0,0 +1,96 @@ +package management + +import ( + "context" + + "github.com/aws/eks-anywhere/pkg/logger" + "github.com/aws/eks-anywhere/pkg/task" + "github.com/aws/eks-anywhere/pkg/workflows" +) + +type createBootStrapClusterTask struct{} + +func (s *createBootStrapClusterTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Creating new bootstrap cluster") + + bootstrapOptions, err := commandContext.Provider.BootstrapClusterOpts(commandContext.ClusterSpec) + if err != nil { + commandContext.SetError(err) + return nil + } + + bootstrapCluster, err := commandContext.Bootstrapper.CreateBootstrapCluster(ctx, commandContext.ClusterSpec, bootstrapOptions...) + if err != nil { + commandContext.SetError(err) + return nil + } + commandContext.BootstrapCluster = bootstrapCluster + + return &installCAPIComponentsTask{} +} + +func (s *createBootStrapClusterTask) Name() string { + return "bootstrap-cluster-init" +} + +func (s *createBootStrapClusterTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *createBootStrapClusterTask) Checkpoint() *task.CompletedTask { + return nil +} + +// createWorkloadClusterTask implementation. +type createWorkloadClusterTask struct{} + +func (s *createWorkloadClusterTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Creating new workload cluster") + + if err := commandContext.ClusterCreator.Run(ctx, commandContext.ClusterSpec, *commandContext.BootstrapCluster); err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + + workloadCluster, err := commandContext.ClusterManager.GetWorkloadCluster(ctx, commandContext.BootstrapCluster, commandContext.ClusterSpec, commandContext.Provider) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectDiagnosticsTask{} + } + commandContext.WorkloadCluster = workloadCluster + + logger.Info("Creating EKS-A namespace") + err = commandContext.ClusterManager.CreateEKSANamespace(ctx, commandContext.WorkloadCluster) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectDiagnosticsTask{} + } + + logger.Info("Installing cluster-api providers on workload cluster") + err = commandContext.ClusterManager.InstallCAPI(ctx, commandContext.ClusterSpec, commandContext.WorkloadCluster, commandContext.Provider) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectDiagnosticsTask{} + } + + logger.Info("Installing EKS-A secrets on workload cluster") + err = commandContext.Provider.UpdateSecrets(ctx, commandContext.WorkloadCluster, commandContext.ClusterSpec) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectDiagnosticsTask{} + } + + return &installResourcesOnManagementTask{} +} + +func (s *createWorkloadClusterTask) Name() string { + return "workload-cluster-init" +} + +func (s *createWorkloadClusterTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *createWorkloadClusterTask) Checkpoint() *task.CompletedTask { + return nil +} diff --git a/pkg/workflows/management/create_gitops.go b/pkg/workflows/management/create_gitops.go new file mode 100644 index 0000000000000..66a310def37cc --- /dev/null +++ b/pkg/workflows/management/create_gitops.go @@ -0,0 +1,33 @@ +package management + +import ( + "context" + + "github.com/aws/eks-anywhere/pkg/logger" + "github.com/aws/eks-anywhere/pkg/task" +) + +type installGitOpsManagerTask struct{} + +func (s *installGitOpsManagerTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Installing GitOps Toolkit on workload cluster") + + err := commandContext.GitOpsManager.InstallGitOps(ctx, commandContext.WorkloadCluster, commandContext.ClusterSpec, commandContext.Provider.DatacenterConfig(commandContext.ClusterSpec), commandContext.Provider.MachineConfigs(commandContext.ClusterSpec)) + if err != nil { + logger.MarkFail("Error when installing GitOps toolkits on workload cluster; EKS-A will continue with cluster creation, but GitOps will not be enabled", "error", err) + return &writeClusterConfigTask{} + } + return &writeClusterConfigTask{} +} + +func (s *installGitOpsManagerTask) Name() string { + return "gitops-manager-install" +} + +func (s *installGitOpsManagerTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *installGitOpsManagerTask) Checkpoint() *task.CompletedTask { + return nil +} diff --git a/pkg/workflows/management/create_install_capi.go b/pkg/workflows/management/create_install_capi.go new file mode 100644 index 0000000000000..bd0993da8dafc --- /dev/null +++ b/pkg/workflows/management/create_install_capi.go @@ -0,0 +1,45 @@ +package management + +import ( + "context" + + "github.com/aws/eks-anywhere/pkg/logger" + "github.com/aws/eks-anywhere/pkg/task" + "github.com/aws/eks-anywhere/pkg/workflows" +) + +type installCAPIComponentsTask struct{} + +func (s *installCAPIComponentsTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Provider specific pre-capi-install-setup on bootstrap cluster") + if err := commandContext.Provider.PreCAPIInstallOnBootstrap(ctx, commandContext.BootstrapCluster, commandContext.ClusterSpec); err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + + logger.Info("Installing cluster-api providers on bootstrap cluster") + if err := commandContext.ClusterManager.InstallCAPI(ctx, commandContext.ClusterSpec, commandContext.BootstrapCluster, commandContext.Provider); err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + + logger.Info("Provider specific post-setup") + if err := commandContext.Provider.PostCAPIInstallSetup(ctx, commandContext.ClusterSpec.Cluster, commandContext.BootstrapCluster); err != nil { + commandContext.SetError(err) + return &workflows.CollectMgmtClusterDiagnosticsTask{} + } + + return &installEksaComponentsOnBootstrapTask{} +} + +func (s *installCAPIComponentsTask) Name() string { + return "install-capi-components-bootstrap" +} + +func (s *installCAPIComponentsTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *installCAPIComponentsTask) Checkpoint() *task.CompletedTask { + return nil +} diff --git a/pkg/workflows/management/create_install_resources.go b/pkg/workflows/management/create_install_resources.go new file mode 100644 index 0000000000000..8cba26e80aa00 --- /dev/null +++ b/pkg/workflows/management/create_install_resources.go @@ -0,0 +1,33 @@ +package management + +import ( + "context" + + "github.com/aws/eks-anywhere/pkg/logger" + "github.com/aws/eks-anywhere/pkg/task" + "github.com/aws/eks-anywhere/pkg/workflows" +) + +type installResourcesOnManagementTask struct{} + +func (s *installResourcesOnManagementTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Installing resources on management cluster") + + if err := commandContext.Provider.PostWorkloadInit(ctx, commandContext.WorkloadCluster, commandContext.ClusterSpec); err != nil { + commandContext.SetError(err) + return &workflows.CollectDiagnosticsTask{} + } + return &moveClusterManagementTask{} +} + +func (s *installResourcesOnManagementTask) Name() string { + return "install-resources-on-management-cluster" +} + +func (s *installResourcesOnManagementTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *installResourcesOnManagementTask) Checkpoint() *task.CompletedTask { + return nil +} diff --git a/pkg/workflows/management/create_move_capi.go b/pkg/workflows/management/create_move_capi.go new file mode 100644 index 0000000000000..c692e977d988b --- /dev/null +++ b/pkg/workflows/management/create_move_capi.go @@ -0,0 +1,35 @@ +package management + +import ( + "context" + + "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" +) + +type moveClusterManagementTask struct{} + +func (s *moveClusterManagementTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Moving cluster management from bootstrap to workload cluster") + err := commandContext.ClusterManager.MoveCAPI(ctx, commandContext.BootstrapCluster, commandContext.WorkloadCluster, commandContext.WorkloadCluster.Name, commandContext.ClusterSpec, types.WithNodeRef()) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectDiagnosticsTask{} + } + + return &installEksaComponentsOnWorkloadTask{} +} + +func (s *moveClusterManagementTask) Name() string { + return "capi-management-move" +} + +func (s *moveClusterManagementTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *moveClusterManagementTask) Checkpoint() *task.CompletedTask { + return nil +} diff --git a/pkg/workflows/management/create_test.go b/pkg/workflows/management/create_test.go new file mode 100644 index 0000000000000..0bc3a070f8ece --- /dev/null +++ b/pkg/workflows/management/create_test.go @@ -0,0 +1,858 @@ +package management_test + +import ( + "context" + "errors" + "fmt" + "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/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 createTestSetup struct { + t *testing.T + packageInstaller *mocks.MockPackageInstaller + clusterManager *mocks.MockClusterManager + bootstrapper *mocks.MockBootstrapper + gitOpsManager *mocks.MockGitOpsManager + provider *providermocks.MockProvider + writer *writermocks.MockFileWriter + validator *mocks.MockValidator + eksdInstaller *mocks.MockEksdInstaller + clusterCreator *mocks.MockClusterCreator + datacenterConfig providers.DatacenterConfig + machineConfigs []providers.MachineConfig + ctx context.Context + clusterSpec *cluster.Spec + bootstrapCluster *types.Cluster + workloadCluster *types.Cluster + workflow *management.Create +} + +func newCreateTest(t *testing.T) *createTestSetup { + featureEnvVars := []string{} + featureEnvVars = append(featureEnvVars, features.UseControllerForCli) + mockCtrl := gomock.NewController(t) + bootstrapper := mocks.NewMockBootstrapper(mockCtrl) + clusterManager := mocks.NewMockClusterManager(mockCtrl) + gitOpsManager := mocks.NewMockGitOpsManager(mockCtrl) + provider := providermocks.NewMockProvider(mockCtrl) + writer := writermocks.NewMockFileWriter(mockCtrl) + eksdInstaller := mocks.NewMockEksdInstaller(mockCtrl) + packageInstaller := mocks.NewMockPackageInstaller(mockCtrl) + + datacenterConfig := &v1alpha1.VSphereDatacenterConfig{} + machineConfigs := []providers.MachineConfig{&v1alpha1.VSphereMachineConfig{}} + clusterCreator := mocks.NewMockClusterCreator(mockCtrl) + validator := mocks.NewMockValidator(mockCtrl) + + workflow := management.NewCreate( + bootstrapper, + provider, + clusterManager, + gitOpsManager, + writer, + eksdInstaller, + packageInstaller, + clusterCreator, + ) + + for _, e := range featureEnvVars { + t.Setenv(e, "true") + } + + return &createTestSetup{ + t: t, + bootstrapper: bootstrapper, + clusterManager: clusterManager, + gitOpsManager: gitOpsManager, + provider: provider, + writer: writer, + validator: validator, + eksdInstaller: eksdInstaller, + packageInstaller: packageInstaller, + clusterCreator: clusterCreator, + datacenterConfig: datacenterConfig, + machineConfigs: machineConfigs, + workflow: workflow, + ctx: context.Background(), + bootstrapCluster: &types.Cluster{Name: "bootstrap"}, + workloadCluster: &types.Cluster{Name: "workload"}, + clusterSpec: test.NewClusterSpec(func(s *cluster.Spec) { s.Cluster.Name = "cluster-name" }), + } +} + +func (c *createTestSetup) expectSetup() { + c.provider.EXPECT().SetupAndValidateCreateCluster(c.ctx, c.clusterSpec) + c.provider.EXPECT().Name() + c.gitOpsManager.EXPECT().Validations(c.ctx, c.clusterSpec) +} + +func (c *createTestSetup) expectCreateBootstrap() { + opts := []bootstrapper.BootstrapClusterOption{bootstrapper.WithExtraDockerMounts()} + + gomock.InOrder( + c.provider.EXPECT().BootstrapClusterOpts( + c.clusterSpec).Return(opts, nil), + // Checking for not nil because in go you can't compare closures + c.bootstrapper.EXPECT().CreateBootstrapCluster( + c.ctx, c.clusterSpec, gomock.Not(gomock.Nil()), + ).Return(c.bootstrapCluster, nil), + ) +} + +func (c *createTestSetup) expectCAPIInstall() { + gomock.InOrder( + c.provider.EXPECT().PreCAPIInstallOnBootstrap( + c.ctx, c.bootstrapCluster, c.clusterSpec), + + c.clusterManager.EXPECT().InstallCAPI( + c.ctx, c.clusterSpec, c.bootstrapCluster, c.provider), + + c.provider.EXPECT().PostCAPIInstallSetup( + c.ctx, c.clusterSpec.Cluster, c.bootstrapCluster), + ) +} + +func (c *createTestSetup) expectInstallEksaComponentsBootstrap() { + gomock.InOrder( + c.clusterManager.EXPECT().InstallCustomComponents( + c.ctx, c.clusterSpec, c.bootstrapCluster, c.provider), + + c.eksdInstaller.EXPECT().InstallEksdCRDs(c.ctx, c.clusterSpec, c.bootstrapCluster), + + c.clusterManager.EXPECT().CreateEKSAReleaseBundle( + c.ctx, c.bootstrapCluster, c.clusterSpec), + + c.eksdInstaller.EXPECT().InstallEksdManifest( + c.ctx, c.clusterSpec, c.bootstrapCluster), + ) +} + +func (c *createTestSetup) expectInstallEksaComponentsWorkload(err1, err2, err3, err4, err5 error) { + gomock.InOrder( + c.clusterManager.EXPECT().InstallCustomComponents( + c.ctx, c.clusterSpec, c.workloadCluster, c.provider).Return(err1), + + c.eksdInstaller.EXPECT().InstallEksdCRDs(c.ctx, c.clusterSpec, c.workloadCluster).Return(err2), + + c.clusterManager.EXPECT().CreateEKSAReleaseBundle( + c.ctx, c.workloadCluster, c.clusterSpec).Return(err3), + + c.eksdInstaller.EXPECT().InstallEksdManifest( + c.ctx, c.clusterSpec, c.workloadCluster).Return(err4), + + c.clusterCreator.EXPECT().Run( + c.ctx, c.clusterSpec, *c.workloadCluster).Return(err5), + ) +} + +func (c *createTestSetup) expectInstallGitOpsManager() { + gomock.InOrder( + c.provider.EXPECT().DatacenterConfig( + c.clusterSpec).Return(c.datacenterConfig), + + c.provider.EXPECT().MachineConfigs( + c.clusterSpec).Return(c.machineConfigs), + + c.gitOpsManager.EXPECT().InstallGitOps( + c.ctx, c.workloadCluster, c.clusterSpec, c.datacenterConfig, c.machineConfigs), + ) +} + +func (c *createTestSetup) expectWriteClusterConfig() { + gomock.InOrder( + c.provider.EXPECT().DatacenterConfig( + c.clusterSpec).Return(c.datacenterConfig), + + c.provider.EXPECT().MachineConfigs( + c.clusterSpec).Return(c.machineConfigs), + + c.writer.EXPECT().Write( + "cluster-name-eks-a-cluster.yaml", gomock.Any(), gomock.Any()), + ) +} + +func (c *createTestSetup) expectDeleteBootstrap() { + c.bootstrapper.EXPECT().DeleteBootstrapCluster(c.ctx, c.bootstrapCluster, gomock.Any(), gomock.Any()) +} + +func (c *createTestSetup) run() error { + return c.workflow.Run(c.ctx, c.clusterSpec, c.validator) +} + +func (c *createTestSetup) expectPreflightValidationsToPass() { + c.validator.EXPECT().PreflightValidations(c.ctx) +} + +func (c *createTestSetup) expectInstallResourcesOnManagementTask() { + gomock.InOrder( + c.provider.EXPECT().PostWorkloadInit(c.ctx, c.workloadCluster, c.clusterSpec), + ) +} + +func (c *createTestSetup) expectMoveManagement() { + c.clusterManager.EXPECT().MoveCAPI( + c.ctx, c.bootstrapCluster, c.workloadCluster, c.workloadCluster.Name, c.clusterSpec, gomock.Any(), + ) +} + +func (c *createTestSetup) expectCreateWorkload() { + gomock.InOrder( + c.clusterCreator.EXPECT().Run( + c.ctx, c.clusterSpec, *c.bootstrapCluster), + + c.clusterManager.EXPECT().GetWorkloadCluster( + c.ctx, c.bootstrapCluster, c.clusterSpec, c.provider).Return(c.workloadCluster, nil), + + c.clusterManager.EXPECT().CreateEKSANamespace( + c.ctx, c.workloadCluster), + + c.clusterManager.EXPECT().InstallCAPI( + c.ctx, c.clusterSpec, c.workloadCluster, c.provider), + + c.provider.EXPECT().UpdateSecrets( + c.ctx, c.workloadCluster, c.clusterSpec), + ) +} + +func (c *createTestSetup) expectCuratedPackagesInstallation() { + c.packageInstaller.EXPECT().InstallCuratedPackages(c.ctx).Times(1) +} + +func TestCreateRunSuccess(t *testing.T) { + test := newCreateTest(t) + test.expectSetup() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectCreateWorkload() + test.expectInstallResourcesOnManagementTask() + test.expectMoveManagement() + test.expectInstallEksaComponentsWorkload(nil, nil, nil, nil, nil) + test.expectInstallEksaComponentsBootstrap() + test.expectInstallGitOpsManager() + test.expectWriteClusterConfig() + test.expectDeleteBootstrap() + test.expectPreflightValidationsToPass() + test.expectCuratedPackagesInstallation() + + err := test.run() + if err != nil { + t.Fatalf("Create.Run() err = %v, want err = nil", err) + } +} + +func TestCreateBootstrapOptsFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectPreflightValidationsToPass() + + err := errors.New("test") + + opts := []bootstrapper.BootstrapClusterOption{} + + gomock.InOrder( + c.provider.EXPECT().BootstrapClusterOpts( + c.clusterSpec).Return(opts, err), + ) + + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err = c.run() + if err == nil { + t.Fatalf("expected error from task") + } +} + +func TestCreateValidationsFailure(t *testing.T) { + c := newCreateTest(t) + err := errors.New("test") + + c.provider.EXPECT().SetupAndValidateCreateCluster(c.ctx, c.clusterSpec).Return(err) + c.provider.EXPECT().Name() + c.gitOpsManager.EXPECT().Validations(c.ctx, c.clusterSpec) + + c.validator.EXPECT().PreflightValidations(c.ctx) + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err = c.run() + if err == nil { + t.Fatalf("expected error from task") + } +} + +func TestCreateBootstrapFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectPreflightValidationsToPass() + + err := errors.New("test") + + opts := []bootstrapper.BootstrapClusterOption{} + + gomock.InOrder( + c.provider.EXPECT().BootstrapClusterOpts( + c.clusterSpec).Return(opts, nil), + c.bootstrapper.EXPECT().CreateBootstrapCluster( + c.ctx, c.clusterSpec, gomock.Not(gomock.Nil()), + ).Return(nil, err), + ) + + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err = c.run() + if err == nil { + t.Fatalf("expected error from task") + } +} + +func TestCreatePreCAPIFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectCreateBootstrap() + c.expectPreflightValidationsToPass() + + c.provider.EXPECT().PreCAPIInstallOnBootstrap( + c.ctx, c.bootstrapCluster, c.clusterSpec).Return(errors.New("test")) + + c.clusterManager.EXPECT().SaveLogsManagementCluster(c.ctx, c.clusterSpec, c.bootstrapCluster) + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err := c.run() + if err == nil { + t.Fatalf("Create.Run() expected to return an error %v", err) + } +} + +func TestCreateInstallCAPIFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectCreateBootstrap() + c.expectPreflightValidationsToPass() + + gomock.InOrder( + c.provider.EXPECT().PreCAPIInstallOnBootstrap( + c.ctx, c.bootstrapCluster, c.clusterSpec), + + c.clusterManager.EXPECT().InstallCAPI( + c.ctx, c.clusterSpec, c.bootstrapCluster, c.provider).Return(errors.New("test")), + ) + + c.clusterManager.EXPECT().SaveLogsManagementCluster(c.ctx, c.clusterSpec, c.bootstrapCluster) + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err := c.run() + if err == nil { + t.Fatalf("Create.Run() expected to return an error %v", err) + } +} + +func TestCreatePostCAPIFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectCreateBootstrap() + c.expectPreflightValidationsToPass() + + gomock.InOrder( + c.provider.EXPECT().PreCAPIInstallOnBootstrap( + c.ctx, c.bootstrapCluster, c.clusterSpec), + + c.clusterManager.EXPECT().InstallCAPI( + c.ctx, c.clusterSpec, c.bootstrapCluster, c.provider), + + c.provider.EXPECT().PostCAPIInstallSetup( + c.ctx, c.clusterSpec.Cluster, c.bootstrapCluster).Return(errors.New("test")), + ) + + c.clusterManager.EXPECT().SaveLogsManagementCluster(c.ctx, c.clusterSpec, c.bootstrapCluster) + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err := c.run() + if err == nil { + t.Fatalf("Create.Run() expected to return an error %v", err) + } +} + +func TestCreatePostWorkloadInitFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectCreateBootstrap() + c.expectPreflightValidationsToPass() + c.expectCAPIInstall() + c.expectInstallEksaComponentsBootstrap() + c.expectCreateWorkload() + + c.provider.EXPECT().PostWorkloadInit( + c.ctx, c.workloadCluster, c.clusterSpec).Return(errors.New("test")) + + c.clusterManager.EXPECT().SaveLogsManagementCluster(c.ctx, c.clusterSpec, c.bootstrapCluster) + c.clusterManager.EXPECT().SaveLogsWorkloadCluster(c.ctx, c.provider, c.clusterSpec, c.workloadCluster) + + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err := c.run() + if err == nil { + t.Fatalf("Create.Run() expected to return an error %v", err) + } +} + +func TestCreateInstallComponentsFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectCreateBootstrap() + c.expectPreflightValidationsToPass() + c.expectCAPIInstall() + + gomock.InOrder( + c.clusterManager.EXPECT().InstallCustomComponents( + c.ctx, c.clusterSpec, c.bootstrapCluster, c.provider), + + c.eksdInstaller.EXPECT().InstallEksdCRDs(c.ctx, c.clusterSpec, c.bootstrapCluster).Return(errors.New("test")), + ) + + c.clusterManager.EXPECT().SaveLogsManagementCluster(c.ctx, c.clusterSpec, c.bootstrapCluster) + c.clusterManager.EXPECT().SaveLogsWorkloadCluster(c.ctx, c.provider, c.clusterSpec, nil) + + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err := c.run() + if err == nil { + t.Fatalf("Create.Run() expected to return an error %v", err) + } +} + +func TestCreateEKSAReleaseBundleFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectCreateBootstrap() + c.expectPreflightValidationsToPass() + c.expectCAPIInstall() + + gomock.InOrder( + c.clusterManager.EXPECT().InstallCustomComponents( + c.ctx, c.clusterSpec, c.bootstrapCluster, c.provider), + + c.eksdInstaller.EXPECT().InstallEksdCRDs(c.ctx, c.clusterSpec, c.bootstrapCluster), + + c.clusterManager.EXPECT().CreateEKSAReleaseBundle( + c.ctx, c.bootstrapCluster, c.clusterSpec).Return(errors.New("test")), + ) + + c.clusterManager.EXPECT().SaveLogsManagementCluster(c.ctx, c.clusterSpec, c.bootstrapCluster) + c.clusterManager.EXPECT().SaveLogsWorkloadCluster(c.ctx, c.provider, c.clusterSpec, nil) + + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err := c.run() + if err == nil { + t.Fatalf("Create.Run() expected to return an error %v", err) + } +} + +func TestCreateInstallEksdManifestFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectCreateBootstrap() + c.expectPreflightValidationsToPass() + c.expectCAPIInstall() + + gomock.InOrder( + c.clusterManager.EXPECT().InstallCustomComponents( + c.ctx, c.clusterSpec, c.bootstrapCluster, c.provider), + + c.eksdInstaller.EXPECT().InstallEksdCRDs(c.ctx, c.clusterSpec, c.bootstrapCluster), + + c.clusterManager.EXPECT().CreateEKSAReleaseBundle( + c.ctx, c.bootstrapCluster, c.clusterSpec), + + c.eksdInstaller.EXPECT().InstallEksdManifest( + c.ctx, c.clusterSpec, c.bootstrapCluster).Return(errors.New("test")), + ) + + c.clusterManager.EXPECT().SaveLogsManagementCluster(c.ctx, c.clusterSpec, c.bootstrapCluster) + c.clusterManager.EXPECT().SaveLogsWorkloadCluster(c.ctx, c.provider, c.clusterSpec, nil) + + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err := c.run() + if err == nil { + t.Fatalf("Create.Run() expected to return an error %v", err) + } +} + +func TestCreateMoveCAPIFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectCreateBootstrap() + c.expectPreflightValidationsToPass() + c.expectCAPIInstall() + c.expectInstallEksaComponentsBootstrap() + c.expectCreateWorkload() + c.expectInstallResourcesOnManagementTask() + + c.clusterManager.EXPECT().MoveCAPI( + c.ctx, c.bootstrapCluster, c.workloadCluster, "workload", c.clusterSpec, gomock.Any()).Return(errors.New("test")) + + c.clusterManager.EXPECT().SaveLogsManagementCluster(c.ctx, c.clusterSpec, c.bootstrapCluster) + c.clusterManager.EXPECT().SaveLogsWorkloadCluster(c.ctx, c.provider, c.clusterSpec, c.workloadCluster) + + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + + err := c.run() + if err == nil { + t.Fatalf("Create.Run() expected to return an error %v", err) + } +} + +func TestCreateInstallEKSAWorkloadFailure(t *testing.T) { + test := newCreateTest(t) + test.expectSetup() + test.expectPreflightValidationsToPass() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectInstallEksaComponentsBootstrap() + test.expectCreateWorkload() + test.expectInstallResourcesOnManagementTask() + test.expectMoveManagement() + + test.clusterManager.EXPECT().InstallCustomComponents( + test.ctx, test.clusterSpec, test.workloadCluster, test.provider).Return(errors.New("test")) + + test.clusterManager.EXPECT().SaveLogsManagementCluster(test.ctx, test.clusterSpec, test.bootstrapCluster) + test.clusterManager.EXPECT().SaveLogsWorkloadCluster(test.ctx, test.provider, test.clusterSpec, test.workloadCluster) + + test.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", test.clusterSpec.Cluster.Name), gomock.Any()) + + err := test.run() + if err == nil { + t.Fatalf("Create.Run() error expected") + } +} + +func TestCreateInstallEKSACustomComponentsFailure(t *testing.T) { + c := newCreateTest(t) + c.expectSetup() + c.expectCreateBootstrap() + c.expectCAPIInstall() + + err := errors.New("test") + c.clusterManager.EXPECT().InstallCustomComponents( + c.ctx, c.clusterSpec, c.bootstrapCluster, c.provider).Return(err) + + c.clusterManager.EXPECT().SaveLogsManagementCluster( + c.ctx, c.clusterSpec, c.bootstrapCluster, + ) + c.clusterManager.EXPECT().SaveLogsWorkloadCluster( + c.ctx, c.provider, c.clusterSpec, nil, + ) + c.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", c.clusterSpec.Cluster.Name), gomock.Any()) + c.expectPreflightValidationsToPass() + + err = c.run() + if err == nil { + t.Fatalf("expected error from task") + } +} + +func TestCreateCreatorWorkloadFailure(t *testing.T) { + test := newCreateTest(t) + test.expectSetup() + test.expectPreflightValidationsToPass() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectInstallEksaComponentsBootstrap() + test.expectCreateWorkload() + test.expectInstallResourcesOnManagementTask() + test.expectMoveManagement() + + err := errors.New("test") + test.expectInstallEksaComponentsWorkload(nil, nil, nil, nil, err) + + test.clusterManager.EXPECT().SaveLogsManagementCluster(test.ctx, test.clusterSpec, test.bootstrapCluster) + test.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", test.clusterSpec.Cluster.Name), gomock.Any()) + + err = test.run() + if err == nil { + t.Fatalf("Create.Run() error expected") + } +} + +func TestCreateRunCreatorFailure(t *testing.T) { + test := newCreateTest(t) + test.expectSetup() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectInstallEksaComponentsBootstrap() + test.expectPreflightValidationsToPass() + + test.clusterCreator.EXPECT().Run( + test.ctx, test.clusterSpec, *test.bootstrapCluster).Return(errors.New("test")) + + test.clusterManager.EXPECT().SaveLogsManagementCluster(test.ctx, test.clusterSpec, test.bootstrapCluster) + test.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", test.clusterSpec.Cluster.Name), gomock.Any()) + + err := test.run() + if err == nil { + t.Fatalf("expected error from task") + } +} + +func TestCreateGetWorkloadClusterFailure(t *testing.T) { + test := newCreateTest(t) + test.expectSetup() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectInstallEksaComponentsBootstrap() + test.expectPreflightValidationsToPass() + + test.clusterCreator.EXPECT().Run( + test.ctx, test.clusterSpec, *test.bootstrapCluster) + + test.clusterManager.EXPECT().GetWorkloadCluster( + test.ctx, test.bootstrapCluster, test.clusterSpec, test.provider).Return(nil, errors.New("test")) + + test.clusterManager.EXPECT().SaveLogsManagementCluster(test.ctx, test.clusterSpec, test.bootstrapCluster) + test.clusterManager.EXPECT().SaveLogsWorkloadCluster(test.ctx, test.provider, test.clusterSpec, nil) + + test.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", test.clusterSpec.Cluster.Name), gomock.Any()) + + err := test.run() + if err == nil { + t.Fatalf("expected error from task") + } +} + +func TestCreateClusterCreateEKSANamespaceFailure(t *testing.T) { + test := newCreateTest(t) + test.expectSetup() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectInstallEksaComponentsBootstrap() + test.expectPreflightValidationsToPass() + + test.clusterCreator.EXPECT().Run( + test.ctx, test.clusterSpec, *test.bootstrapCluster) + + test.clusterManager.EXPECT().GetWorkloadCluster( + test.ctx, test.bootstrapCluster, test.clusterSpec, test.provider).Return(test.workloadCluster, nil) + + test.clusterManager.EXPECT().CreateEKSANamespace( + test.ctx, test.workloadCluster).Return(errors.New("test")) + + test.clusterManager.EXPECT().SaveLogsManagementCluster(test.ctx, test.clusterSpec, test.bootstrapCluster) + test.clusterManager.EXPECT().SaveLogsWorkloadCluster(test.ctx, test.provider, test.clusterSpec, test.workloadCluster) + + test.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", test.clusterSpec.Cluster.Name), gomock.Any()) + + err := test.run() + if err == nil { + t.Fatalf("expected error from task") + } +} + +func TestCreateInstallCAPIWorkloadFailure(t *testing.T) { + test := newCreateTest(t) + test.expectSetup() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectInstallEksaComponentsBootstrap() + test.expectPreflightValidationsToPass() + + test.clusterCreator.EXPECT().Run( + test.ctx, test.clusterSpec, *test.bootstrapCluster) + + test.clusterManager.EXPECT().GetWorkloadCluster( + test.ctx, test.bootstrapCluster, test.clusterSpec, test.provider).Return(test.workloadCluster, nil) + + test.clusterManager.EXPECT().CreateEKSANamespace( + test.ctx, test.workloadCluster) + + test.clusterManager.EXPECT().InstallCAPI( + test.ctx, test.clusterSpec, test.workloadCluster, test.provider).Return(errors.New("test")) + + test.clusterManager.EXPECT().SaveLogsManagementCluster(test.ctx, test.clusterSpec, test.bootstrapCluster) + test.clusterManager.EXPECT().SaveLogsWorkloadCluster(test.ctx, test.provider, test.clusterSpec, test.workloadCluster) + + test.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", test.clusterSpec.Cluster.Name), gomock.Any()) + + err := test.run() + if err == nil { + t.Fatalf("expected error from task") + } +} + +func TestCreateUpdateSecretsFailure(t *testing.T) { + test := newCreateTest(t) + test.expectSetup() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectInstallEksaComponentsBootstrap() + test.expectPreflightValidationsToPass() + + test.clusterCreator.EXPECT().Run( + test.ctx, test.clusterSpec, *test.bootstrapCluster) + + test.clusterManager.EXPECT().GetWorkloadCluster( + test.ctx, test.bootstrapCluster, test.clusterSpec, test.provider).Return(test.workloadCluster, nil) + + test.clusterManager.EXPECT().CreateEKSANamespace( + test.ctx, test.workloadCluster) + + test.clusterManager.EXPECT().InstallCAPI( + test.ctx, test.clusterSpec, test.workloadCluster, test.provider) + + test.provider.EXPECT().UpdateSecrets( + test.ctx, test.workloadCluster, test.clusterSpec).Return(errors.New("test")) + + test.clusterManager.EXPECT().SaveLogsManagementCluster(test.ctx, test.clusterSpec, test.bootstrapCluster) + test.clusterManager.EXPECT().SaveLogsWorkloadCluster(test.ctx, test.provider, test.clusterSpec, test.workloadCluster) + + test.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", test.clusterSpec.Cluster.Name), gomock.Any()) + + err := test.run() + if err == nil { + t.Fatalf("expected error from task") + } +} + +func TestCreateGitOPsFailure(t *testing.T) { + test := newCreateTest(t) + test.expectSetup() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectCreateWorkload() + test.expectInstallResourcesOnManagementTask() + test.expectMoveManagement() + test.expectInstallEksaComponentsWorkload(nil, nil, nil, nil, nil) + test.expectInstallEksaComponentsBootstrap() + test.expectPreflightValidationsToPass() + + gomock.InOrder( + test.provider.EXPECT().DatacenterConfig( + test.clusterSpec).Return(test.datacenterConfig), + + test.provider.EXPECT().MachineConfigs( + test.clusterSpec).Return(test.machineConfigs), + + test.gitOpsManager.EXPECT().InstallGitOps( + test.ctx, test.workloadCluster, test.clusterSpec, test.datacenterConfig, test.machineConfigs).Return(errors.New("test")), + ) + test.expectWriteClusterConfig() + test.expectCuratedPackagesInstallation() + test.expectDeleteBootstrap() + + err := test.run() + if err != nil { + t.Fatalf("Create.Run() err = %v, want err = nil", err) + } +} + +func TestCreateRunAWSIAMSuccess(t *testing.T) { + test := newCreateTest(t) + test.clusterSpec.AWSIamConfig = &v1alpha1.AWSIamConfig{} + + test.expectSetup() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectCreateWorkload() + test.expectInstallResourcesOnManagementTask() + test.expectMoveManagement() + test.expectInstallEksaComponentsWorkload(nil, nil, nil, nil, nil) + test.expectInstallEksaComponentsBootstrap() + test.expectInstallGitOpsManager() + test.expectWriteClusterConfig() + test.expectDeleteBootstrap() + test.expectPreflightValidationsToPass() + test.expectCuratedPackagesInstallation() + + err := test.run() + if err != nil { + t.Fatalf("Create.Run() err = %v, want err = nil", err) + } +} + +func TestCreateWriteConfigFailure(t *testing.T) { + test := newCreateTest(t) + + test.expectSetup() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectCreateWorkload() + test.expectInstallResourcesOnManagementTask() + test.expectMoveManagement() + test.expectInstallEksaComponentsWorkload(nil, nil, nil, nil, nil) + test.expectInstallEksaComponentsBootstrap() + test.expectInstallGitOpsManager() + test.expectPreflightValidationsToPass() + + gomock.InOrder( + test.provider.EXPECT().DatacenterConfig( + test.clusterSpec).Return(test.datacenterConfig), + + test.provider.EXPECT().MachineConfigs( + test.clusterSpec).Return(test.machineConfigs), + + test.writer.EXPECT().Write( + "cluster-name-eks-a-cluster.yaml", gomock.Any(), gomock.Any()).Return("", errors.New("test")), + ) + + test.clusterManager.EXPECT().SaveLogsManagementCluster( + test.ctx, test.clusterSpec, test.bootstrapCluster, + ) + test.clusterManager.EXPECT().SaveLogsWorkloadCluster( + test.ctx, test.provider, test.clusterSpec, test.workloadCluster, + ) + test.writer.EXPECT().Write(fmt.Sprintf("%s-checkpoint.yaml", test.clusterSpec.Cluster.Name), gomock.Any()) + + err := test.run() + if err == nil { + t.Fatalf("Create.Run() err = %v, want err = nil", err) + } +} + +func TestCreateRunDeleteBootstrapFailure(t *testing.T) { + test := newCreateTest(t) + test.expectSetup() + test.expectCreateBootstrap() + test.expectCAPIInstall() + test.expectCreateWorkload() + test.expectInstallResourcesOnManagementTask() + test.expectMoveManagement() + test.expectInstallEksaComponentsWorkload(nil, nil, nil, nil, nil) + test.expectInstallEksaComponentsBootstrap() + test.expectInstallGitOpsManager() + test.expectPreflightValidationsToPass() + test.expectCuratedPackagesInstallation() + + gomock.InOrder( + test.provider.EXPECT().DatacenterConfig( + test.clusterSpec).Return(test.datacenterConfig), + + test.provider.EXPECT().MachineConfigs( + test.clusterSpec).Return(test.machineConfigs), + + test.writer.EXPECT().Write( + "cluster-name-eks-a-cluster.yaml", gomock.Any(), gomock.Any()), + + test.writer.EXPECT().Write( + "cluster-name-checkpoint.yaml", gomock.Any(), gomock.Any()), + ) + test.bootstrapper.EXPECT().DeleteBootstrapCluster(test.ctx, test.bootstrapCluster, gomock.Any(), gomock.Any()).Return(errors.New("test")) + + err := test.run() + if err == nil { + t.Fatalf("Create.Run() err = %v, want err = nil", err) + } +} diff --git a/pkg/workflows/management/delete_bootstrap.go b/pkg/workflows/management/delete_bootstrap.go new file mode 100644 index 0000000000000..dad43c82d113a --- /dev/null +++ b/pkg/workflows/management/delete_bootstrap.go @@ -0,0 +1,35 @@ +package management + +import ( + "context" + + "github.com/aws/eks-anywhere/pkg/constants" + "github.com/aws/eks-anywhere/pkg/logger" + "github.com/aws/eks-anywhere/pkg/task" +) + +type deleteBootstrapClusterTask struct{} + +func (s *deleteBootstrapClusterTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Deleting bootstrap cluster") + err := commandContext.Bootstrapper.DeleteBootstrapCluster(ctx, commandContext.BootstrapCluster, constants.Create, false) + if err != nil { + commandContext.SetError(err) + } + if commandContext.OriginalError == nil { + logger.MarkSuccess("Cluster created!") + } + return &installCuratedPackagesTask{} +} + +func (s *deleteBootstrapClusterTask) Name() string { + return "delete-kind-cluster" +} + +func (s *deleteBootstrapClusterTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *deleteBootstrapClusterTask) Checkpoint() *task.CompletedTask { + return nil +} diff --git a/pkg/workflows/management/install_curated_packages.go b/pkg/workflows/management/install_curated_packages.go new file mode 100644 index 0000000000000..a3c9d407a23b7 --- /dev/null +++ b/pkg/workflows/management/install_curated_packages.go @@ -0,0 +1,26 @@ +package management + +import ( + "context" + + "github.com/aws/eks-anywhere/pkg/task" +) + +type installCuratedPackagesTask struct{} + +func (s *installCuratedPackagesTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + commandContext.PackageInstaller.InstallCuratedPackages(ctx) + return nil +} + +func (s *installCuratedPackagesTask) Name() string { + return "install-curated-packages" +} + +func (s *installCuratedPackagesTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *installCuratedPackagesTask) Checkpoint() *task.CompletedTask { + return nil +} diff --git a/pkg/workflows/management/upgrade.go b/pkg/workflows/management/upgrade.go index be9bc38a940de..35d5c8425e861 100644 --- a/pkg/workflows/management/upgrade.go +++ b/pkg/workflows/management/upgrade.go @@ -66,8 +66,8 @@ func (c *Upgrade) Run(ctx context.Context, clusterSpec *cluster.Spec, management ClusterUpgrader: c.clusterUpgrader, } if features.IsActive(features.CheckpointEnabled()) { - return task.NewTaskRunner(&setupAndValidate{}, c.writer, task.WithCheckpointFile()).RunTask(ctx, commandContext) + return task.NewTaskRunner(&setupAndValidateUpgrade{}, c.writer, task.WithCheckpointFile()).RunTask(ctx, commandContext) } - return task.NewTaskRunner(&setupAndValidate{}, c.writer).RunTask(ctx, commandContext) + return task.NewTaskRunner(&setupAndValidateUpgrade{}, c.writer).RunTask(ctx, commandContext) } diff --git a/pkg/workflows/management/upgrade_management_components_test.go b/pkg/workflows/management/upgrade_management_components_test.go index 09c07265c7c2f..ec543023fc9b1 100644 --- a/pkg/workflows/management/upgrade_management_components_test.go +++ b/pkg/workflows/management/upgrade_management_components_test.go @@ -82,8 +82,8 @@ func TestRunnerHappyPath(t *testing.T) { clusterSpec := test.NewClusterSpec() managementCluster := &types.Cluster{ - Name: clusterSpec.Cluster.Name, - KubeconfigFile: kubeconfig.FromClusterName(clusterSpec.Cluster.Name), + Name: clusterSpec.Cluster.Name, + KubeconfigFile: kubeconfig.FromClusterName(clusterSpec.Cluster.Name), } ctx := context.Background() @@ -132,8 +132,8 @@ func TestRunnerStopsWhenValidationFailed(t *testing.T) { clusterSpec := test.NewClusterSpec() managementCluster := &types.Cluster{ - Name: clusterSpec.Cluster.Name, - KubeconfigFile: kubeconfig.FromClusterName(clusterSpec.Cluster.Name), + Name: clusterSpec.Cluster.Name, + KubeconfigFile: kubeconfig.FromClusterName(clusterSpec.Cluster.Name), } ctx := context.Background() diff --git a/pkg/workflows/management/validate.go b/pkg/workflows/management/validate.go index 3a7f6e0be2759..870f1d5edfcd8 100644 --- a/pkg/workflows/management/validate.go +++ b/pkg/workflows/management/validate.go @@ -9,10 +9,10 @@ import ( "github.com/aws/eks-anywhere/pkg/validations" ) -type setupAndValidate struct{} +type setupAndValidateUpgrade struct{} // Run setupAndValidate validates management cluster before upgrade process starts. -func (s *setupAndValidate) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { +func (s *setupAndValidateUpgrade) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { logger.Info("Performing setup and validations") currentSpec, err := commandContext.ClusterManager.GetCurrentClusterSpec(ctx, commandContext.ManagementCluster, commandContext.ClusterSpec.Cluster.Name) if err != nil { @@ -33,7 +33,7 @@ func (s *setupAndValidate) Run(ctx context.Context, commandContext *task.Command return &updateSecrets{} } -func (s *setupAndValidate) providerValidation(ctx context.Context, commandContext *task.CommandContext) []validations.Validation { +func (s *setupAndValidateUpgrade) providerValidation(ctx context.Context, commandContext *task.CommandContext) []validations.Validation { return []validations.Validation{ func() *validations.ValidationResult { return &validations.ValidationResult{ @@ -44,11 +44,11 @@ func (s *setupAndValidate) providerValidation(ctx context.Context, commandContex } } -func (s *setupAndValidate) Name() string { +func (s *setupAndValidateUpgrade) Name() string { return "setup-and-validate" } -func (s *setupAndValidate) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { +func (s *setupAndValidateUpgrade) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { if err := commandContext.Provider.SetupAndValidateUpgradeCluster(ctx, commandContext.ManagementCluster, commandContext.ClusterSpec, commandContext.CurrentClusterSpec); err != nil { commandContext.SetError(err) return nil, err @@ -63,8 +63,50 @@ func (s *setupAndValidate) Restore(ctx context.Context, commandContext *task.Com return &updateSecrets{}, nil } -func (s *setupAndValidate) Checkpoint() *task.CompletedTask { +func (s *setupAndValidateUpgrade) Checkpoint() *task.CompletedTask { return &task.CompletedTask{ Checkpoint: nil, } } + +type setupAndValidateCreate struct{} + +// setupAndValidateCreate implementation + +func (s *setupAndValidateCreate) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Performing setup and validations") + runner := validations.NewRunner() + runner.Register(s.providerValidation(ctx, commandContext)...) + runner.Register(commandContext.GitOpsManager.Validations(ctx, commandContext.ClusterSpec)...) + runner.Register(commandContext.Validations.PreflightValidations(ctx)...) + + err := runner.Run() + if err != nil { + commandContext.SetError(err) + return nil + } + return &createBootStrapClusterTask{} +} + +func (s *setupAndValidateCreate) providerValidation(ctx context.Context, commandContext *task.CommandContext) []validations.Validation { + return []validations.Validation{ + func() *validations.ValidationResult { + return &validations.ValidationResult{ + Name: fmt.Sprintf("%s Provider setup is valid", commandContext.Provider.Name()), + Err: commandContext.Provider.SetupAndValidateCreateCluster(ctx, commandContext.ClusterSpec), + } + }, + } +} + +func (s *setupAndValidateCreate) Name() string { + return "setup-validate" +} + +func (s *setupAndValidateCreate) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *setupAndValidateCreate) Checkpoint() *task.CompletedTask { + return nil +} diff --git a/pkg/workflows/management/write_cluster_config.go b/pkg/workflows/management/write_cluster_config.go index 5873b6597a454..f7d2b7a515f9c 100644 --- a/pkg/workflows/management/write_cluster_config.go +++ b/pkg/workflows/management/write_cluster_config.go @@ -6,6 +6,7 @@ import ( "github.com/aws/eks-anywhere/pkg/clustermarshaller" "github.com/aws/eks-anywhere/pkg/logger" "github.com/aws/eks-anywhere/pkg/task" + "github.com/aws/eks-anywhere/pkg/workflows" ) type writeClusterConfig struct{} @@ -37,3 +38,27 @@ func (s *writeClusterConfig) Checkpoint() *task.CompletedTask { func (s *writeClusterConfig) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { return &postClusterUpgrade{}, nil } + +type writeClusterConfigTask struct{} + +func (s *writeClusterConfigTask) Run(ctx context.Context, commandContext *task.CommandContext) task.Task { + logger.Info("Writing cluster config file") + err := clustermarshaller.WriteClusterConfig(commandContext.ClusterSpec, commandContext.Provider.DatacenterConfig(commandContext.ClusterSpec), commandContext.Provider.MachineConfigs(commandContext.ClusterSpec), commandContext.Writer) + if err != nil { + commandContext.SetError(err) + return &workflows.CollectDiagnosticsTask{} + } + return &deleteBootstrapClusterTask{} +} + +func (s *writeClusterConfigTask) Name() string { + return "write-cluster-config" +} + +func (s *writeClusterConfigTask) Restore(ctx context.Context, commandContext *task.CommandContext, completedTask *task.CompletedTask) (task.Task, error) { + return nil, nil +} + +func (s *writeClusterConfigTask) Checkpoint() *task.CompletedTask { + return nil +} diff --git a/pkg/workflows/testdata/cluster-name-checkpoint.yaml b/pkg/workflows/testdata/cluster-name-checkpoint.yaml index 8ce11c47f5df2..e36e9ddf9be53 100644 --- a/pkg/workflows/testdata/cluster-name-checkpoint.yaml +++ b/pkg/workflows/testdata/cluster-name-checkpoint.yaml @@ -1,7 +1,6 @@ completedTasks: bootstrap-cluster-init: checkpoint: - ExistingManagement: false KubeconfigFile: kubeconfig.yaml Name: bootstrap capi-management-move-to-bootstrap: