diff --git a/multicluster/apis/multicluster/constants/constants.go b/multicluster/apis/multicluster/constants/constants.go index d1fb88d92d9..72c097d6404 100644 --- a/multicluster/apis/multicluster/constants/constants.go +++ b/multicluster/apis/multicluster/constants/constants.go @@ -24,7 +24,8 @@ const ( ServiceImportKind = "ServiceImport" ClusterInfoKind = "ClusterInfo" - ResourceExportFinalizer = "resourceexport.finalizers.antrea.io" + LegacyResourceExportFinalizer = "resourceexport.finalizers.antrea.io" + ResourceExportFinalizer = "resourceexport.antrea.io/finalizer" // ResourceExport labels. SourceName = "sourceName" diff --git a/multicluster/apis/multicluster/v1alpha1/resourceexport_webhook.go b/multicluster/apis/multicluster/v1alpha1/resourceexport_webhook.go index f9f252fa13e..dbcec874b45 100644 --- a/multicluster/apis/multicluster/v1alpha1/resourceexport_webhook.go +++ b/multicluster/apis/multicluster/v1alpha1/resourceexport_webhook.go @@ -17,6 +17,8 @@ limitations under the License. package v1alpha1 import ( + "slices" + "k8s.io/klog/v2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/webhook" @@ -53,16 +55,12 @@ func (r *ResourceExport) Default() { if kindLabelVal, exists := r.Labels[constants.SourceKind]; !exists || kindLabelVal != constants.AntreaClusterNetworkPolicyKind { r.Labels[constants.SourceKind] = constants.AntreaClusterNetworkPolicyKind } - if r.DeletionTimestamp.IsZero() && !stringExistsInSlice(r.Finalizers, constants.ResourceExportFinalizer) { + // Add domain qualified finalizer for ResourceExports to avoid Kubernetes from reporting errors: + // "prefer a domain-qualified finalizer name to avoid accidental conflicts with other finalizer writers" + // https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#finalizers + // Note for ResourceExports created before Antrea v2.2, LegacyResourceExportFinalizer may still be present + // and needs to be removed before a ResourceExport is deleted. + if r.DeletionTimestamp.IsZero() && !slices.Contains(r.Finalizers, constants.ResourceExportFinalizer) { r.Finalizers = append(r.Finalizers, constants.ResourceExportFinalizer) } } - -func stringExistsInSlice(slice []string, s string) bool { - for _, item := range slice { - if item == s { - return true - } - } - return false -} diff --git a/multicluster/controllers/multicluster/common/helper.go b/multicluster/controllers/multicluster/common/helper.go index 8aec9945008..59d1441ad98 100644 --- a/multicluster/controllers/multicluster/common/helper.go +++ b/multicluster/controllers/multicluster/common/helper.go @@ -42,25 +42,6 @@ func ToMCResourceName(originalResourceName string) string { return AntreaMCSPrefix + originalResourceName } -func StringExistsInSlice(slice []string, s string) bool { - for _, item := range slice { - if item == s { - return true - } - } - return false -} - -func RemoveStringFromSlice(slice []string, s string) (result []string) { - for _, item := range slice { - if item == s { - continue - } - result = append(result, item) - } - return -} - func GetServiceEndpointSubset(svc *corev1.Service) corev1.EndpointSubset { var epSubset corev1.EndpointSubset for _, ip := range svc.Spec.ClusterIPs { diff --git a/multicluster/controllers/multicluster/leader/clusterinfo_export_handler.go b/multicluster/controllers/multicluster/leader/clusterinfo_export_handler.go index 3e2dee45bad..5596960fa91 100644 --- a/multicluster/controllers/multicluster/leader/clusterinfo_export_handler.go +++ b/multicluster/controllers/multicluster/leader/clusterinfo_export_handler.go @@ -24,12 +24,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/klog/v2" + "k8s.io/utils/strings/slices" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "antrea.io/antrea/multicluster/apis/multicluster/constants" mcsv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" - "antrea.io/antrea/multicluster/controllers/multicluster/common" ) func (r *ResourceExportReconciler) handleClusterInfo(ctx context.Context, req ctrl.Request, resExport mcsv1alpha1.ResourceExport) (ctrl.Result, error) { @@ -41,7 +41,7 @@ func (r *ResourceExportReconciler) handleClusterInfo(ctx context.Context, req ct } if !resExport.DeletionTimestamp.IsZero() { - if common.StringExistsInSlice(resExport.Finalizers, constants.ResourceExportFinalizer) { + if slices.Contains(resExport.Finalizers, constants.LegacyResourceExportFinalizer) || slices.Contains(resExport.Finalizers, constants.ResourceExportFinalizer) { err := r.Client.Delete(ctx, resImport, &client.DeleteOptions{}) if err == nil || apierrors.IsNotFound(err) { return r.deleteResourceExport(&resExport) diff --git a/multicluster/controllers/multicluster/leader/memberclusterannounce_controller.go b/multicluster/controllers/multicluster/leader/memberclusterannounce_controller.go index adc4c8968d2..b757b6b0887 100644 --- a/multicluster/controllers/multicluster/leader/memberclusterannounce_controller.go +++ b/multicluster/controllers/multicluster/leader/memberclusterannounce_controller.go @@ -20,6 +20,7 @@ package leader import ( "context" "fmt" + "slices" "sync" "time" @@ -93,7 +94,7 @@ func (r *MemberClusterAnnounceReconciler) Reconcile(ctx context.Context, req ctr } r.addOrUpdateMemberStatus(memberID) - if common.StringExistsInSlice(memberAnnounce.Finalizers, finalizer) { + if slices.Contains(memberAnnounce.Finalizers, finalizer) { return ctrl.Result{}, nil } klog.InfoS("Adding finalizer to MemberClusterAnnounce", "MemberClusterAnnounce", klog.KObj(memberAnnounce)) diff --git a/multicluster/controllers/multicluster/leader/resourceexport_controller.go b/multicluster/controllers/multicluster/leader/resourceexport_controller.go index c836f28dc88..6436032637a 100644 --- a/multicluster/controllers/multicluster/leader/resourceexport_controller.go +++ b/multicluster/controllers/multicluster/leader/resourceexport_controller.go @@ -19,6 +19,7 @@ package leader import ( "context" "fmt" + "slices" "strings" "time" @@ -101,7 +102,7 @@ func (r *ResourceExportReconciler) Reconcile(ctx context.Context, req ctrl.Reque // clean up any replicated resources like ResourceImport. // For more details about using Finalizers, please refer to https://book.kubebuilder.io/reference/using-finalizers.html. if !resExport.DeletionTimestamp.IsZero() { - if common.StringExistsInSlice(resExport.Finalizers, constants.ResourceExportFinalizer) { + if slices.Contains(resExport.Finalizers, constants.LegacyResourceExportFinalizer) || slices.Contains(resExport.Finalizers, constants.ResourceExportFinalizer) { err := r.handleDeleteEvent(ctx, &resExport) if err != nil { return ctrl.Result{}, err @@ -461,7 +462,10 @@ func (r *ResourceExportReconciler) updateResourceExportStatus(resExport *mcsv1al // deleteResourceExport removes ResourceExport finalizer string and updates it, so Kubernetes can complete deletion. func (r *ResourceExportReconciler) deleteResourceExport(resExport *mcsv1alpha1.ResourceExport) (ctrl.Result, error) { - resExport.SetFinalizers(common.RemoveStringFromSlice(resExport.Finalizers, constants.ResourceExportFinalizer)) + finalizers := slices.DeleteFunc(slices.Clone(resExport.Finalizers), func(s string) bool { + return s == constants.LegacyResourceExportFinalizer || s == constants.ResourceExportFinalizer + }) + resExport.SetFinalizers(finalizers) if err := r.Client.Update(context.Background(), resExport, &client.UpdateOptions{}); err != nil { return ctrl.Result{}, err } diff --git a/multicluster/controllers/multicluster/leader/resourceexport_controller_test.go b/multicluster/controllers/multicluster/leader/resourceexport_controller_test.go index c678eb270b2..a47985c299c 100644 --- a/multicluster/controllers/multicluster/leader/resourceexport_controller_test.go +++ b/multicluster/controllers/multicluster/leader/resourceexport_controller_test.go @@ -21,11 +21,13 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" mcs "sigs.k8s.io/mcs-api/pkg/apis/v1alpha1" @@ -53,10 +55,18 @@ var ( Namespace: "default", Name: "cluster-a-default-nginx-service", }} + svcResReq2 = ctrl.Request{NamespacedName: types.NamespacedName{ + Namespace: "default", + Name: "cluster-b-default-nginx-service", + }} epResReq = ctrl.Request{NamespacedName: types.NamespacedName{ Namespace: "default", Name: "cluster-a-default-nginx-endpoints", }} + epResReq2 = ctrl.Request{NamespacedName: types.NamespacedName{ + Namespace: "default", + Name: "cluster-c-default-nginx-endpoints", + }} acnpResReq = ctrl.Request{NamespacedName: types.NamespacedName{ Namespace: "default", Name: "test-acnp-export", @@ -83,10 +93,24 @@ var ( ) func TestResourceExportReconciler_handleServiceExportDeleteEvent(t *testing.T) { - existingResExport := &mcsv1alpha1.ResourceExport{ + existingResExportWithLegacyFinalizer := &mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "cluster-a-default-nginx-service", + Finalizers: []string{constants.LegacyResourceExportFinalizer}, + Labels: svcLabels, + DeletionTimestamp: &now, + }, + Spec: mcsv1alpha1.ResourceExportSpec{ + Namespace: "default", + Name: "nginx", + Kind: constants.ServiceKind, + }, + } + existingResExport := &mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-b-default-nginx-service", Finalizers: []string{constants.ResourceExportFinalizer}, Labels: svcLabels, DeletionTimestamp: &now, @@ -104,17 +128,22 @@ func TestResourceExportReconciler_handleServiceExportDeleteEvent(t *testing.T) { }, } namespacedName := types.NamespacedName{Namespace: "default", Name: "default-nginx-service"} - fakeClient := fake.NewClientBuilder().WithScheme(common.TestScheme).WithObjects(existingResExport, existResImport).Build() + fakeClient := fake.NewClientBuilder().WithScheme(common.TestScheme).WithObjects(existingResExportWithLegacyFinalizer, existingResExport, existResImport).Build() + r := NewResourceExportReconciler(fakeClient, common.TestScheme) - if _, err := r.Reconcile(common.TestCtx, svcResReq); err != nil { - t.Errorf("ResourceExport Reconciler should handle ResourceExport delete event successfully but got error = %v", err) - } else { - resImport := &mcsv1alpha1.ResourceImport{} - err := fakeClient.Get(common.TestCtx, namespacedName, resImport) - if !apierrors.IsNotFound(err) { - t.Errorf("ResourceExport Reconciler should delete ResourceImport successfully but got error = %v", err) - } - } + _, err := r.Reconcile(common.TestCtx, svcResReq) + require.NoError(t, err, "ResourceExport Reconciler should handle ResourceExport delete event successfully") + _, err = r.Reconcile(common.TestCtx, svcResReq2) + require.NoError(t, err, "ResourceExport Reconciler should handle ResourceExport delete event successfully") + + resImport := &mcsv1alpha1.ResourceImport{} + err = fakeClient.Get(common.TestCtx, namespacedName, resImport) + assert.Truef(t, apierrors.IsNotFound(err), "ResourceExport Reconciler should delete ResourceImport successfully") + + resExportsLeft := &mcsv1alpha1.ResourceExportList{} + err = fakeClient.List(common.TestCtx, resExportsLeft) + require.NoError(t, err, "failed to get all ResourceExports") + assert.Empty(t, resExportsLeft.Items, "unexpected number of ResourceExports left in the cluster after deletion") } func TestResourceExportReconciler_handleEndpointsExportDeleteEvent(t *testing.T) { @@ -124,7 +153,7 @@ func TestResourceExportReconciler_handleEndpointsExportDeleteEvent(t *testing.T) Name: "cluster-a-default-nginx-endpoints", Labels: epLabels, DeletionTimestamp: &now, - Finalizers: []string{constants.ResourceExportFinalizer}, + Finalizers: []string{constants.LegacyResourceExportFinalizer}, }, Spec: mcsv1alpha1.ResourceExportSpec{ Namespace: "default", @@ -140,7 +169,7 @@ func TestResourceExportReconciler_handleEndpointsExportDeleteEvent(t *testing.T) Namespace: "default", Name: "cluster-b-default-nginx-endpoints", Labels: epLabels, - Finalizers: []string{constants.ResourceExportFinalizer}, + Finalizers: []string{constants.LegacyResourceExportFinalizer}, }, Spec: mcsv1alpha1.ResourceExportSpec{ Namespace: "default", @@ -151,6 +180,22 @@ func TestResourceExportReconciler_handleEndpointsExportDeleteEvent(t *testing.T) }, }, } + // A ResourceExport with both legacy and new domain qualified finalizers should remove + // all the finalizers and be deleted successfully. + existingResExport3 := &mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-c-default-nginx-endpoints", + Labels: epLabels, + DeletionTimestamp: &now, + Finalizers: []string{constants.LegacyResourceExportFinalizer, constants.ResourceExportFinalizer}, + }, + Spec: mcsv1alpha1.ResourceExportSpec{ + Namespace: "default", + Name: "nginx", + Kind: constants.EndpointsKind, + }, + } existResImport := &mcsv1alpha1.ResourceImport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", @@ -167,20 +212,24 @@ func TestResourceExportReconciler_handleEndpointsExportDeleteEvent(t *testing.T) } expectedSubsets := common.EPNginxSubset2 namespacedName := types.NamespacedName{Namespace: "default", Name: "default-nginx-endpoints"} - fakeClient := fake.NewClientBuilder().WithScheme(common.TestScheme).WithObjects(existingResExport1, existingResExport2, existResImport). - WithStatusSubresource(existingResExport1, existingResExport2, existResImport).Build() + fakeClient := fake.NewClientBuilder().WithScheme(common.TestScheme).WithObjects(existingResExport1, existingResExport2, existingResExport3, existResImport). + WithStatusSubresource(existingResExport1, existingResExport2, existingResExport3, existResImport).Build() + r := NewResourceExportReconciler(fakeClient, common.TestScheme) - if _, err := r.Reconcile(common.TestCtx, epResReq); err != nil { - t.Errorf("ResourceExport Reconciler should handle Endpoints ResourceExport delete event successfully but got error = %v", err) - } else { - resImport := &mcsv1alpha1.ResourceImport{} - err := fakeClient.Get(common.TestCtx, namespacedName, resImport) - if err != nil { - t.Errorf("failed to get ResourceImport, got error = %v", err) - } else if !reflect.DeepEqual(resImport.Spec.Endpoints.Subsets, expectedSubsets) { - t.Errorf("expected ResourceImport Subsets are %v, but got %v", expectedSubsets, resImport.Spec.Endpoints.Subsets) - } - } + _, err := r.Reconcile(common.TestCtx, epResReq) + require.NoError(t, err, "ResourceExport Reconciler should handle Endpoints ResourceExport delete event successfully") + _, err = r.Reconcile(common.TestCtx, epResReq2) + require.NoError(t, err, "ResourceExport Reconciler should handle Endpoints ResourceExport delete event successfully") + + resImport := &mcsv1alpha1.ResourceImport{} + err = fakeClient.Get(common.TestCtx, namespacedName, resImport) + require.NoError(t, err, "failed to get ResourceImport") + assert.ElementsMatch(t, expectedSubsets, resImport.Spec.Endpoints.Subsets, "unexpected ResourceImport Subsets") + + resExportsLeft := &mcsv1alpha1.ResourceExportList{} + err = fakeClient.List(common.TestCtx, resExportsLeft) + require.NoError(t, err, "failed to get all ResourceExports") + assert.Equalf(t, 1, len(resExportsLeft.Items), "unexpected number of ResourceExports left in the cluster after deletion") } func TestResourceExportReconciler_handleServiceExportCreateEvent(t *testing.T) { @@ -504,6 +553,20 @@ func TestResourceExportReconciler_handleClusterInfoKind(t *testing.T) { }, } deletedTime := metav1.Now() + cluster3ResExportToDelLegacyFinalizer := mcsv1alpha1.ResourceExport{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "cluster-c-default-clusterinfo", + Finalizers: []string{constants.LegacyResourceExportFinalizer}, + DeletionTimestamp: &deletedTime, + }, + Spec: mcsv1alpha1.ResourceExportSpec{ + Kind: constants.ClusterInfoKind, + ClusterID: "cluster-c", + Name: "cluster-c", + Namespace: "default", + }, + } cluster3ResExportToDel := mcsv1alpha1.ResourceExport{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", @@ -531,52 +594,55 @@ func TestResourceExportReconciler_handleClusterInfoKind(t *testing.T) { }, } tests := []struct { - name string - ciRes mcsv1alpha1.ResourceExport - expectedInfo mcsv1alpha1.ClusterInfo - isDelete bool + name string + ciRes mcsv1alpha1.ResourceExport + existingObjects []client.Object + expectedInfo mcsv1alpha1.ClusterInfo + isDelete bool }{ { - name: "create a ClusterInfo kind of ResourceImport successfully", - ciRes: clusterACIResExport, - expectedInfo: clusterAInfo, + name: "create a ClusterInfo kind of ResourceImport successfully", + ciRes: clusterACIResExport, + existingObjects: []client.Object{&clusterACIResExport}, + expectedInfo: clusterAInfo, }, { - name: "update a ClusterInfo kind of ResourceImport successfully", - ciRes: clusterBCIResExport, - expectedInfo: clusterBInfoNew, + name: "update a ClusterInfo kind of ResourceImport successfully", + ciRes: clusterBCIResExport, + existingObjects: []client.Object{&clusterBCIResExport, &existResImport}, + expectedInfo: clusterBInfoNew, }, { - name: "delete a ClusterInfo kind of ResourceImport successfully", - ciRes: cluster3ResExportToDel, - isDelete: true, + name: "delete a ClusterInfo kind of ResourceImport and ResourceExport with legacy finalizer successfully", + ciRes: cluster3ResExportToDelLegacyFinalizer, + existingObjects: []client.Object{&existResImportToDel, &cluster3ResExportToDelLegacyFinalizer}, + isDelete: true, + }, + { + name: "delete a ClusterInfo kind of ResourceImport and ResourceExport successfully", + ciRes: cluster3ResExportToDelLegacyFinalizer, + existingObjects: []client.Object{&existResImportToDel, &cluster3ResExportToDel}, + isDelete: true, }, } - fakeClient := fake.NewClientBuilder().WithScheme(common.TestScheme).WithObjects(&clusterACIResExport, &clusterBCIResExport, - &existResImport, &existResImportToDel, &cluster3ResExportToDel).Build() - r := NewResourceExportReconciler(fakeClient, common.TestScheme) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + fakeClient := fake.NewClientBuilder().WithScheme(common.TestScheme).WithObjects(tt.existingObjects...).Build() + r := NewResourceExportReconciler(fakeClient, common.TestScheme) namespacedName := types.NamespacedName{Namespace: tt.ciRes.Namespace, Name: tt.ciRes.Name} req := ctrl.Request{NamespacedName: namespacedName} - if _, err := r.Reconcile(common.TestCtx, req); err != nil { - t.Errorf("ResourceExport Reconciler should handle Resourcexports events successfully but got error = %v", err) + _, err := r.Reconcile(common.TestCtx, req) + require.NoError(t, err, "ResourceExport Reconciler should handle ResourceExports events successfully") + + teImport := mcsv1alpha1.ResourceImport{} + err = fakeClient.Get(common.TestCtx, namespacedName, &teImport) + if err == nil { + assert.Falsef(t, tt.isDelete, "Expected error to be not found err but got nil") + assert.Truef(t, reflect.DeepEqual(*teImport.Spec.ClusterInfo, tt.expectedInfo), "unexpected ClusterInfo") } else { - teImport := mcsv1alpha1.ResourceImport{} - err := fakeClient.Get(common.TestCtx, namespacedName, &teImport) - if err == nil { - if tt.isDelete { - t.Error("Expected not found err but got nil err") - } else if !reflect.DeepEqual(*teImport.Spec.ClusterInfo, tt.expectedInfo) { - t.Errorf("Expected ClusterInfo %v but got %v", tt.expectedInfo, teImport.Spec.ClusterInfo) - } - } else { - teExport := mcsv1alpha1.ResourceExport{} - err := fakeClient.Get(common.TestCtx, namespacedName, &teExport) - if !apierrors.IsNotFound(err) { - t.Errorf("ResourceExport should be deleted successfully but got = %v", err) - } - } + teExport := mcsv1alpha1.ResourceExport{} + err := fakeClient.Get(common.TestCtx, namespacedName, &teExport) + assert.Truef(t, apierrors.IsNotFound(err), "ResourceExport should be deleted successfully") } }) } diff --git a/multicluster/controllers/multicluster/leader/stale_controller.go b/multicluster/controllers/multicluster/leader/stale_controller.go index a85a882c298..369acec1259 100644 --- a/multicluster/controllers/multicluster/leader/stale_controller.go +++ b/multicluster/controllers/multicluster/leader/stale_controller.go @@ -19,6 +19,7 @@ package leader import ( "context" "fmt" + "slices" "strings" "time" @@ -31,7 +32,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller" mcv1alpha1 "antrea.io/antrea/multicluster/apis/multicluster/v1alpha1" - "antrea.io/antrea/multicluster/controllers/multicluster/common" "antrea.io/antrea/multicluster/controllers/multicluster/commonarea" ) @@ -127,8 +127,10 @@ func (c *StaleResCleanupController) Reconcile(ctx context.Context, req ctrl.Requ } // When cleanup is done, remove the Finalizer of this MemberClusterAnnounce. - finalizer := fmt.Sprintf("%s/%s", MemberClusterAnnounceFinalizer, memberAnnounce.ClusterID) - memberAnnounce.Finalizers = common.RemoveStringFromSlice(memberAnnounce.Finalizers, finalizer) + finalizerToRemove := fmt.Sprintf("%s/%s", MemberClusterAnnounceFinalizer, memberAnnounce.ClusterID) + memberAnnounce.Finalizers = slices.DeleteFunc(slices.Clone(memberAnnounce.Finalizers), func(s string) bool { + return s == finalizerToRemove + }) if err := c.Update(context.TODO(), memberAnnounce); err != nil { klog.ErrorS(err, "Failed to update MemberClusterAnnounce", "MemberClusterAnnounce", klog.KObj(memberAnnounce)) return ctrl.Result{}, err diff --git a/multicluster/test/integration/resourceexport_controller_test.go b/multicluster/test/integration/resourceexport_controller_test.go index a41d384fb3c..a892ef9b5b4 100644 --- a/multicluster/test/integration/resourceexport_controller_test.go +++ b/multicluster/test/integration/resourceexport_controller_test.go @@ -72,7 +72,7 @@ var _ = Describe("ResourceExport controller", func() { constants.SourceClusterID: clusteraID, }, Generation: 1, - Finalizers: []string{constants.ResourceExportFinalizer}, + Finalizers: []string{constants.LegacyResourceExportFinalizer}, }, Spec: mcsv1alpha1.ResourceExportSpec{ ClusterID: clusteraID, @@ -127,7 +127,7 @@ var _ = Describe("ResourceExport controller", func() { constants.SourceClusterID: clusterbID, }, Generation: 1, - Finalizers: []string{constants.ResourceExportFinalizer}, + Finalizers: []string{constants.LegacyResourceExportFinalizer}, }, Spec: mcsv1alpha1.ResourceExportSpec{ ClusterID: clusterbID,