From 2aef03b106ff0285d052652e8df120d190fb0eeb Mon Sep 17 00:00:00 2001 From: Tanvir Tatla Date: Mon, 1 Apr 2024 12:04:31 -0700 Subject: [PATCH] update tests and mocks --- pkg/clustermanager/cluster_manager.go | 68 ++++++++++++++++++ pkg/clustermanager/cluster_manager_test.go | 82 +++++++++++++++++----- pkg/workflows/interfaces/interfaces.go | 2 + pkg/workflows/interfaces/mocks/clients.go | 28 ++++++++ 4 files changed, 163 insertions(+), 17 deletions(-) diff --git a/pkg/clustermanager/cluster_manager.go b/pkg/clustermanager/cluster_manager.go index 84c69ac1271f..a0ec614c7b5d 100644 --- a/pkg/clustermanager/cluster_manager.go +++ b/pkg/clustermanager/cluster_manager.go @@ -674,6 +674,73 @@ func (c *ClusterManager) PauseCAPIWorkloadClusters(ctx context.Context, manageme return nil } +func (c *ClusterManager) resumeEksaReconcileForManagementAndWorkloadClusters(ctx context.Context, managementCluster *types.Cluster, clusterSpec *cluster.Spec, provider providers.Provider) error { + clusters := &v1alpha1.ClusterList{} + err := c.clusterClient.ListObjects(ctx, eksaClusterResourceType, clusterSpec.Cluster.Namespace, managementCluster.KubeconfigFile, clusters) + if err != nil { + return err + } + + for _, w := range clusters.Items { + if w.ManagedBy() != clusterSpec.Cluster.Name { + continue + } + + if err := c.resumeReconcileForCluster(ctx, managementCluster, &w, provider); err != nil { + return err + } + } + + return nil +} + +// ResumeEKSAControllerReconcile resumes a paused EKS-Anywhere cluster. +func (c *ClusterManager) ResumeEKSAControllerReconcile(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec, provider providers.Provider) error { + // clear pause annotation + clusterSpec.Cluster.ClearPauseAnnotation() + provider.DatacenterConfig(clusterSpec).ClearPauseAnnotation() + + if clusterSpec.Cluster.IsSelfManaged() { + return c.resumeEksaReconcileForManagementAndWorkloadClusters(ctx, cluster, clusterSpec, provider) + } + + return c.resumeReconcileForCluster(ctx, cluster, clusterSpec.Cluster, provider) +} + +func (c *ClusterManager) resumeReconcileForCluster(ctx context.Context, clusterCreds *types.Cluster, cluster *v1alpha1.Cluster, provider providers.Provider) error { + pausedAnnotation := cluster.PausedAnnotation() + err := c.clusterClient.RemoveAnnotationInNamespace(ctx, provider.DatacenterResourceType(), cluster.Spec.DatacenterRef.Name, pausedAnnotation, clusterCreds, cluster.Namespace) + if err != nil { + return fmt.Errorf("removing paused annotation when resuming datacenterconfig reconciliation: %v", err) + } + + if provider.MachineResourceType() != "" { + for _, machineConfigRef := range cluster.MachineConfigRefs() { + err = c.clusterClient.RemoveAnnotationInNamespace(ctx, provider.MachineResourceType(), machineConfigRef.Name, pausedAnnotation, clusterCreds, cluster.Namespace) + if err != nil { + return fmt.Errorf("removing paused annotation when resuming reconciliation for machine config %s: %v", machineConfigRef.Name, err) + } + } + } + + err = c.clusterClient.RemoveAnnotationInNamespace(ctx, cluster.ResourceType(), cluster.Name, pausedAnnotation, clusterCreds, cluster.Namespace) + if err != nil { + return fmt.Errorf("removing paused annotation when resuming cluster reconciliation: %v", err) + } + + if err = c.clusterClient.RemoveAnnotationInNamespace(ctx, + cluster.ResourceType(), + cluster.Name, + v1alpha1.ManagedByCLIAnnotation, + clusterCreds, + cluster.Namespace, + ); err != nil { + return fmt.Errorf("removing managed by CLI annotation when resuming cluster reconciliation: %v", err) + } + + return nil +} + // ResumeCAPIWorkloadClusters resumes all workload CAPI clusters except the management cluster. func (c *ClusterManager) ResumeCAPIWorkloadClusters(ctx context.Context, managementCluster *types.Cluster) error { clusters, err := c.clusterClient.GetClusters(ctx, managementCluster) @@ -693,6 +760,7 @@ func (c *ClusterManager) ResumeCAPIWorkloadClusters(ctx context.Context, managem return nil } +// AllowDeleteWhilePaused allows the deletion of paused clusters. func (c *ClusterManager) AllowDeleteWhilePaused(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec) error { return c.allowDeleteWhilePaused(ctx, cluster, clusterSpec.Cluster) } diff --git a/pkg/clustermanager/cluster_manager_test.go b/pkg/clustermanager/cluster_manager_test.go index 476cfca75239..97a0954acd1f 100644 --- a/pkg/clustermanager/cluster_manager_test.go +++ b/pkg/clustermanager/cluster_manager_test.go @@ -771,7 +771,7 @@ func TestPauseEKSAControllerReconcileWorkloadCluster(t *testing.T) { tt.Expect(tt.clusterManager.PauseEKSAControllerReconcile(tt.ctx, tt.cluster, tt.clusterSpec, tt.mocks.provider)).To(Succeed()) } -func TestPauseEKSAControllerReconcileWorkloadClusterUpdateAnnotationError(t *testing.T) { +func TestResumeEKSAControllerReconcileWorkloadClusterUpdateAnnotationError(t *testing.T) { tt := newTest(t, clustermanager.WithRetrier(retrier.NewWithMaxRetries(1, 0))) tt.clusterSpec.Cluster = &v1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{ @@ -788,15 +788,26 @@ func TestPauseEKSAControllerReconcileWorkloadClusterUpdateAnnotationError(t *tes }, } + datacenterConfig := &v1alpha1.VSphereDatacenterConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: tt.clusterName, + }, + Spec: v1alpha1.VSphereDatacenterConfigSpec{ + Insecure: true, + }, + } + pauseAnnotation := "anywhere.eks.amazonaws.com/paused" + tt.mocks.provider.EXPECT().DatacenterResourceType().Return(eksaVSphereDatacenterResourceType) tt.mocks.provider.EXPECT().MachineResourceType().Return("") - tt.mocks.client.EXPECT().UpdateAnnotationInNamespace(tt.ctx, eksaVSphereDatacenterResourceType, tt.clusterSpec.Cluster.Spec.DatacenterRef.Name, expectedPauseAnnotation, tt.cluster, "").Return(nil) - tt.mocks.client.EXPECT().UpdateAnnotationInNamespace(tt.ctx, eksaClusterResourceType, tt.clusterSpec.Cluster.Name, expectedPauseAnnotation, tt.cluster, "").Return(errors.New("pause eksa cluster error")) + tt.mocks.provider.EXPECT().DatacenterConfig(tt.clusterSpec).Return(datacenterConfig) + tt.mocks.client.EXPECT().RemoveAnnotationInNamespace(tt.ctx, eksaVSphereDatacenterResourceType, tt.clusterSpec.Cluster.Spec.DatacenterRef.Name, pauseAnnotation, tt.cluster, "").Return(nil) + tt.mocks.client.EXPECT().RemoveAnnotationInNamespace(tt.ctx, eksaClusterResourceType, tt.clusterSpec.Cluster.Name, pauseAnnotation, tt.cluster, "").Return(errors.New("pause eksa cluster error")) - tt.Expect(tt.clusterManager.PauseEKSAControllerReconcile(tt.ctx, tt.cluster, tt.clusterSpec, tt.mocks.provider)).NotTo(Succeed()) + tt.Expect(tt.clusterManager.ResumeEKSAControllerReconcile(tt.ctx, tt.cluster, tt.clusterSpec, tt.mocks.provider)).NotTo(Succeed()) } -func TestPauseEKSAControllerReconcileManagementCluster(t *testing.T) { +func TestResumeEKSAControllerReconcileManagementCluster(t *testing.T) { tt := newTest(t) tt.clusterSpec.Cluster = &v1alpha1.Cluster{ ObjectMeta: metav1.ObjectMeta{ @@ -813,6 +824,18 @@ func TestPauseEKSAControllerReconcileManagementCluster(t *testing.T) { }, } + tt.clusterSpec.Cluster.PauseReconcile() + + datacenterConfig := &v1alpha1.VSphereDatacenterConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: tt.clusterName, + }, + Spec: v1alpha1.VSphereDatacenterConfigSpec{ + Insecure: true, + }, + } + pauseAnnotation := "anywhere.eks.amazonaws.com/paused" + tt.mocks.client.EXPECT(). ListObjects(tt.ctx, eksaClusterResourceType, "", "", &v1alpha1.ClusterList{}). DoAndReturn(func(_ context.Context, _, _, _ string, obj *v1alpha1.ClusterList) error { @@ -851,31 +874,28 @@ func TestPauseEKSAControllerReconcileManagementCluster(t *testing.T) { }) tt.mocks.provider.EXPECT().DatacenterResourceType().Return(eksaVSphereDatacenterResourceType).Times(2) tt.mocks.provider.EXPECT().MachineResourceType().Return("").Times(2) - tt.mocks.client.EXPECT().UpdateAnnotationInNamespace(tt.ctx, eksaVSphereDatacenterResourceType, tt.clusterSpec.Cluster.Spec.DatacenterRef.Name, expectedPauseAnnotation, tt.cluster, "").Return(nil).Times(2) - tt.mocks.client.EXPECT().UpdateAnnotationInNamespace(tt.ctx, eksaClusterResourceType, tt.clusterSpec.Cluster.Name, expectedPauseAnnotation, tt.cluster, "").Return(nil) - tt.mocks.client.EXPECT().UpdateAnnotationInNamespace( + tt.mocks.provider.EXPECT().DatacenterConfig(tt.clusterSpec).Return(datacenterConfig) + tt.mocks.client.EXPECT().RemoveAnnotationInNamespace(tt.ctx, eksaVSphereDatacenterResourceType, tt.clusterSpec.Cluster.Spec.DatacenterRef.Name, pauseAnnotation, tt.cluster, "").Return(nil).Times(2) + tt.mocks.client.EXPECT().RemoveAnnotationInNamespace(tt.ctx, eksaClusterResourceType, tt.clusterSpec.Cluster.Name, pauseAnnotation, tt.cluster, "").Return(nil) + tt.mocks.client.EXPECT().RemoveAnnotationInNamespace( tt.ctx, eksaClusterResourceType, tt.clusterSpec.Cluster.Name, - map[string]string{ - v1alpha1.ManagedByCLIAnnotation: "true", - }, + v1alpha1.ManagedByCLIAnnotation, tt.cluster, "", ).Return(nil) - tt.mocks.client.EXPECT().UpdateAnnotationInNamespace(tt.ctx, eksaClusterResourceType, "workload-cluster-1", expectedPauseAnnotation, tt.cluster, "").Return(nil) - tt.mocks.client.EXPECT().UpdateAnnotationInNamespace( + tt.mocks.client.EXPECT().RemoveAnnotationInNamespace(tt.ctx, eksaClusterResourceType, "workload-cluster-1", pauseAnnotation, tt.cluster, "").Return(nil) + tt.mocks.client.EXPECT().RemoveAnnotationInNamespace( tt.ctx, eksaClusterResourceType, "workload-cluster-1", - map[string]string{ - v1alpha1.ManagedByCLIAnnotation: "true", - }, + v1alpha1.ManagedByCLIAnnotation, tt.cluster, "", ).Return(nil) - tt.Expect(tt.clusterManager.PauseEKSAControllerReconcile(tt.ctx, tt.cluster, tt.clusterSpec, tt.mocks.provider)).To(Succeed()) + tt.Expect(tt.clusterManager.ResumeEKSAControllerReconcile(tt.ctx, tt.cluster, tt.clusterSpec, tt.mocks.provider)).To(Succeed()) } func TestPauseEKSAControllerReconcileManagementClusterListObjectsError(t *testing.T) { @@ -1084,3 +1104,31 @@ func TestCreateRegistryCredSecretSuccess(t *testing.T) { err := tt.clusterManager.CreateRegistryCredSecret(tt.ctx, tt.cluster) tt.Expect(err).To(BeNil()) } + +func TestAllowDeleteWhilePaused(t *testing.T) { + tests := []struct { + name string + err error + }{ + { + name: "success allow delete while paused", + err: nil, + }, + { + name: "fail allow delete while paused", + err: fmt.Errorf("failure"), + }, + } + allowDelete := map[string]string{v1alpha1.AllowDeleteWhenPausedAnnotation: "true"} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + tt := newTest(t) + cluster := tt.clusterSpec.Cluster + tt.mocks.client.EXPECT().UpdateAnnotationInNamespace(tt.ctx, cluster.ResourceType(), cluster.Name, allowDelete, tt.cluster, cluster.Namespace).Return(test.err) + err := tt.clusterManager.AllowDeleteWhilePaused(tt.ctx, tt.cluster, tt.clusterSpec) + expectedErr := fmt.Errorf("updating paused annotation in cluster reconciliation: %v", test.err) + tt.Expect(err).To(Or(BeNil(), MatchError(expectedErr))) + }) + } +} diff --git a/pkg/workflows/interfaces/interfaces.go b/pkg/workflows/interfaces/interfaces.go index 7b31d1bfb947..37b2d0e01c9a 100644 --- a/pkg/workflows/interfaces/interfaces.go +++ b/pkg/workflows/interfaces/interfaces.go @@ -42,6 +42,8 @@ type ClusterManager interface { Upgrade(ctx context.Context, cluster *types.Cluster, currentManagementComponents, newManagementComponents *cluster.ManagementComponents, newSpec *cluster.Spec) (*types.ChangeDiff, error) CreateRegistryCredSecret(ctx context.Context, mgmt *types.Cluster) error GenerateAWSIAMKubeconfig(ctx context.Context, cluster *types.Cluster) error + ResumeEKSAControllerReconcile(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec, provider providers.Provider) error + AllowDeleteWhilePaused(ctx context.Context, cluster *types.Cluster, clusterSpec *cluster.Spec) error } type GitOpsManager interface { diff --git a/pkg/workflows/interfaces/mocks/clients.go b/pkg/workflows/interfaces/mocks/clients.go index 07e0e277411d..1e534ea03926 100644 --- a/pkg/workflows/interfaces/mocks/clients.go +++ b/pkg/workflows/interfaces/mocks/clients.go @@ -99,6 +99,20 @@ func (m *MockClusterManager) EXPECT() *MockClusterManagerMockRecorder { return m.recorder } +// AllowDeleteWhilePaused mocks base method. +func (m *MockClusterManager) AllowDeleteWhilePaused(arg0 context.Context, arg1 *types.Cluster, arg2 *cluster.Spec) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AllowDeleteWhilePaused", arg0, arg1, arg2) + ret0, _ := ret[0].(error) + return ret0 +} + +// AllowDeleteWhilePaused indicates an expected call of AllowDeleteWhilePaused. +func (mr *MockClusterManagerMockRecorder) AllowDeleteWhilePaused(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllowDeleteWhilePaused", reflect.TypeOf((*MockClusterManager)(nil).AllowDeleteWhilePaused), arg0, arg1, arg2) +} + // ApplyBundles mocks base method. func (m *MockClusterManager) ApplyBundles(arg0 context.Context, arg1 *cluster.Spec, arg2 *types.Cluster) error { m.ctrl.T.Helper() @@ -287,6 +301,20 @@ func (mr *MockClusterManagerMockRecorder) ResumeCAPIWorkloadClusters(arg0, arg1 return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResumeCAPIWorkloadClusters", reflect.TypeOf((*MockClusterManager)(nil).ResumeCAPIWorkloadClusters), arg0, arg1) } +// ResumeEKSAControllerReconcile mocks base method. +func (m *MockClusterManager) ResumeEKSAControllerReconcile(arg0 context.Context, arg1 *types.Cluster, arg2 *cluster.Spec, arg3 providers.Provider) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ResumeEKSAControllerReconcile", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(error) + return ret0 +} + +// ResumeEKSAControllerReconcile indicates an expected call of ResumeEKSAControllerReconcile. +func (mr *MockClusterManagerMockRecorder) ResumeEKSAControllerReconcile(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResumeEKSAControllerReconcile", reflect.TypeOf((*MockClusterManager)(nil).ResumeEKSAControllerReconcile), arg0, arg1, arg2, arg3) +} + // SaveLogsManagementCluster mocks base method. func (m *MockClusterManager) SaveLogsManagementCluster(arg0 context.Context, arg1 *cluster.Spec, arg2 *types.Cluster) error { m.ctrl.T.Helper()