Skip to content

Commit 7a096f9

Browse files
authored
CLOUDP-148453: Add finalizer to teams CRs (#830)
* Use finalizer to prevent removal of assigned teams CR
1 parent 5884b3f commit 7a096f9

File tree

4 files changed

+81
-65
lines changed

4 files changed

+81
-65
lines changed

pkg/controller/atlasdeployment/atlasdeployment_controller.go

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,6 @@ import (
4949
"github.com/mongodb/mongodb-atlas-kubernetes/pkg/util/kube"
5050
)
5151

52-
const (
53-
finalizer = "mongodbatlas/finalizer"
54-
)
55-
5652
// AtlasDeploymentReconciler reconciles an AtlasDeployment object
5753
type AtlasDeploymentReconciler struct {
5854
watch.ResourceWatcher
@@ -148,13 +144,13 @@ func (r *AtlasDeploymentReconciler) Reconcile(context context.Context, req ctrl.
148144
r.verifyNonTenantCase(deployment)
149145

150146
if deployment.GetDeletionTimestamp().IsZero() {
151-
if !haveFinalizer(deployment, finalizer) {
147+
if !customresource.HaveFinalizer(deployment, customresource.FinalizerLabel) {
152148
err = r.Client.Get(context, kube.ObjectKeyFromObject(deployment), deployment)
153149
if err != nil {
154150
result = workflow.Terminate(workflow.Internal, err.Error())
155151
return result.ReconcileResult(), nil
156152
}
157-
deployment.SetFinalizers(append(deployment.GetFinalizers(), finalizer))
153+
customresource.SetFinalizer(deployment, customresource.FinalizerLabel)
158154
if err = r.Client.Update(context, deployment); err != nil {
159155
result = workflow.Terminate(workflow.Internal, err.Error())
160156
log.Errorw("Failed to add finalizer", "error", err)
@@ -164,7 +160,7 @@ func (r *AtlasDeploymentReconciler) Reconcile(context context.Context, req ctrl.
164160
}
165161

166162
if !deployment.GetDeletionTimestamp().IsZero() {
167-
if haveFinalizer(deployment, finalizer) {
163+
if customresource.HaveFinalizer(deployment, customresource.FinalizerLabel) {
168164
if customresource.ResourceShouldBeLeftInAtlas(deployment) {
169165
log.Infof("Not removing Atlas Deployment from Atlas as the '%s' annotation is set", customresource.ResourcePolicyAnnotation)
170166
} else {
@@ -202,15 +198,6 @@ func (r *AtlasDeploymentReconciler) Reconcile(context context.Context, req ctrl.
202198
return workflow.OK().ReconcileResult(), nil
203199
}
204200

205-
func haveFinalizer(deployment *mdbv1.AtlasDeployment, finalizer string) bool {
206-
for _, f := range deployment.Finalizers {
207-
if f == finalizer {
208-
return true
209-
}
210-
}
211-
return false
212-
}
213-
214201
func (r *AtlasDeploymentReconciler) verifyNonTenantCase(deployment *mdbv1.AtlasDeployment) {
215202
var pSettings *mdbv1.ProviderSettingsSpec
216203
var deploymentType string
@@ -598,21 +585,12 @@ func (r *AtlasDeploymentReconciler) removeDeletionFinalizer(context context.Cont
598585
if err != nil {
599586
return fmt.Errorf("cannot get AtlasDeployment while adding finalizer: %w", err)
600587
}
601-
deployment.Finalizers = removeString(deployment.Finalizers, finalizer)
588+
589+
customresource.UnsetFinalizer(deployment, customresource.FinalizerLabel)
602590
if err = r.Client.Update(context, deployment); err != nil {
603591
return fmt.Errorf("failed to remove deletion finalizer from %s: %w", deployment.GetDeploymentName(), err)
604592
}
605593
return nil
606594
}
607595

608-
func removeString(slice []string, s string) (result []string) {
609-
for _, item := range slice {
610-
if item == s {
611-
continue
612-
}
613-
result = append(result, item)
614-
}
615-
return result
616-
}
617-
618596
type deploymentHandlerFunc func(ctx *workflow.Context, project *mdbv1.AtlasProject, deployment *mdbv1.AtlasDeployment, req reconcile.Request) (workflow.Result, error)

pkg/controller/atlasproject/atlasproject_controller.go

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -181,16 +181,16 @@ func (r *AtlasProjectReconciler) ensureDeletionFinalizer(ctx *workflow.Context,
181181
log := ctx.Log
182182

183183
if project.GetDeletionTimestamp().IsZero() {
184-
if !isDeletionFinalizerPresent(project) {
185-
log.Debugw("Add deletion finalizer", "name", getFinalizerName())
184+
if !customresource.HaveFinalizer(project, customresource.FinalizerLabel) {
185+
log.Debugw("Add deletion finalizer", "name", customresource.FinalizerLabel)
186186
if err := r.addDeletionFinalizer(context, project); err != nil {
187187
return workflow.Terminate(workflow.Internal, err.Error())
188188
}
189189
}
190190
}
191191

192192
if !project.GetDeletionTimestamp().IsZero() {
193-
if isDeletionFinalizerPresent(project) {
193+
if customresource.HaveFinalizer(project, customresource.FinalizerLabel) {
194194
if customresource.ResourceShouldBeLeftInAtlas(project) {
195195
log.Infof("Not removing the Atlas Project from Atlas as the '%s' annotation is set", customresource.ResourcePolicyAnnotation)
196196
} else {
@@ -334,7 +334,7 @@ func (r *AtlasProjectReconciler) addDeletionFinalizer(ctx context.Context, p *md
334334
if err != nil {
335335
return fmt.Errorf("failed to get project before adding deletion finalizer: %w", err)
336336
}
337-
p.Finalizers = append(p.GetFinalizers(), getFinalizerName())
337+
customresource.SetFinalizer(p, customresource.FinalizerLabel)
338338
if err := r.Client.Update(ctx, p); err != nil {
339339
return fmt.Errorf("failed to add deletion finalizer for %s: %w", p.Name, err)
340340
}
@@ -346,38 +346,13 @@ func (r *AtlasProjectReconciler) removeDeletionFinalizer(ctx context.Context, p
346346
if err != nil {
347347
return fmt.Errorf("failed to get project before removing deletion finalizer: %w", err)
348348
}
349-
finalizers := p.GetFinalizers()
350-
finalizers = removeString(finalizers, getFinalizerName())
351-
p.SetFinalizers(finalizers)
349+
customresource.UnsetFinalizer(p, customresource.FinalizerLabel)
352350
if err = r.Client.Update(ctx, p); err != nil {
353351
return fmt.Errorf("failed to remove deletion finalizer from %s: %w", p.Name, err)
354352
}
355353
return nil
356354
}
357355

358-
func getFinalizerName() string {
359-
return "mongodbatlas/finalizer"
360-
}
361-
362-
func isDeletionFinalizerPresent(project *mdbv1.AtlasProject) bool {
363-
for _, finalizer := range project.GetFinalizers() {
364-
if finalizer == getFinalizerName() {
365-
return true
366-
}
367-
}
368-
return false
369-
}
370-
371-
func removeString(slice []string, s string) (result []string) {
372-
for _, item := range slice {
373-
if item == s {
374-
continue
375-
}
376-
result = append(result, item)
377-
}
378-
return result
379-
}
380-
381356
// setCondition sets the condition from the result and logs the warnings
382357
func setCondition(ctx *workflow.Context, condition status.ConditionType, result workflow.Result) {
383358
ctx.SetConditionFromResult(condition, result)

pkg/controller/atlasproject/team_reconciler.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package atlasproject
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"net/http"
78
"sync"
89

@@ -28,13 +29,16 @@ func (r *AtlasProjectReconciler) teamReconcile(
2829
return func(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
2930
log := r.Log.With("atlasteam", req.NamespacedName)
3031

31-
// TODO(helderjs): Add finalizers to avoid delete assigned teams
32-
// TODO(helderjs): Add skip reconciliation annotation
3332
result := customresource.PrepareResource(r.Client, req, team, log)
3433
if !result.IsOk() {
3534
return result.ReconcileResult(), nil
3635
}
3736

37+
if shouldSkip := customresource.ReconciliationShouldBeSkipped(team); shouldSkip {
38+
log.Infow(fmt.Sprintf("-> Skipping AtlasTeam reconciliation as annotation %s=%s", customresource.ReconciliationPolicyAnnotation, customresource.ReconciliationPolicySkip), "spec", team.Spec)
39+
return workflow.OK().ReconcileResult(), nil
40+
}
41+
3842
teamCtx, err := createTeamContextFromParent(team, r.Client, connection, r.AtlasDomain, log)
3943
if err != nil {
4044
teamCtx.SetConditionFalse(status.ReadyType)
@@ -69,13 +73,35 @@ func (r *AtlasProjectReconciler) teamReconcile(
6973
return result.ReconcileResult(), nil
7074
}
7175

76+
if team.GetDeletionTimestamp().IsZero() {
77+
if len(team.Status.Projects) > 0 {
78+
log.Debugw("Adding deletion finalizer", "name", customresource.FinalizerLabel)
79+
customresource.SetFinalizer(team, customresource.FinalizerLabel)
80+
} else {
81+
log.Debugw("Removing deletion finalizer", "name", customresource.FinalizerLabel)
82+
customresource.UnsetFinalizer(team, customresource.FinalizerLabel)
83+
}
84+
85+
if err = r.Client.Update(ctx, team); err != nil {
86+
result = workflow.Terminate(workflow.Internal, err.Error())
87+
log.Errorw("Failed to update finalizer", "error", err)
88+
return result.ReconcileResult(), nil
89+
}
90+
}
91+
7292
if !team.GetDeletionTimestamp().IsZero() {
73-
log.Infow("-> Starting AtlasTeam deletion", "spec", team.Spec)
74-
_, err := teamCtx.Client.Projects.Delete(ctx, team.Status.ID)
75-
var apiError *mongodbatlas.ErrorResponse
76-
if errors.As(err, &apiError) && apiError.ErrorCode == atlas.NotInGroup {
77-
log.Infow("team does not exist", "projectID", team.Status.ID)
78-
return workflow.Terminate(workflow.TeamDoesNotExist, err.Error()).ReconcileResult(), nil
93+
if customresource.HaveFinalizer(team, customresource.FinalizerLabel) {
94+
log.Warnf("team %s is assigned to a project. Remove it from all projects before delete", team.Name)
95+
} else if customresource.ResourceShouldBeLeftInAtlas(team) {
96+
log.Infof("Not removing the Atlas Team from Atlas as the '%s' annotation is set", customresource.ResourcePolicyAnnotation)
97+
} else {
98+
log.Infow("-> Starting AtlasTeam deletion", "spec", team.Spec)
99+
_, err := teamCtx.Client.Teams.RemoveTeamFromOrganization(ctx, teamCtx.Connection.OrgID, team.Status.ID)
100+
var apiError *mongodbatlas.ErrorResponse
101+
if errors.As(err, &apiError) && apiError.ErrorCode == atlas.NotInGroup {
102+
log.Infow("team does not exist", "projectID", team.Status.ID)
103+
return workflow.Terminate(workflow.TeamDoesNotExist, err.Error()).ReconcileResult(), nil
104+
}
79105
}
80106
}
81107

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package customresource
2+
3+
import (
4+
mdbv1 "github.com/mongodb/mongodb-atlas-kubernetes/pkg/api/v1"
5+
)
6+
7+
const FinalizerLabel = "mongodbatlas/finalizer"
8+
9+
func HaveFinalizer(resource mdbv1.AtlasCustomResource, finalizer string) bool {
10+
for _, f := range resource.GetFinalizers() {
11+
if f == finalizer {
12+
return true
13+
}
14+
}
15+
16+
return false
17+
}
18+
19+
// SetFinalizer Add the given finalizer to the list of resource finalizer
20+
func SetFinalizer(resource mdbv1.AtlasCustomResource, finalizer string) {
21+
if !HaveFinalizer(resource, finalizer) {
22+
resource.SetFinalizers(append(resource.GetFinalizers(), finalizer))
23+
}
24+
}
25+
26+
// UnsetFinalizer remove the given finalizer from the list of resource finalizer
27+
func UnsetFinalizer(resource mdbv1.AtlasCustomResource, finalizer string) {
28+
finalizers := make([]string, 0, len(resource.GetFinalizers()))
29+
30+
for _, f := range resource.GetFinalizers() {
31+
if f != finalizer {
32+
finalizers = append(finalizers, f)
33+
}
34+
}
35+
36+
resource.SetFinalizers(finalizers)
37+
}

0 commit comments

Comments
 (0)