Skip to content

Commit 1bf3bf9

Browse files
CLOUDP-297401: Handle x509 just like other project resources (#2084)
Handle x509 just like other project resources
1 parent 569bf04 commit 1bf3bf9

File tree

6 files changed

+109
-24
lines changed

6 files changed

+109
-24
lines changed

api/condition.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const (
5050
ProjectTeamsReadyType ConditionType = "ProjectTeamsReady"
5151
SearchIndexesReadyType ConditionType = "AtlasSearchIndexesReady"
5252
BackupComplianceReadyType ConditionType = "BackupCompliancePolicyReady"
53+
X509AuthReadyType ConditionType = "X509AuthReady"
5354
)
5455

5556
// AtlasDeployment condition types

internal/controller/atlasproject/atlasproject_controller.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,11 @@ func (r *AtlasProjectReconciler) ensureProjectResources(workflowCtx *workflow.Co
244244
}
245245
results = append(results, result)
246246

247+
if result = r.ensureX509(workflowCtx, project); result.IsOk() {
248+
r.EventRecorder.Event(project, "Normal", string(api.X509AuthReadyType), "")
249+
}
250+
results = append(results, result)
251+
247252
return results
248253
}
249254

internal/controller/atlasproject/project.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,13 @@ func (r *AtlasProjectReconciler) handleProject(ctx *workflow.Context, orgID stri
3838
return r.manage(ctx, atlasProject, projectInAtlas.ID)
3939
}
4040

41-
if err = r.ensureX509(ctx, atlasProject); err != nil {
42-
return r.terminate(ctx, workflow.Internal, err)
43-
}
44-
4541
ctx.SetConditionTrue(api.ProjectReadyType)
4642
r.EventRecorder.Event(atlasProject, "Normal", string(api.ProjectReadyType), "")
4743

4844
results := r.ensureProjectResources(ctx, atlasProject, services)
4945
for i := range results {
5046
if !results[i].IsOk() {
5147
logIfWarning(ctx, results[i])
52-
5348
return results[i].ReconcileResult(), nil
5449
}
5550
}

internal/controller/atlasproject/project_test.go

Lines changed: 76 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,74 @@ func TestHandleProject(t *testing.T) {
271271
},
272272
"should fail to configure authentication modes": {
273273
atlasClientMocker: func() *mongodbatlas.Client {
274-
return nil
274+
integrations := &atlasmocks.ThirdPartyIntegrationsClientMock{
275+
ListFunc: func(projectID string) (*mongodbatlas.ThirdPartyIntegrations, *mongodbatlas.Response, error) {
276+
return &mongodbatlas.ThirdPartyIntegrations{}, nil, nil
277+
},
278+
}
279+
encryptionAtRest := &atlasmocks.EncryptionAtRestClientMock{
280+
GetFunc: func(projectID string) (*mongodbatlas.EncryptionAtRest, *mongodbatlas.Response, error) {
281+
return &mongodbatlas.EncryptionAtRest{}, nil, nil
282+
},
283+
}
284+
projectAPI := &atlasmocks.ProjectsClientMock{}
285+
286+
return &mongodbatlas.Client{
287+
Integrations: integrations,
288+
EncryptionsAtRest: encryptionAtRest,
289+
Projects: projectAPI,
290+
}
275291
},
276-
atlasSDKMocker: func() *admin.APIClient {
277-
return nil
292+
atlasSDKMocker: func() *admin.APIClient { //nolint:dupl
293+
ipAccessList := mockadmin.NewProjectIPAccessListApi(t)
294+
ipAccessList.EXPECT().ListProjectIpAccessLists(context.Background(), "projectID").
295+
Return(admin.ListProjectIpAccessListsApiRequest{ApiService: ipAccessList})
296+
ipAccessList.EXPECT().ListProjectIpAccessListsExecute(mock.AnythingOfType("admin.ListProjectIpAccessListsApiRequest")).
297+
Return(nil, nil, nil)
298+
privateEndpoints := mockadmin.NewPrivateEndpointServicesApi(t)
299+
privateEndpoints.EXPECT().ListPrivateEndpointServices(context.Background(), "projectID", mock.Anything).
300+
Return(admin.ListPrivateEndpointServicesApiRequest{ApiService: privateEndpoints})
301+
privateEndpoints.EXPECT().ListPrivateEndpointServicesExecute(mock.AnythingOfType("admin.ListPrivateEndpointServicesApiRequest")).
302+
Return(nil, nil, nil)
303+
networkPeering := mockadmin.NewNetworkPeeringApi(t)
304+
networkPeering.EXPECT().ListPeeringConnectionsWithParams(context.Background(), mock.AnythingOfType("*admin.ListPeeringConnectionsApiParams")).
305+
Return(admin.ListPeeringConnectionsApiRequest{ApiService: networkPeering})
306+
networkPeering.EXPECT().ListPeeringConnectionsExecute(mock.AnythingOfType("admin.ListPeeringConnectionsApiRequest")).
307+
Return(nil, nil, nil)
308+
networkPeering.EXPECT().ListPeeringContainers(context.Background(), "projectID").
309+
Return(admin.ListPeeringContainersApiRequest{ApiService: networkPeering})
310+
networkPeering.EXPECT().ListPeeringContainersExecute(mock.AnythingOfType("admin.ListPeeringContainersApiRequest")).
311+
Return(nil, nil, nil)
312+
audit := mockadmin.NewAuditingApi(t)
313+
audit.EXPECT().GetAuditingConfiguration(context.Background(), "projectID").
314+
Return(admin.GetAuditingConfigurationApiRequest{ApiService: audit})
315+
audit.EXPECT().GetAuditingConfigurationExecute(mock.AnythingOfType("admin.GetAuditingConfigurationApiRequest")).
316+
Return(nil, nil, nil)
317+
customRoles := mockadmin.NewCustomDatabaseRolesApi(t)
318+
customRoles.EXPECT().ListCustomDatabaseRoles(context.Background(), "projectID").
319+
Return(admin.ListCustomDatabaseRolesApiRequest{ApiService: customRoles})
320+
customRoles.EXPECT().ListCustomDatabaseRolesExecute(mock.AnythingOfType("admin.ListCustomDatabaseRolesApiRequest")).
321+
Return(nil, nil, nil)
322+
projectAPI := mockadmin.NewProjectsApi(t)
323+
projectAPI.EXPECT().GetProjectSettings(context.Background(), "projectID").
324+
Return(admin.GetProjectSettingsApiRequest{ApiService: projectAPI})
325+
projectAPI.EXPECT().GetProjectSettingsExecute(mock.AnythingOfType("admin.GetProjectSettingsApiRequest")).
326+
Return(admin.NewGroupSettings(), nil, nil)
327+
backup := mockadmin.NewCloudBackupsApi(t)
328+
backup.EXPECT().GetDataProtectionSettings(context.Background(), "projectID").
329+
Return(admin.GetDataProtectionSettingsApiRequest{ApiService: backup})
330+
backup.EXPECT().GetDataProtectionSettingsExecute(mock.AnythingOfType("admin.GetDataProtectionSettingsApiRequest")).
331+
Return(nil, nil, nil)
332+
333+
return &admin.APIClient{
334+
ProjectIPAccessListApi: ipAccessList,
335+
PrivateEndpointServicesApi: privateEndpoints,
336+
NetworkPeeringApi: networkPeering,
337+
AuditingApi: audit,
338+
CustomDatabaseRolesApi: customRoles,
339+
ProjectsApi: projectAPI,
340+
CloudBackupsApi: backup,
341+
}
278342
},
279343
projectServiceMocker: func() project.ProjectService {
280344
service := translation.NewProjectServiceMock(t)
@@ -284,10 +348,14 @@ func TestHandleProject(t *testing.T) {
284348
return service
285349
},
286350
teamServiceMocker: func() teams.TeamsService {
287-
return nil
351+
service := translation.NewTeamsServiceMock(t)
352+
service.EXPECT().ListProjectTeams(context.Background(), mock.Anything).Return([]teams.AssignedTeam{}, nil)
353+
return service
288354
},
289355
encryptionAtRestMocker: func() encryptionatrest.EncryptionAtRestService {
290-
return nil
356+
service := translation.NewEncryptionAtRestServiceMock(t)
357+
service.EXPECT().Get(context.Background(), mock.Anything).Return(nil, nil)
358+
return service
291359
},
292360
project: &akov2.AtlasProject{
293361
ObjectMeta: metav1.ObjectMeta{
@@ -303,10 +371,10 @@ func TestHandleProject(t *testing.T) {
303371
ID: "projectID",
304372
},
305373
},
306-
result: reconcile.Result{RequeueAfter: workflow.DefaultRetry},
374+
result: reconcile.Result{RequeueAfter: workflow.DefaultRetry, Requeue: false},
307375
conditions: []api.Condition{
308-
api.FalseCondition(api.ProjectReadyType).
309-
WithReason(string(workflow.Internal)).
376+
api.TrueCondition(api.ProjectReadyType),
377+
api.FalseCondition(api.X509AuthReadyType).
310378
WithMessageRegexp("secrets \"invalid-ref\" not found"),
311379
},
312380
finalizers: []string{customresource.FinalizerLabel},

internal/controller/atlasproject/x509_auth.go

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"fmt"
88
"strings"
99

10+
"github.com/mongodb/mongodb-atlas-kubernetes/v2/api"
11+
1012
"go.mongodb.org/atlas-sdk/v20231115008/admin"
1113
"go.uber.org/zap"
1214
corev1 "k8s.io/api/core/v1"
@@ -18,7 +20,21 @@ import (
1820
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/workflow"
1921
)
2022

21-
func (r *AtlasProjectReconciler) ensureX509(ctx *workflow.Context, atlasProject *akov2.AtlasProject) error {
23+
func terminateX509(workflowCtx *workflow.Context, err error) workflow.Result {
24+
workflowCtx.SetConditionFalseMsg(api.X509AuthReadyType, err.Error())
25+
return workflow.Terminate(workflow.ProjectX509NotConfigured, err)
26+
}
27+
28+
func emptyX509(workflowCtx *workflow.Context) workflow.Result {
29+
workflowCtx.UnsetCondition(api.X509AuthReadyType)
30+
return idleX509()
31+
}
32+
33+
func idleX509() workflow.Result {
34+
return workflow.OK()
35+
}
36+
37+
func (r *AtlasProjectReconciler) ensureX509(ctx *workflow.Context, atlasProject *akov2.AtlasProject) workflow.Result {
2238
atlasProject.Status.AuthModes.AddAuthMode(authmode.Scram)
2339

2440
hasAuthModesX509 := atlasProject.Status.AuthModes.CheckAuthMode(authmode.X509)
@@ -32,19 +48,18 @@ func (r *AtlasProjectReconciler) ensureX509(ctx *workflow.Context, atlasProject
3248
default:
3349
ctx.EnsureStatusOption(status.AtlasProjectAuthModesOption(atlasProject.Status.AuthModes))
3450
}
35-
36-
return nil
51+
return idleX509()
3752
}
3853

39-
func (r *AtlasProjectReconciler) enableX509Authentication(ctx *workflow.Context, atlasProject *akov2.AtlasProject) error {
54+
func (r *AtlasProjectReconciler) enableX509Authentication(ctx *workflow.Context, atlasProject *akov2.AtlasProject) workflow.Result {
4055
specCert, err := readX509CertFromSecret(ctx.Context, r.Client, *atlasProject.X509SecretObjectKey(), r.Log)
4156
if err != nil {
42-
return err
57+
return terminateX509(ctx, err)
4358
}
4459

4560
ldapConfig, _, err := ctx.SdkClient.LDAPConfigurationApi.GetLDAPConfiguration(ctx.Context, atlasProject.ID()).Execute()
4661
if err != nil {
47-
return err
62+
return terminateX509(ctx, err)
4863
}
4964

5065
customerX509 := ldapConfig.GetCustomerX509()
@@ -58,27 +73,27 @@ func (r *AtlasProjectReconciler) enableX509Authentication(ctx *workflow.Context,
5873

5974
_, _, err = ctx.SdkClient.LDAPConfigurationApi.SaveLDAPConfiguration(ctx.Context, atlasProject.ID(), &conf).Execute()
6075
if err != nil {
61-
return err
76+
return terminateX509(ctx, err)
6277
}
6378
}
6479

6580
atlasProject.Status.AuthModes.AddAuthMode(authmode.X509)
6681
ctx.EnsureStatusOption(status.AtlasProjectAuthModesOption(atlasProject.Status.AuthModes))
6782

68-
return nil
83+
return idleX509()
6984
}
7085

71-
func (r *AtlasProjectReconciler) disableX509Authentication(ctx *workflow.Context, atlasProject *akov2.AtlasProject) error {
86+
func (r *AtlasProjectReconciler) disableX509Authentication(ctx *workflow.Context, atlasProject *akov2.AtlasProject) workflow.Result {
7287
r.Log.Infow("Disable x509 auth", "projectID", atlasProject.ID())
7388
_, _, err := ctx.SdkClient.X509AuthenticationApi.DisableCustomerManagedX509(ctx.Context, atlasProject.ID()).Execute()
7489
if err != nil {
75-
return err
90+
return terminateX509(ctx, err)
7691
}
7792

7893
atlasProject.Status.AuthModes.RemoveAuthMode(authmode.X509)
7994
ctx.EnsureStatusOption(status.AtlasProjectAuthModesOption(atlasProject.Status.AuthModes))
8095

81-
return nil
96+
return emptyX509(ctx)
8297
}
8398

8499
func readX509CertFromSecret(ctx context.Context, kubeClient client.Client, secretRef client.ObjectKey, log *zap.SugaredLogger) (string, error) {

internal/controller/workflow/reason.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const (
4444
ProjectAlertConfigurationIsNotReadyInAtlas ConditionReason = "ProjectAlertConfigurationIsNotReadyInAtlas"
4545
ProjectCustomRolesReady ConditionReason = "ProjectCustomRolesReady"
4646
ProjectTeamUnavailable ConditionReason = "ProjectTeamUnavailable"
47+
ProjectX509NotConfigured ConditionReason = "ProjectX509NotConfigured"
4748
)
4849

4950
// Atlas Backup Compliance Policy reasons

0 commit comments

Comments
 (0)