diff --git a/internal/controllers/managedcontrolplane/controller.go b/internal/controllers/managedcontrolplane/controller.go index 27ce453..d0d6354 100644 --- a/internal/controllers/managedcontrolplane/controller.go +++ b/internal/controllers/managedcontrolplane/controller.go @@ -91,7 +91,13 @@ func (r *ManagedControlPlaneReconciler) Reconcile(ctx context.Context, req recon }). WithConditionUpdater(false). WithConditionEvents(r.eventRecorder, conditions.EventPerChange). - WithSmartRequeue(r.sr). + WithSmartRequeue(r.sr, func(rr ReconcileResult) ctrlutils.SmartRequeueAction { + if rr.SmartRequeue == ctrlutils.SR_NO_REQUEUE && rr.Object.Status.Phase != commonapi.StatusPhaseReady { + // requeue if the phase is not 'Ready' if a requeue is not already planned + return ctrlutils.SR_BACKOFF + } + return rr.SmartRequeue + }). Build(). UpdateStatus(ctx, r.OnboardingCluster.Client(), rr) } diff --git a/internal/controllers/managedcontrolplane/controller_test.go b/internal/controllers/managedcontrolplane/controller_test.go index eac9b77..31f246b 100644 --- a/internal/controllers/managedcontrolplane/controller_test.go +++ b/internal/controllers/managedcontrolplane/controller_test.go @@ -284,6 +284,10 @@ var _ = Describe("ManagedControlPlane Controller", func() { Expect(env.Client(platform).Create(env.Ctx, sec)).To(Succeed()) } + // remove non-ready cluster condition because it will prevent the MCP from becoming ready + cluster.Status.Conditions[1].Status = metav1.ConditionTrue + Expect(env.Client(platform).Status().Update(env.Ctx, cluster)).To(Succeed()) + // reconcile the MCP again // expected outcome: // - the mcp has conditions that reflect that all access requests are ready @@ -867,4 +871,29 @@ var _ = Describe("ManagedControlPlane Controller", func() { env.ShouldReconcile(mcpRec, testutils.RequestFromObject(mcp)) }) + It("should requeue the MCP if its phase is not 'Ready', even if all accesses are ready", func() { + _, env := defaultTestSetup("testdata", "test-02") + + mcp := &corev2alpha1.ManagedControlPlaneV2{} + mcp.SetName("mcp-01") + mcp.SetNamespace("test") + Expect(env.Client(onboarding).Get(env.Ctx, client.ObjectKeyFromObject(mcp), mcp)).To(Succeed()) + + res := env.ShouldReconcile(mcpRec, testutils.RequestFromObject(mcp)) + Expect(env.Client(onboarding).Get(env.Ctx, client.ObjectKeyFromObject(mcp), mcp)).To(Succeed()) + Expect(mcp.Status.Conditions).To(ContainElements( + MatchCondition(TestCondition(). + WithType("Cluster.Ready"). + WithStatus(metav1.ConditionFalse)), + MatchCondition(TestCondition(). + WithType(corev2alpha1.ConditionAllAccessReady). + WithStatus(metav1.ConditionTrue)), + MatchCondition(TestCondition(). + WithType("AccessReady.token_viewer"). + WithStatus(metav1.ConditionTrue)), + )) + Expect(res.RequeueAfter).To(BeNumerically(">", 0)) + Expect(res.RequeueAfter).To(BeNumerically("<", 1*time.Minute), "MCP has not been requeued") + }) + }) diff --git a/internal/controllers/managedcontrolplane/testdata/test-02/config.yaml b/internal/controllers/managedcontrolplane/testdata/test-02/config.yaml new file mode 100644 index 0000000..d693772 --- /dev/null +++ b/internal/controllers/managedcontrolplane/testdata/test-02/config.yaml @@ -0,0 +1,7 @@ +managedControlPlane: + mcpClusterPurpose: mcp + reconcileMCPEveryXDays: 7 + defaultOIDCProvider: + issuer: https://example.com/oidc + groupsPrefix: 'mygroups:' + usernamePrefix: 'myuser:' diff --git a/internal/controllers/managedcontrolplane/testdata/test-02/onboarding/mcp-01.yaml b/internal/controllers/managedcontrolplane/testdata/test-02/onboarding/mcp-01.yaml new file mode 100644 index 0000000..7692f9c --- /dev/null +++ b/internal/controllers/managedcontrolplane/testdata/test-02/onboarding/mcp-01.yaml @@ -0,0 +1,19 @@ +apiVersion: core.openmcp.cloud/v2alpha1 +kind: ManagedControlPlaneV2 +metadata: + name: mcp-01 + namespace: test + uid: 6aa4f8e1-a590-4fd7-b751-0b93f9f38bde +spec: + iam: + tokens: + - name: viewer + permissions: + - rules: + - apiGroups: [ '' ] + resources: [ 'pods', 'services' ] + verbs: [ 'get', 'list', 'watch' ] +status: + access: + token_viewer: + name: 6nilzexg diff --git a/internal/controllers/managedcontrolplane/testdata/test-02/onboarding/mcp-access-secret-01.yaml b/internal/controllers/managedcontrolplane/testdata/test-02/onboarding/mcp-access-secret-01.yaml new file mode 100644 index 0000000..17bd2ee --- /dev/null +++ b/internal/controllers/managedcontrolplane/testdata/test-02/onboarding/mcp-access-secret-01.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +data: + kubeconfig: ZmFrZQ== +kind: Secret +metadata: + labels: + core.openmcp.cloud/mcp-name: mcp-01 + core.openmcp.cloud/mcp-namespace: test + core.openmcp.cloud/token-provider: viewer + openmcp.cloud/managed-by: ManagedControlPlane + name: 6nilzexg + namespace: test + ownerReferences: + - apiVersion: core.openmcp.cloud/v2alpha1 + blockOwnerDeletion: true + controller: true + kind: ManagedControlPlaneV2 + name: mcp-01 + uid: 6aa4f8e1-a590-4fd7-b751-0b93f9f38bde +type: Opaque diff --git a/internal/controllers/managedcontrolplane/testdata/test-02/platform/ar-01.yaml b/internal/controllers/managedcontrolplane/testdata/test-02/platform/ar-01.yaml new file mode 100644 index 0000000..02ef03f --- /dev/null +++ b/internal/controllers/managedcontrolplane/testdata/test-02/platform/ar-01.yaml @@ -0,0 +1,40 @@ +apiVersion: clusters.openmcp.cloud/v1alpha1 +kind: AccessRequest +metadata: + finalizers: + - clusters.openmcp.cloud/finalizer + labels: + clusters.openmcp.cloud/profile: kind + clusters.openmcp.cloud/provider: kind + core.openmcp.cloud/mcp-name: mcp-01 + core.openmcp.cloud/mcp-namespace: test + core.openmcp.cloud/token-provider: viewer + openmcp.cloud/managed-by: ManagedControlPlane + name: c73jfgp2 + namespace: mcp--ac6294ed-3227-8926-b364-f791fabdb843 + uid: 5ebc81b8-8d5a-4e57-9d7e-7ea4b915fcaf +spec: + clusterRef: + name: mcp-12345 + namespace: mcp--ac6294ed-3227-8926-b364-f791fabdb843 + requestRef: + name: mcp-01 + namespace: mcp--ac6294ed-3227-8926-b364-f791fabdb843 + token: + permissions: + - rules: + - apiGroups: + - "" + resources: + - pods + - services + verbs: + - get + - list + - watch +status: + observedGeneration: 2 + phase: Granted + secretRef: + name: c73jfgp2.kubeconfig + namespace: mcp--ac6294ed-3227-8926-b364-f791fabdb843 diff --git a/internal/controllers/managedcontrolplane/testdata/test-02/platform/ar-secret-01.yaml b/internal/controllers/managedcontrolplane/testdata/test-02/platform/ar-secret-01.yaml new file mode 100644 index 0000000..5ea9d15 --- /dev/null +++ b/internal/controllers/managedcontrolplane/testdata/test-02/platform/ar-secret-01.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Secret +metadata: + creationTimestamp: "2025-10-14T11:02:07Z" + name: c73jfgp2.kubeconfig + namespace: mcp--ac6294ed-3227-8926-b364-f791fabdb843 + ownerReferences: + - apiVersion: clusters.openmcp.cloud/v1alpha1 + kind: AccessRequest + name: c73jfgp2 + uid: 5ebc81b8-8d5a-4e57-9d7e-7ea4b915fcaf + resourceVersion: "629926" + uid: b7c4bf8e-442f-4c54-8eff-b7b5e4a41a4d +type: Opaque +data: + kubeconfig: ZmFrZQ== diff --git a/internal/controllers/managedcontrolplane/testdata/test-02/platform/cluster-01.yaml b/internal/controllers/managedcontrolplane/testdata/test-02/platform/cluster-01.yaml new file mode 100644 index 0000000..a013f3c --- /dev/null +++ b/internal/controllers/managedcontrolplane/testdata/test-02/platform/cluster-01.yaml @@ -0,0 +1,36 @@ +apiVersion: clusters.openmcp.cloud/v1alpha1 +kind: Cluster +metadata: + finalizers: + - request.clusters.openmcp.cloud/24143a57-be40-495e-96e2-4623e563a066 + - clusters.openmcp.cloud/finalizer + generation: 1 + labels: + clusters.openmcp.cloud/delete-without-requests: "true" + name: mcp-12345 + namespace: mcp--ac6294ed-3227-8926-b364-f791fabdb843 +spec: + kubernetes: {} + profile: kind + purposes: + - mcp + tenancy: Exclusive +status: + conditions: + - lastTransitionTime: "2025-09-22T08:23:32Z" + message: "" + reason: ClusterExists + status: "True" + type: KindReady + - lastTransitionTime: "2025-09-22T08:24:02Z" + message: "" + reason: AllPodsReady + status: "True" + type: MetalLBReady + - lastTransitionTime: "2025-09-22T08:24:02Z" + message: "" + reason: ClusterAndMetalLBReady + status: "False" + type: Ready + observedGeneration: 0 + phase: Progressing diff --git a/internal/controllers/managedcontrolplane/testdata/test-02/platform/cr-01.yaml b/internal/controllers/managedcontrolplane/testdata/test-02/platform/cr-01.yaml new file mode 100644 index 0000000..4984e43 --- /dev/null +++ b/internal/controllers/managedcontrolplane/testdata/test-02/platform/cr-01.yaml @@ -0,0 +1,19 @@ +apiVersion: clusters.openmcp.cloud/v1alpha1 +kind: ClusterRequest +metadata: + labels: + core.openmcp.cloud/mcp-name: mcp-01 + core.openmcp.cloud/mcp-namespace: test + openmcp.cloud/managed-by: ManagedControlPlane + name: mcp-01 + namespace: mcp--ac6294ed-3227-8926-b364-f791fabdb843 + uid: 24143a57-be40-495e-96e2-4623e563a066 +spec: + purpose: mcp + waitForClusterDeletion: true +status: + cluster: + name: mcp-12345 + namespace: mcp--ac6294ed-3227-8926-b364-f791fabdb843 + observedGeneration: 1 + phase: Granted