Skip to content

Commit 39a3e3e

Browse files
authored
CLOUDP-278387: Add index for dbUser by project and improve connection secret generation (#1860)
1 parent 94ecc3e commit 39a3e3e

File tree

7 files changed

+245
-40
lines changed

7 files changed

+245
-40
lines changed

pkg/controller/atlasdeployment/advanced_deployment.go

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package atlasdeployment
22

33
import (
4-
"context"
54
"fmt"
65
"reflect"
76
"strings"
87

98
v1 "k8s.io/api/core/v1"
9+
"k8s.io/apimachinery/pkg/fields"
1010
ctrl "sigs.k8s.io/controller-runtime"
1111
"sigs.k8s.io/controller-runtime/pkg/client"
1212

@@ -19,6 +19,7 @@ import (
1919
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/connectionsecret"
2020
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/customresource"
2121
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/workflow"
22+
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/indexer"
2223
)
2324

2425
const FreeTier = "M0"
@@ -112,13 +113,17 @@ func (r *AtlasDeploymentReconciler) handleAdvancedDeployment(ctx *workflow.Conte
112113
}
113114

114115
func (r *AtlasDeploymentReconciler) ensureConnectionSecrets(ctx *workflow.Context, deploymentInAKO deployment.Deployment, connection *status.ConnectionStrings) error {
115-
dbUsers, err := r.getProjectDatabaseUsers(ctx.Context, deploymentInAKO.GetProjectID())
116+
databaseUsers := &akov2.AtlasDatabaseUserList{}
117+
listOpts := &client.ListOptions{
118+
FieldSelector: fields.OneTermEqualSelector(indexer.AtlasDatabaseUserByProject, deploymentInAKO.GetProjectID()),
119+
}
120+
err := r.Client.List(ctx.Context, databaseUsers, listOpts)
116121
if err != nil {
117122
return err
118123
}
119124

120125
secrets := make([]string, 0)
121-
for _, dbUser := range dbUsers {
126+
for _, dbUser := range databaseUsers.Items {
122127
found := false
123128
for _, c := range dbUser.Status.Conditions {
124129
if c.Type == api.ReadyType && c.Status == v1.ConditionTrue {
@@ -204,33 +209,3 @@ func (r *AtlasDeploymentReconciler) ensureAdvancedOptions(ctx *workflow.Context,
204209

205210
return nil
206211
}
207-
208-
func (r *AtlasDeploymentReconciler) getProjectDatabaseUsers(ctx context.Context, projectID string) ([]*akov2.AtlasDatabaseUser, error) {
209-
databaseUsers := &akov2.AtlasDatabaseUserList{}
210-
err := r.Client.List(ctx, databaseUsers, &client.ListOptions{})
211-
if err != nil {
212-
return nil, err
213-
}
214-
215-
result := make([]*akov2.AtlasDatabaseUser, 0, len(databaseUsers.Items))
216-
for _, dbUser := range databaseUsers.Items {
217-
switch {
218-
// if external reference and refer to same project as deployment, append
219-
case dbUser.Spec.ExternalProjectRef != nil && dbUser.Spec.ExternalProjectRef.ID == projectID:
220-
result = append(result, &dbUser)
221-
// if internal reference and project resource is the same of the deployment, append
222-
case dbUser.Spec.Project != nil:
223-
atlasProject := &akov2.AtlasProject{}
224-
err = r.Client.Get(ctx, *dbUser.Spec.Project.GetObject(dbUser.Namespace), atlasProject)
225-
if err != nil {
226-
return nil, err
227-
}
228-
229-
if atlasProject.ID() == projectID {
230-
result = append(result, &dbUser)
231-
}
232-
}
233-
}
234-
235-
return result, nil
236-
}

pkg/controller/atlasdeployment/atlasdeployment_controller_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,17 +366,20 @@ func TestRegularClusterReconciliation(t *testing.T) {
366366
}
367367
d.Spec.DeploymentSpec.SearchNodes = searchNodes
368368

369+
ctx := context.Background()
369370
logger := zaptest.NewLogger(t)
370371

371372
sch := runtime.NewScheme()
372373
require.NoError(t, akov2.AddToScheme(sch))
373374
require.NoError(t, corev1.AddToScheme(sch))
375+
dbUserProjectIndexer := indexer.NewAtlasDatabaseUserByProjectIndexer(ctx, nil, logger)
374376
// Subresources need to be explicitly set now since controller-runtime 1.15
375377
// https://github.com/kubernetes-sigs/controller-runtime/issues/2362#issuecomment-1698194188
376378
k8sClient := fake.NewClientBuilder().
377379
WithScheme(sch).
378380
WithObjects(secret, project, bPolicy, bSchedule, d).
379381
WithStatusSubresource(bPolicy, bSchedule).
382+
WithIndex(dbUserProjectIndexer.Object(), dbUserProjectIndexer.Name(), dbUserProjectIndexer.Keys).
380383
Build()
381384

382385
orgID := "0987654321"
@@ -535,7 +538,7 @@ func TestRegularClusterReconciliation(t *testing.T) {
535538

536539
t.Run("should reconcile with existing cluster", func(t *testing.T) {
537540
result, err := reconciler.Reconcile(
538-
context.Background(),
541+
ctx,
539542
ctrl.Request{
540543
NamespacedName: types.NamespacedName{
541544
Namespace: d.Namespace,
@@ -549,6 +552,7 @@ func TestRegularClusterReconciliation(t *testing.T) {
549552
}
550553

551554
func TestServerlessInstanceReconciliation(t *testing.T) {
555+
ctx := context.Background()
552556
secret := &corev1.Secret{
553557
ObjectMeta: metav1.ObjectMeta{
554558
Name: "api-secret",
@@ -585,11 +589,13 @@ func TestServerlessInstanceReconciliation(t *testing.T) {
585589
sch := runtime.NewScheme()
586590
require.NoError(t, akov2.AddToScheme(sch))
587591
require.NoError(t, corev1.AddToScheme(sch))
592+
dbUserProjectIndexer := indexer.NewAtlasDatabaseUserByProjectIndexer(ctx, nil, logger)
588593
// Subresources need to be explicitly set now since controller-runtime 1.15
589594
// https://github.com/kubernetes-sigs/controller-runtime/issues/2362#issuecomment-1698194188
590595
k8sClient := fake.NewClientBuilder().
591596
WithScheme(sch).
592597
WithObjects(secret, project, d).
598+
WithIndex(dbUserProjectIndexer.Object(), dbUserProjectIndexer.Name(), dbUserProjectIndexer.Keys).
593599
Build()
594600

595601
orgID := "0987654321"
@@ -660,7 +666,7 @@ func TestServerlessInstanceReconciliation(t *testing.T) {
660666

661667
t.Run("should reconcile with existing serverless instance", func(t *testing.T) {
662668
result, err := reconciler.Reconcile(
663-
context.Background(),
669+
ctx,
664670
ctrl.Request{
665671
NamespacedName: types.NamespacedName{
666672
Namespace: d.Namespace,

pkg/controller/atlasdeployment/serverless_deployment_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common"
2727
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/provider"
2828
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/workflow"
29+
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/indexer"
2930
)
3031

3132
func TestHandleServerlessInstance(t *testing.T) {
@@ -779,33 +780,36 @@ func TestHandleServerlessInstance(t *testing.T) {
779780

780781
for name, tt := range tests {
781782
t.Run(name, func(t *testing.T) {
783+
ctx := context.Background()
782784
logger := zaptest.NewLogger(t)
783785
testScheme := runtime.NewScheme()
784786
require.NoError(t, akov2.AddToScheme(testScheme))
787+
dbUserProjectIndexer := indexer.NewAtlasDatabaseUserByProjectIndexer(ctx, nil, logger)
785788
k8sClient := fake.NewClientBuilder().
786789
WithScheme(testScheme).
787790
WithObjects(tt.atlasDeployment).
791+
WithIndex(dbUserProjectIndexer.Object(), dbUserProjectIndexer.Name(), dbUserProjectIndexer.Keys).
788792
Build()
789793
reconciler := &AtlasDeploymentReconciler{
790794
Client: k8sClient,
791795
Log: logger.Sugar(),
792796
deploymentService: tt.deploymentService(),
793797
}
794-
ctx := &workflow.Context{
795-
Context: context.Background(),
798+
workflowCtx := &workflow.Context{
799+
Context: ctx,
796800
Log: logger.Sugar(),
797801
SdkClient: tt.sdkMock(),
798802
}
799803

800804
deploymentInAKO := deployment.NewDeployment("project-id", tt.atlasDeployment).(*deployment.Serverless)
801-
result, err := reconciler.handleServerlessInstance(ctx, deploymentInAKO, tt.deploymentInAtlas)
805+
result, err := reconciler.handleServerlessInstance(workflowCtx, deploymentInAKO, tt.deploymentInAtlas)
802806
require.NoError(t, err)
803807
assert.Equal(t, tt.expectedResult, result)
804808
assert.True(
805809
t,
806810
cmp.Equal(
807811
tt.expectedConditions,
808-
ctx.Conditions(),
812+
workflowCtx.Conditions(),
809813
cmpopts.IgnoreFields(api.Condition{}, "LastTransitionTime"),
810814
),
811815
)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package indexer
2+
3+
import (
4+
"context"
5+
6+
"go.uber.org/zap"
7+
"sigs.k8s.io/controller-runtime/pkg/client"
8+
9+
akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1"
10+
)
11+
12+
const (
13+
AtlasDatabaseUserByProject = "atlasdatabaseuser.spec.projectRef,externalProjectID"
14+
)
15+
16+
type AtlasDatabaseUserByProjectIndexer struct {
17+
ctx context.Context
18+
client client.Client
19+
logger *zap.SugaredLogger
20+
}
21+
22+
func NewAtlasDatabaseUserByProjectIndexer(ctx context.Context, client client.Client, logger *zap.Logger) *AtlasDatabaseUserByProjectIndexer {
23+
return &AtlasDatabaseUserByProjectIndexer{
24+
ctx: ctx,
25+
client: client,
26+
logger: logger.Named(AtlasDatabaseUserByProject).Sugar(),
27+
}
28+
}
29+
30+
func (*AtlasDatabaseUserByProjectIndexer) Object() client.Object {
31+
return &akov2.AtlasDatabaseUser{}
32+
}
33+
34+
func (*AtlasDatabaseUserByProjectIndexer) Name() string {
35+
return AtlasDatabaseUserByProject
36+
}
37+
38+
func (a *AtlasDatabaseUserByProjectIndexer) Keys(object client.Object) []string {
39+
user, ok := object.(*akov2.AtlasDatabaseUser)
40+
if !ok {
41+
a.logger.Errorf("expected *v1.AtlasDatabaseUser but got %T", object)
42+
return nil
43+
}
44+
45+
if user.Spec.ExternalProjectRef != nil && user.Spec.ExternalProjectRef.ID != "" {
46+
return []string{user.Spec.ExternalProjectRef.ID}
47+
}
48+
49+
if user.Spec.Project != nil && user.Spec.Project.Name != "" {
50+
project := &akov2.AtlasProject{}
51+
err := a.client.Get(a.ctx, *user.Spec.Project.GetObject(user.Namespace), project)
52+
if err != nil {
53+
a.logger.Errorf("unable to find project to index: %s", err)
54+
55+
return nil
56+
}
57+
58+
if project.ID() != "" {
59+
return []string{project.ID()}
60+
}
61+
}
62+
63+
return nil
64+
}

0 commit comments

Comments
 (0)