diff --git a/internal/controller/core/authorization/controller.go b/internal/controller/core/authorization/controller.go index 211925b..91b028b 100644 --- a/internal/controller/core/authorization/controller.go +++ b/internal/controller/core/authorization/controller.go @@ -144,6 +144,28 @@ func (ar *AuthorizationReconciler) reconcile(ctx context.Context, req ctrl.Reque return componentutils.ReconcileResult[*openmcpv1alpha1.Authorization]{Component: authz, Conditions: authorizationConditions(true, cconst.ReasonDeletionWaitingForDependingComponents, fmt.Sprintf("Deletion is waiting for the following dependencies to be removed: [%s]", depString)), Result: ctrl.Result{RequeueAfter: 60 * time.Second}} } + // If there is a ClusterAdmin resource with the same name and namespace as the Authorization, we need to delete it first and wait for it to be removed before we can delete the Authorization. + log.Info("Deleting Cluster Admin resources") + clusterAdmin := &openmcpv1alpha1.ClusterAdmin{} + if err = ar.Client.Get(ctx, client.ObjectKey{Name: authz.Name, Namespace: authz.Namespace}, clusterAdmin); err != nil { + if !apierrors.IsNotFound(err) { + log.Error(err, "error fetching ClusterAdmin resource") + return componentutils.ReconcileResult[*openmcpv1alpha1.Authorization]{Component: authz, ReconcileError: openmcperrors.WithReason(fmt.Errorf("error fetching ClusterAdmin resource: %w", err), cconst.ReasonCrateClusterInteractionProblem)} + } + } else { + if !clusterAdmin.DeletionTimestamp.IsZero() { + if err = ar.Client.Delete(ctx, clusterAdmin); err != nil { + if !apierrors.IsNotFound(err) { + log.Error(err, "error deleting ClusterAdmin resource") + return componentutils.ReconcileResult[*openmcpv1alpha1.Authorization]{Component: authz, ReconcileError: openmcperrors.WithReason(fmt.Errorf("error deleting ClusterAdmin resource: %w", err), cconst.ReasonCrateClusterInteractionProblem)} + } + } + } + + log.Info("Deletion is waiting for the ClusterAdmin to be removed") + return componentutils.ReconcileResult[*openmcpv1alpha1.Authorization]{Component: authz, Conditions: authorizationConditions(true, cconst.ReasonDeletionWaitingForDependingComponents, "Deletion is waiting for the ClusterAdmin to be removed"), Result: ctrl.Result{RequeueAfter: 60 * time.Second}} + } + log.Info("Deleting Authorization") if err = ar.deleteAuthorization(ctx, apiServerClient); err != nil { log.Error(err, "error deleting authorization resources") diff --git a/internal/controller/core/authorization/controller_test.go b/internal/controller/core/authorization/controller_test.go index 25c7a93..1f86c08 100644 --- a/internal/controller/core/authorization/controller_test.go +++ b/internal/controller/core/authorization/controller_test.go @@ -1032,6 +1032,53 @@ var _ = Describe("CO-1153 Authorization Controller", func() { })) }) + It("should delete the corresponding ClusterAdmin resource when the Authorization is deleted", func() { + var err error + env := testEnvWithAPIServerAccess("testdata", "test-09") + + authz := &openmcpv1alpha1.Authorization{} + err = env.Client(testutils.CrateCluster).Get(env.Ctx, types.NamespacedName{Name: "test", Namespace: "test"}, authz) + Expect(err).ToNot(HaveOccurred()) + + req := testing.RequestFromObject(authz) + _ = env.ShouldReconcile(authzReconciler, req) + + err = env.Client(testutils.CrateCluster).Get(env.Ctx, client.ObjectKeyFromObject(authz), authz) + Expect(err).ToNot(HaveOccurred()) + Expect(authz.Status.Conditions).To(ContainElements( + MatchComponentCondition(openmcpv1alpha1.ComponentCondition{ + Type: openmcpv1alpha1.AuthorizationComponent.ReconciliationCondition(), + Status: openmcpv1alpha1.ComponentConditionStatusTrue, + }), + )) + + clusterAdmin := &openmcpv1alpha1.ClusterAdmin{} + err = env.Client(testutils.CrateCluster).Get(env.Ctx, types.NamespacedName{Name: "test", Namespace: "test"}, clusterAdmin) + Expect(err).ToNot(HaveOccurred()) + + err = env.Client(testutils.CrateCluster).Delete(env.Ctx, authz) + Expect(err).ToNot(HaveOccurred()) + + req = testing.RequestFromObject(authz) + _ = env.ShouldReconcile(authzReconciler, req) + + err = env.Client(testutils.CrateCluster).Get(env.Ctx, types.NamespacedName{Name: "test", Namespace: "test"}, authz) + Expect(err).ToNot(HaveOccurred()) + + err = env.Client(testutils.CrateCluster).Delete(env.Ctx, clusterAdmin) + Expect(err).ToNot(HaveOccurred()) + + _ = env.ShouldReconcile(authzReconciler, req) + + err = env.Client(testutils.CrateCluster).Get(env.Ctx, types.NamespacedName{Name: "test", Namespace: "test"}, authz) + Expect(err).To(HaveOccurred()) + Expect(errors.IsNotFound(err)).To(BeTrue()) + + err = env.Client(testutils.CrateCluster).Get(env.Ctx, types.NamespacedName{Name: "test", Namespace: "test"}, clusterAdmin) + Expect(err).To(HaveOccurred()) + Expect(errors.IsNotFound(err)).To(BeTrue()) + }) + }) func verifyStandardClusterRole(role *rbacv1.ClusterRole) { diff --git a/internal/controller/core/authorization/testdata/test-09/apiserver.yaml b/internal/controller/core/authorization/testdata/test-09/apiserver.yaml new file mode 100644 index 0000000..4fd39a7 --- /dev/null +++ b/internal/controller/core/authorization/testdata/test-09/apiserver.yaml @@ -0,0 +1,42 @@ +apiVersion: core.openmcp.cloud/v1alpha1 +kind: APIServer +metadata: + name: test + namespace: test + labels: + "openmcp.cloud/mcp-generation": "1" +spec: + desiredRegion: + direction: central + name: europe + type: GardenerDedicated +status: + conditions: + - lastTransitionTime: "2024-05-22T08:23:47Z" + status: "True" + type: apiServerHealthy + observedGenerations: + internalConfiguration: -1 + managedControlPlane: 1 + resource: 0 + adminAccess: + creationTimestamp: "2024-05-22T08:23:47Z" + expirationTimestamp: "2024-11-18T08:23:47Z" + kubeconfig: | + apiVersion: v1 + clusters: + - name: apiserver + cluster: + server: https://apiserver.dummy + certificate-authority-data: ZHVtbXkK + contexts: + - name: apiserver + context: + cluster: apiserver + user: apiserver + current-context: apiserver + users: + - name: apiserver + user: + client-certificate-data: ZHVtbXkK + client-key-data: ZHVtbXkK \ No newline at end of file diff --git a/internal/controller/core/authorization/testdata/test-09/authorization.yaml b/internal/controller/core/authorization/testdata/test-09/authorization.yaml new file mode 100644 index 0000000..3a7c7a3 --- /dev/null +++ b/internal/controller/core/authorization/testdata/test-09/authorization.yaml @@ -0,0 +1,18 @@ +apiVersion: core.openmcp.cloud/v1alpha1 +kind: Authorization +metadata: + name: test + namespace: test + labels: + "openmcp.cloud/mcp-generation": "1" +spec: + roleBindings: + - role: admin + subjects: + - kind: User + name: admin + - role: admin + subjects: + - kind: ServiceAccount + name: pipeline + namespace: automate diff --git a/internal/controller/core/authorization/testdata/test-09/clusteradmin.yaml b/internal/controller/core/authorization/testdata/test-09/clusteradmin.yaml new file mode 100644 index 0000000..9f1564e --- /dev/null +++ b/internal/controller/core/authorization/testdata/test-09/clusteradmin.yaml @@ -0,0 +1,9 @@ +apiVersion: core.openmcp.cloud/v1alpha1 +kind: ClusterAdmin +metadata: + name: test + namespace: test +spec: + subjects: + - kind: User + name: admin