Skip to content

Commit 4692512

Browse files
authored
CLOUDP-267957: Deployment independent resource (#1773)
1 parent 405d4cf commit 4692512

22 files changed

+1010
-383
lines changed

config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ spec:
6767
required:
6868
- name
6969
type: object
70+
connectionSecret:
71+
description: LocalObjectReference is a reference to an object in the
72+
same namespace as the referent
73+
properties:
74+
name:
75+
description: |-
76+
Name of the resource being referred to
77+
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
78+
type: string
79+
required:
80+
- name
81+
type: object
7082
deploymentSpec:
7183
description: Configuration for the advanced (v1.5) deployment API
7284
https://www.mongodb.com/docs/atlas/reference/api/clusters/
@@ -605,6 +617,16 @@ spec:
605617
required:
606618
- name
607619
type: object
620+
externalProjectRef:
621+
description: ExternalProjectRef holds the Atlas project ID the user
622+
belongs to
623+
properties:
624+
id:
625+
description: ID is the Atlas project ID
626+
type: string
627+
required:
628+
- id
629+
type: object
608630
processArgs:
609631
description: ProcessArgs allows to modify Advanced Configuration Options
610632
properties:
@@ -822,9 +844,16 @@ spec:
822844
- name
823845
- providerSettings
824846
type: object
825-
required:
826-
- projectRef
827847
type: object
848+
x-kubernetes-validations:
849+
- message: must define only one project reference through externalProjectRef
850+
or projectRef
851+
rule: (has(self.externalProjectRef) && !has(self.projectRef)) || (!has(self.externalProjectRef)
852+
&& has(self.projectRef))
853+
- message: must define a local connection secret when referencing an external
854+
project
855+
rule: (has(self.externalProjectRef) && has(self.connectionSecret)) ||
856+
!has(self.externalProjectRef)
828857
status:
829858
description: AtlasDeploymentStatus defines the observed state of AtlasDeployment.
830859
properties:

pkg/api/v1/atlasdatabaseuser_types.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,20 @@ func (p *AtlasDatabaseUser) WithDeleteAfterDate(date string) *AtlasDatabaseUser
300300
return p
301301
}
302302

303+
func (p *AtlasDatabaseUser) WithExternaLProject(projectID, credentialsName string) *AtlasDatabaseUser {
304+
p.Spec.Project = nil
305+
p.Spec.ExternalProjectRef = &ExternalProjectReference{
306+
ID: projectID,
307+
}
308+
p.Spec.LocalCredentialHolder = api.LocalCredentialHolder{
309+
ConnectionSecret: &api.LocalObjectReference{
310+
Name: credentialsName,
311+
},
312+
}
313+
314+
return p
315+
}
316+
303317
func (p AtlasDatabaseUser) Credentials() *api.LocalObjectReference {
304318
return p.Spec.Credentials()
305319
}
Lines changed: 13 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,22 @@
1-
package v1
1+
package v1 // nolint: dupl
22

33
import (
44
"testing"
55

6-
"github.com/stretchr/testify/assert"
7-
"github.com/stretchr/testify/require"
8-
"k8s.io/apimachinery/pkg/runtime"
9-
106
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api"
117
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common"
12-
"github.com/mongodb/mongodb-atlas-kubernetes/v2/test/helper/cel"
138
)
149

1510
func TestProjectReference(t *testing.T) {
16-
validator, err := cel.VersionValidatorFromFile(t, "../../../config/crd/bases/atlas.mongodb.com_atlasdatabaseusers.yaml", "v1")
17-
require.NoError(t, err)
18-
19-
tests := map[string]struct {
20-
dbUser *AtlasDatabaseUser
21-
expectedErrors []string
22-
}{
11+
tests := projectReferenceTestCase{
2312
"no project reference is set": {
24-
dbUser: &AtlasDatabaseUser{
13+
object: &AtlasDatabaseUser{
2514
Spec: AtlasDatabaseUserSpec{},
2615
},
2716
expectedErrors: []string{"spec: Invalid value: \"object\": must define only one project reference through externalProjectRef or projectRef"},
2817
},
2918
"both project references are set": {
30-
dbUser: &AtlasDatabaseUser{
19+
object: &AtlasDatabaseUser{
3120
Spec: AtlasDatabaseUserSpec{
3221
Project: &common.ResourceRefNamespaced{
3322
Name: "my-project",
@@ -43,7 +32,7 @@ func TestProjectReference(t *testing.T) {
4332
},
4433
},
4534
"external project references is set": {
46-
dbUser: &AtlasDatabaseUser{
35+
object: &AtlasDatabaseUser{
4736
Spec: AtlasDatabaseUserSpec{
4837
ExternalProjectRef: &ExternalProjectReference{
4938
ID: "my-project-id",
@@ -55,7 +44,7 @@ func TestProjectReference(t *testing.T) {
5544
},
5645
},
5746
"kubernetes project references is set": {
58-
dbUser: &AtlasDatabaseUser{
47+
object: &AtlasDatabaseUser{
5948
Spec: AtlasDatabaseUserSpec{
6049
Project: &common.ResourceRefNamespaced{
6150
Name: "my-project",
@@ -65,32 +54,13 @@ func TestProjectReference(t *testing.T) {
6554
},
6655
}
6756

68-
for name, tt := range tests {
69-
t.Run(name, func(t *testing.T) {
70-
unstructuredDBUser, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tt.dbUser)
71-
require.NoError(t, err)
72-
73-
errs := validator(unstructuredDBUser, nil)
74-
75-
require.Equal(t, len(tt.expectedErrors), len(errs))
76-
77-
for i, err := range errs {
78-
assert.Equal(t, tt.expectedErrors[i], err.Error())
79-
}
80-
})
81-
}
57+
assertCELValidation(t, "../../../config/crd/bases/atlas.mongodb.com_atlasdatabaseusers.yaml", tests)
8258
}
8359

8460
func TestExternalProjectReferenceConnectionSecret(t *testing.T) {
85-
validator, err := cel.VersionValidatorFromFile(t, "../../../config/crd/bases/atlas.mongodb.com_atlasdatabaseusers.yaml", "v1")
86-
require.NoError(t, err)
87-
88-
tests := map[string]struct {
89-
dbUser *AtlasDatabaseUser
90-
expectedErrors []string
91-
}{
61+
tests := projectReferenceTestCase{
9262
"external project references is set without connection secret": {
93-
dbUser: &AtlasDatabaseUser{
63+
object: &AtlasDatabaseUser{
9464
Spec: AtlasDatabaseUserSpec{
9565
ExternalProjectRef: &ExternalProjectReference{
9666
ID: "my-project-id",
@@ -102,7 +72,7 @@ func TestExternalProjectReferenceConnectionSecret(t *testing.T) {
10272
},
10373
},
10474
"external project references is set with connection secret": {
105-
dbUser: &AtlasDatabaseUser{
75+
object: &AtlasDatabaseUser{
10676
Spec: AtlasDatabaseUserSpec{
10777
ExternalProjectRef: &ExternalProjectReference{
10878
ID: "my-project-id",
@@ -116,7 +86,7 @@ func TestExternalProjectReferenceConnectionSecret(t *testing.T) {
11686
},
11787
},
11888
"kubernetes project references is set without connection secret": {
119-
dbUser: &AtlasDatabaseUser{
89+
object: &AtlasDatabaseUser{
12090
Spec: AtlasDatabaseUserSpec{
12191
Project: &common.ResourceRefNamespaced{
12292
Name: "my-project",
@@ -125,7 +95,7 @@ func TestExternalProjectReferenceConnectionSecret(t *testing.T) {
12595
},
12696
},
12797
"kubernetes project references is set with connection secret": {
128-
dbUser: &AtlasDatabaseUser{
98+
object: &AtlasDatabaseUser{
12999
Spec: AtlasDatabaseUserSpec{
130100
Project: &common.ResourceRefNamespaced{
131101
Name: "my-project",
@@ -140,18 +110,5 @@ func TestExternalProjectReferenceConnectionSecret(t *testing.T) {
140110
},
141111
}
142112

143-
for name, tt := range tests {
144-
t.Run(name, func(t *testing.T) {
145-
unstructuredDBUser, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tt.dbUser)
146-
require.NoError(t, err)
147-
148-
errs := validator(unstructuredDBUser, nil)
149-
150-
require.Equal(t, len(tt.expectedErrors), len(errs))
151-
152-
for i, err := range errs {
153-
assert.Equal(t, tt.expectedErrors[i], err.Error())
154-
}
155-
})
156-
}
113+
assertCELValidation(t, "../../../config/crd/bases/atlas.mongodb.com_atlasdatabaseusers.yaml", tests)
157114
}

pkg/api/v1/atlasdeployment_types.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,15 @@ const (
4747

4848
// AtlasDeploymentSpec defines the desired state of AtlasDeployment
4949
// Only one of DeploymentSpec, AdvancedDeploymentSpec and ServerlessSpec should be defined
50+
// +kubebuilder:validation:XValidation:rule="(has(self.externalProjectRef) && !has(self.projectRef)) || (!has(self.externalProjectRef) && has(self.projectRef))",message="must define only one project reference through externalProjectRef or projectRef"
51+
// +kubebuilder:validation:XValidation:rule="(has(self.externalProjectRef) && has(self.connectionSecret)) || !has(self.externalProjectRef)",message="must define a local connection secret when referencing an external project"
5052
type AtlasDeploymentSpec struct {
53+
api.LocalCredentialHolder `json:",inline"`
54+
5155
// Project is a reference to AtlasProject resource the deployment belongs to
52-
Project common.ResourceRefNamespaced `json:"projectRef"`
56+
Project *common.ResourceRefNamespaced `json:"projectRef,omitempty"`
57+
// ExternalProjectRef holds the Atlas project ID the user belongs to
58+
ExternalProjectRef *ExternalProjectReference `json:"externalProjectRef,omitempty"`
5359

5460
// Configuration for the advanced (v1.5) deployment API https://www.mongodb.com/docs/atlas/reference/api/clusters/
5561
// +optional
@@ -520,6 +526,10 @@ func (c *AtlasDeployment) UpdateStatus(conditions []api.Condition, options ...ap
520526
}
521527
}
522528

529+
func (c *AtlasDeployment) Credentials() *api.LocalObjectReference {
530+
return c.Spec.Credentials()
531+
}
532+
523533
// ************************************ Builder methods *************************************************
524534

525535
func NewDeployment(namespace, name, nameInAtlas string) *AtlasDeployment {
@@ -619,7 +629,7 @@ func (c *AtlasDeployment) WithAtlasName(name string) *AtlasDeployment {
619629
}
620630

621631
func (c *AtlasDeployment) WithProjectName(projectName string) *AtlasDeployment {
622-
c.Spec.Project = common.ResourceRefNamespaced{Name: projectName}
632+
c.Spec.Project = &common.ResourceRefNamespaced{Name: projectName}
623633
return c
624634
}
625635

@@ -674,6 +684,20 @@ func (c *AtlasDeployment) WithSearchNodes(instanceSize string, count uint8) *Atl
674684
return c
675685
}
676686

687+
func (c *AtlasDeployment) WithExternaLProject(projectID, credentialsName string) *AtlasDeployment {
688+
c.Spec.Project = nil
689+
c.Spec.ExternalProjectRef = &ExternalProjectReference{
690+
ID: projectID,
691+
}
692+
c.Spec.LocalCredentialHolder = api.LocalCredentialHolder{
693+
ConnectionSecret: &api.LocalObjectReference{
694+
Name: credentialsName,
695+
},
696+
}
697+
698+
return c
699+
}
700+
677701
// Lightweight makes the deployment work with small shared instance M2. This is useful for non-deployment tests (e.g.
678702
// database users) and saves some money for the company.
679703
func (c *AtlasDeployment) Lightweight() *AtlasDeployment {
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package v1 // nolint: dupl
2+
3+
import (
4+
"testing"
5+
6+
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api"
7+
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common"
8+
)
9+
10+
func TestDeploymentProjectReference(t *testing.T) {
11+
tests := projectReferenceTestCase{
12+
"no project reference is set": {
13+
object: &AtlasDeployment{
14+
Spec: AtlasDeploymentSpec{},
15+
},
16+
expectedErrors: []string{"spec: Invalid value: \"object\": must define only one project reference through externalProjectRef or projectRef"},
17+
},
18+
"both project references are set": {
19+
object: &AtlasDeployment{
20+
Spec: AtlasDeploymentSpec{
21+
Project: &common.ResourceRefNamespaced{
22+
Name: "my-project",
23+
},
24+
ExternalProjectRef: &ExternalProjectReference{
25+
ID: "my-project-id",
26+
},
27+
},
28+
},
29+
expectedErrors: []string{
30+
"spec: Invalid value: \"object\": must define only one project reference through externalProjectRef or projectRef",
31+
"spec: Invalid value: \"object\": must define a local connection secret when referencing an external project",
32+
},
33+
},
34+
"external project references is set": {
35+
object: &AtlasDeployment{
36+
Spec: AtlasDeploymentSpec{
37+
ExternalProjectRef: &ExternalProjectReference{
38+
ID: "my-project-id",
39+
},
40+
},
41+
},
42+
expectedErrors: []string{
43+
"spec: Invalid value: \"object\": must define a local connection secret when referencing an external project",
44+
},
45+
},
46+
"kubernetes project references is set": {
47+
object: &AtlasDeployment{
48+
Spec: AtlasDeploymentSpec{
49+
Project: &common.ResourceRefNamespaced{
50+
Name: "my-project",
51+
},
52+
},
53+
},
54+
},
55+
}
56+
57+
assertCELValidation(t, "../../../config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml", tests)
58+
}
59+
60+
func TestDeploymentExternalProjectReferenceConnectionSecret(t *testing.T) {
61+
tests := projectReferenceTestCase{
62+
"external project references is set without connection secret": {
63+
object: &AtlasDeployment{
64+
Spec: AtlasDeploymentSpec{
65+
ExternalProjectRef: &ExternalProjectReference{
66+
ID: "my-project-id",
67+
},
68+
},
69+
},
70+
expectedErrors: []string{
71+
"spec: Invalid value: \"object\": must define a local connection secret when referencing an external project",
72+
},
73+
},
74+
"external project references is set with connection secret": {
75+
object: &AtlasDeployment{
76+
Spec: AtlasDeploymentSpec{
77+
ExternalProjectRef: &ExternalProjectReference{
78+
ID: "my-project-id",
79+
},
80+
LocalCredentialHolder: api.LocalCredentialHolder{
81+
ConnectionSecret: &api.LocalObjectReference{
82+
Name: "my-dbuser-connection-secret",
83+
},
84+
},
85+
},
86+
},
87+
},
88+
"kubernetes project references is set without connection secret": {
89+
object: &AtlasDeployment{
90+
Spec: AtlasDeploymentSpec{
91+
Project: &common.ResourceRefNamespaced{
92+
Name: "my-project",
93+
},
94+
},
95+
},
96+
},
97+
"kubernetes project references is set with connection secret": {
98+
object: &AtlasDeployment{
99+
Spec: AtlasDeploymentSpec{
100+
Project: &common.ResourceRefNamespaced{
101+
Name: "my-project",
102+
},
103+
LocalCredentialHolder: api.LocalCredentialHolder{
104+
ConnectionSecret: &api.LocalObjectReference{
105+
Name: "my-dbuser-connection-secret",
106+
},
107+
},
108+
},
109+
},
110+
},
111+
}
112+
113+
assertCELValidation(t, "../../../config/crd/bases/atlas.mongodb.com_atlasdeployments.yaml", tests)
114+
}

0 commit comments

Comments
 (0)