diff --git a/pkg/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller.go b/pkg/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller.go index 2a9f0327a..5b9b7606c 100644 --- a/pkg/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller.go +++ b/pkg/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller.go @@ -183,43 +183,30 @@ func (n *klusterletController) sync(ctx context.Context, controllerContext facto } // Start deploy klusterlet components - // Check if namespace exists - _, err = n.kubeClient.CoreV1().Namespaces().Get(ctx, config.KlusterletNamespace, metav1.GetOptions{}) - switch { - case errors.IsNotFound(err): - _, createErr := n.kubeClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: config.KlusterletNamespace, - Annotations: map[string]string{ - "workload.openshift.io/allowed": "management", - }, - }, - }, metav1.CreateOptions{}) - if createErr != nil { - _, _, _ = helpers.UpdateKlusterletStatus(ctx, n.klusterletClient, klusterletName, helpers.UpdateKlusterletConditionFn(metav1.Condition{ - Type: klusterletApplied, Status: metav1.ConditionFalse, Reason: "KlusterletApplyFailed", - Message: fmt.Sprintf("Failed to create namespace %q: %v", config.KlusterletNamespace, createErr), - })) - return createErr + // Ensure the existence namespaces for klusterlet and klusterlet addon + // Sync pull secret to each namespace + namespaces := []string{config.KlusterletNamespace, fmt.Sprintf("%s-addon", config.KlusterletNamespace)} + for _, namespace := range namespaces { + err := n.ensureNamespace(ctx, klusterlet.Name, namespace) + if err != nil { + return err } - case err != nil: - _, _, _ = helpers.UpdateKlusterletStatus(ctx, n.klusterletClient, klusterletName, helpers.UpdateKlusterletConditionFn(metav1.Condition{ - Type: klusterletApplied, Status: metav1.ConditionFalse, Reason: "KlusterletApplyFailed", - Message: fmt.Sprintf("Failed to get namespace %q: %v", config.KlusterletNamespace, err), - })) - return err - } - // Sync pull secret - _, _, err = resourceapply.SyncSecret( - n.kubeClient.CoreV1(), - controllerContext.Recorder(), - n.operatorNamespace, - imagePullSecret, - config.KlusterletNamespace, - imagePullSecret, - []metav1.OwnerReference{}, - ) + // Sync pull secret + _, _, err = resourceapply.SyncSecret( + n.kubeClient.CoreV1(), + controllerContext.Recorder(), + n.operatorNamespace, + imagePullSecret, + namespace, + imagePullSecret, + []metav1.OwnerReference{}, + ) + + if err != nil { + return err + } + } if err != nil { _, _, _ = helpers.UpdateKlusterletStatus(ctx, n.klusterletClient, klusterletName, helpers.UpdateKlusterletConditionFn(metav1.Condition{ @@ -385,6 +372,36 @@ func (n *klusterletController) sync(ctx context.Context, controllerContext facto return nil } +func (n *klusterletController) ensureNamespace(ctx context.Context, klusterletName, namespace string) error { + _, err := n.kubeClient.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{}) + switch { + case errors.IsNotFound(err): + _, createErr := n.kubeClient.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: namespace, + Annotations: map[string]string{ + "workload.openshift.io/allowed": "management", + }, + }, + }, metav1.CreateOptions{}) + if createErr != nil { + _, _, _ = helpers.UpdateKlusterletStatus(ctx, n.klusterletClient, klusterletName, helpers.UpdateKlusterletConditionFn(metav1.Condition{ + Type: klusterletApplied, Status: metav1.ConditionFalse, Reason: "KlusterletApplyFailed", + Message: fmt.Sprintf("Failed to create namespace %q: %v", namespace, createErr), + })) + return createErr + } + case err != nil: + _, _, _ = helpers.UpdateKlusterletStatus(ctx, n.klusterletClient, klusterletName, helpers.UpdateKlusterletConditionFn(metav1.Condition{ + Type: klusterletApplied, Status: metav1.ConditionFalse, Reason: "KlusterletApplyFailed", + Message: fmt.Sprintf("Failed to get namespace %q: %v", namespace, err), + })) + return err + } + + return nil +} + func (n *klusterletController) cleanUp(ctx context.Context, controllerContext factory.SyncContext, config klusterletConfig) error { // Remove deployment registrationDeployment := fmt.Sprintf("%s-registration-agent", config.KlusterletName) @@ -466,10 +483,13 @@ func (n *klusterletController) cleanUp(ctx context.Context, controllerContext fa } } - // remove the klusterlet namespace - err = n.kubeClient.CoreV1().Namespaces().Delete(ctx, config.KlusterletNamespace, metav1.DeleteOptions{}) - if err != nil && !errors.IsNotFound(err) { - return err + // remove the klusterlet namespace and klusterlet addon namespace + namespaces := []string{config.KlusterletNamespace, fmt.Sprintf("%s-addon", config.KlusterletNamespace)} + for _, namespace := range namespaces { + err = n.kubeClient.CoreV1().Namespaces().Delete(ctx, namespace, metav1.DeleteOptions{}) + if err != nil && !errors.IsNotFound(err) { + return err + } } // remove AppliedManifestWorks diff --git a/pkg/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller_test.go b/pkg/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller_test.go index fce8d6836..7140792fa 100644 --- a/pkg/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller_test.go +++ b/pkg/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller_test.go @@ -277,8 +277,8 @@ func TestSyncDeploy(t *testing.T) { } // Check if resources are created as expected - if len(createObjects) != 11 { - t.Errorf("Expect 11 objects created in the sync loop, actual %d", len(createObjects)) + if len(createObjects) != 12 { + t.Errorf("Expect 12 objects created in the sync loop, actual %d", len(createObjects)) } for _, object := range createObjects { ensureObject(t, object, klusterlet) @@ -338,8 +338,8 @@ func TestSyncDelete(t *testing.T) { } } - if len(deleteActions) != 13 { - t.Errorf("Expected 13 delete actions, but got %d", len(deleteActions)) + if len(deleteActions) != 14 { + t.Errorf("Expected 14 delete actions, but got %d", len(deleteActions)) } deleteCRDActions := []clienttesting.DeleteActionImpl{} @@ -551,8 +551,8 @@ func TestDeployOnKube111(t *testing.T) { } // Check if resources are created as expected - if len(createObjects) != 13 { - t.Errorf("Expect 13 objects created in the sync loop, actual %d", len(createObjects)) + if len(createObjects) != 14 { + t.Errorf("Expect 14 objects created in the sync loop, actual %d", len(createObjects)) } for _, object := range createObjects { ensureObject(t, object, klusterlet) @@ -588,8 +588,8 @@ func TestDeployOnKube111(t *testing.T) { } } - if len(deleteActions) != 15 { - t.Errorf("Expected 15 delete actions, but got %d", len(kubeActions)) + if len(deleteActions) != 16 { + t.Errorf("Expected 16 delete actions, but got %d", len(kubeActions)) } } diff --git a/test/integration/klusterlet_test.go b/test/integration/klusterlet_test.go index ea62278d6..64f166d8e 100644 --- a/test/integration/klusterlet_test.go +++ b/test/integration/klusterlet_test.go @@ -168,6 +168,15 @@ var _ = ginkgo.Describe("Klusterlet", func() { return true }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue()) + // Check addon namespace + addonNamespace := fmt.Sprintf("%s-addon", klusterletNamespace) + gomega.Eventually(func() bool { + if _, err := kubeClient.CoreV1().Namespaces().Get(context.Background(), addonNamespace, metav1.GetOptions{}); err != nil { + return false + } + return true + }, eventuallyTimeout, eventuallyInterval).Should(gomega.BeTrue()) + util.AssertKlusterletCondition(klusterlet.Name, operatorClient, "Applied", "KlusterletApplied", metav1.ConditionTrue) })