Skip to content

Commit 58a9994

Browse files
committed
implement delete path of mcp controller
1 parent 3321922 commit 58a9994

File tree

6 files changed

+369
-30
lines changed

6 files changed

+369
-30
lines changed

api/clusters/v1alpha1/constants/reasons.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ const (
1515
ReasonWaitingForClusterRequest = "WaitingForClusterRequest"
1616
// ReasonWaitingForAccessRequest indicates that something is waiting for an AccessRequest to become ready.
1717
ReasonWaitingForAccessRequest = "WaitingForAccessRequest"
18+
// ReasonWaitingForServices indicates that something is waiting for one or more service providers to do something.
19+
ReasonWaitingForServices = "WaitingForServices"
1820
)

api/core/v2alpha1/constants.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,21 @@ const (
88
const (
99
MCPLabel = GroupName + "/mcp"
1010
OIDCProviderLabel = GroupName + "/oidc-provider"
11+
12+
MCPFinalizer = MCPLabel
13+
14+
// ServiceDependencyFinalizerPrefix is the prefix for the dependency finalizers that are added to MCP resources by associated services.
15+
ServiceDependencyFinalizerPrefix = "services.openmcp.cloud/"
16+
// ClusterRequestFinalizerPrefix is the prefix for the finalizers that are added to MCP resources for cluster requests.
17+
ClusterRequestFinalizerPrefix = "request.clusters.openmcp.cloud/"
1118
)
1219

1320
const (
14-
ConditionClusterRequestReady = "ClusterRequestReady"
15-
ConditionPrefixOIDCAccessReady = "OIDCAccessReady_"
16-
ConditionAllAccessReady = "AllAccessReady"
21+
ConditionMeta = "Meta"
22+
23+
ConditionClusterRequestReady = "ClusterRequestReady"
24+
ConditionPrefixOIDCAccessReady = "OIDCAccessReady_"
25+
ConditionAllAccessReady = "AllAccessReady"
26+
ConditionAllServicesDeleted = "AllServicesDeleted"
27+
ConditionAllClusterRequestsDeleted = "AllClusterRequestsDeleted"
1728
)

internal/controllers/managedcontrolplane/access.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"sigs.k8s.io/controller-runtime/pkg/client"
1212
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1313

14-
"github.com/openmcp-project/controller-utils/pkg/conditions"
1514
ctrlutils "github.com/openmcp-project/controller-utils/pkg/controller"
1615
errutils "github.com/openmcp-project/controller-utils/pkg/errors"
1716
"github.com/openmcp-project/controller-utils/pkg/logging"
@@ -25,41 +24,40 @@ import (
2524
)
2625

2726
// manageAccessRequests aligns the existing AccessRequests for the MCP with the currently configured OIDC providers.
28-
// It uses the given createCon function to create conditions for AccessRequests and removes outdated AccessRequest related conditions directly from the MCP status.
27+
// It uses the given createCon function to create conditions for AccessRequests and returns a set of conditions that should be removed from the MCP status.
2928
// The bool return value specifies whether everything related to MCP access is in the desired state or not. If 'false', it is recommended to requeue the MCP.
30-
func (r *ManagedControlPlaneReconciler) manageAccessRequests(ctx context.Context, mcp *corev2alpha1.ManagedControlPlane, cr *clustersv1alpha1.ClusterRequest, createCon func(conType string, status metav1.ConditionStatus, reason, message string)) (bool, errutils.ReasonableError) {
29+
func (r *ManagedControlPlaneReconciler) manageAccessRequests(ctx context.Context, mcp *corev2alpha1.ManagedControlPlane, cr *clustersv1alpha1.ClusterRequest, createCon func(conType string, status metav1.ConditionStatus, reason, message string)) (bool, sets.Set[string], errutils.ReasonableError) {
3130
updatedAccessRequests, rerr := r.createOrUpdateDesiredAccessRequests(ctx, mcp, cr, createCon)
3231
if rerr != nil {
33-
return false, rerr
32+
return false, nil, rerr
3433
}
3534

3635
accessRequestsInDeletion, rerr := r.deleteUndesiredAccessRequests(ctx, mcp, updatedAccessRequests, createCon)
3736
if rerr != nil {
38-
return false, rerr
37+
return false, nil, rerr
3938
}
4039

4140
allAccessReady, rerr := r.syncAccessSecrets(ctx, mcp, updatedAccessRequests, createCon)
4241
if rerr != nil {
43-
return false, rerr
42+
return false, nil, rerr
4443
}
4544

4645
accessSecretsInDeletion, rerr := r.deleteUndesiredAccessSecrets(ctx, mcp, updatedAccessRequests, createCon)
4746
if rerr != nil {
48-
return false, rerr
47+
return false, nil, rerr
4948
}
5049

5150
// remove conditions for AccessRequests that are neither required nor in deletion (= have been deleted already)
52-
cu := conditions.ConditionUpdater(mcp.Status.Conditions, false).WithEventRecorder(r.eventRecorder, conditions.EventPerChange)
51+
removeConditions := sets.New[string]()
5352
for _, con := range mcp.Status.Conditions {
5453
if !strings.HasPrefix(con.Type, corev2alpha1.ConditionPrefixOIDCAccessReady) {
5554
continue
5655
}
5756
providerName := strings.TrimPrefix(con.Type, corev2alpha1.ConditionPrefixOIDCAccessReady)
5857
if _, ok := updatedAccessRequests[providerName]; !ok && !accessRequestsInDeletion.Has(providerName) {
59-
cu.RemoveCondition(corev2alpha1.ConditionPrefixOIDCAccessReady + providerName)
58+
removeConditions.Insert(con.Type)
6059
}
6160
}
62-
mcp.Status.Conditions, _ = cu.Record(mcp).Conditions()
6361

6462
everythingReady := accessRequestsInDeletion.Len() == 0 && accessSecretsInDeletion.Len() == 0 && allAccessReady
6563
if everythingReady {
@@ -68,7 +66,7 @@ func (r *ManagedControlPlaneReconciler) manageAccessRequests(ctx context.Context
6866
createCon(corev2alpha1.ConditionAllAccessReady, metav1.ConditionFalse, cconst.ReasonWaitingForAccessRequest, "Not all accesses are ready")
6967
}
7068

71-
return everythingReady, nil
69+
return everythingReady, removeConditions, nil
7270
}
7371

7472
// createOrUpdateDesiredAccessRequests creates/updates all AccessRequests that are desired according to the ManagedControlPlane's configured OIDC providers.
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package managedcontrolplane
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
9+
"k8s.io/apimachinery/pkg/util/sets"
10+
"sigs.k8s.io/controller-runtime/pkg/client"
11+
12+
errutils "github.com/openmcp-project/controller-utils/pkg/errors"
13+
"github.com/openmcp-project/controller-utils/pkg/logging"
14+
15+
clustersv1alpha1 "github.com/openmcp-project/openmcp-operator/api/clusters/v1alpha1"
16+
cconst "github.com/openmcp-project/openmcp-operator/api/clusters/v1alpha1/constants"
17+
corev2alpha1 "github.com/openmcp-project/openmcp-operator/api/core/v2alpha1"
18+
libutils "github.com/openmcp-project/openmcp-operator/lib/utils"
19+
)
20+
21+
func (r *ManagedControlPlaneReconciler) deleteRelatedClusterRequests(ctx context.Context, mcp *corev2alpha1.ManagedControlPlane) (sets.Set[string], errutils.ReasonableError) {
22+
log := logging.FromContextOrPanic(ctx)
23+
24+
// delete depending cluster requests, if any
25+
crNames := sets.New[string]()
26+
27+
if mcp == nil {
28+
log.Debug("MCP is nil, no need to check for cluster requests")
29+
return crNames, nil
30+
}
31+
32+
// identify cluster request finalizers
33+
for _, fin := range mcp.Finalizers {
34+
if strings.HasPrefix(fin, corev2alpha1.ClusterRequestFinalizerPrefix) {
35+
crNames.Insert(strings.TrimPrefix(fin, corev2alpha1.ClusterRequestFinalizerPrefix))
36+
}
37+
}
38+
39+
if crNames.Len() == 0 {
40+
log.Debug("No cluster request finalizers found on MCP")
41+
return crNames, nil
42+
}
43+
44+
// fetch cluster requests, if any exist
45+
namespace := libutils.StableRequestNamespace(mcp.Namespace)
46+
resources := map[string]*clustersv1alpha1.ClusterRequest{}
47+
errs := errutils.NewReasonableErrorList()
48+
for crName := range crNames {
49+
cr := &clustersv1alpha1.ClusterRequest{}
50+
cr.SetName(crName)
51+
cr.SetNamespace(namespace)
52+
if err := r.PlatformCluster.Client().Get(ctx, client.ObjectKeyFromObject(cr), cr); err != nil {
53+
if !apierrors.IsNotFound(err) {
54+
errs.Append(errutils.WithReason(fmt.Errorf("error getting ClusterRequest '%s/%s': %w", namespace, crName, err), cconst.ReasonPlatformClusterInteractionProblem))
55+
}
56+
continue
57+
}
58+
resources[crName] = cr
59+
}
60+
if rerr := errs.Aggregate(); rerr != nil {
61+
return sets.KeySet(resources), rerr
62+
}
63+
64+
// delete cluster requests
65+
errs = errutils.NewReasonableErrorList()
66+
for crName, cr := range resources {
67+
if crName == mcp.Name && len(resources) > 1 {
68+
// skip the MCP's main ClusterRequest for now
69+
// we want to make sure that all other ClusterRequests are deleted first
70+
// in case the corresponding clusters are hosting resources that depend on the MCP cluster
71+
log.Debug("Skipping deletion of MCP's primary ClusterRequest, because there are other ClusterRequests to delete first", "crName", crName, "namespace", cr.GetNamespace())
72+
continue
73+
}
74+
if !cr.GetDeletionTimestamp().IsZero() {
75+
log.Debug("ClusterRequest resource already marked for deletion", "crName", crName, "namespace", cr.GetNamespace())
76+
continue
77+
}
78+
log.Info("Deleting ClusterRequest", "crName", crName, "namespace", cr.GetNamespace())
79+
if err := r.PlatformCluster.Client().Delete(ctx, cr); err != nil {
80+
if !apierrors.IsNotFound(err) {
81+
errs.Append(errutils.WithReason(fmt.Errorf("error deleting ClusterRequest '%s/%s': %w", namespace, crName, err), cconst.ReasonPlatformClusterInteractionProblem))
82+
} else {
83+
log.Debug("ClusterRequest not found during deletion", "crName", crName, "namespace", cr.GetNamespace())
84+
delete(resources, crName) // remove from resources if not found
85+
}
86+
}
87+
}
88+
if rerr := errs.Aggregate(); rerr != nil {
89+
return sets.KeySet(resources), rerr
90+
}
91+
92+
return sets.KeySet(resources), nil
93+
}

0 commit comments

Comments
 (0)