Skip to content

CLOUDP-266544: Independent Atlas Database User #1797

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ jobs:
MCLI_PRIVATE_API_KEY: ${{ secrets.ATLAS_PRIVATE_KEY }}
MCLI_ORG_ID: ${{ secrets.ATLAS_ORG_ID}}
MCLI_OPS_MANAGER_URL: "https://cloud-qa.mongodb.com/"
ATLAS_LOCAL_PUBLIC_KEY: ${{ secrets.ATLAS_LOCAL_PUBLIC_KEY }}
ATLAS_LOCAL_PRIVATE_KEY: ${{ secrets.ATLAS_LOCAL_PRIVATE_KEY }}
IMAGE_URL: "${{ env.GHCR_REPO }}:${{ steps.prepare.outputs.tag }}"
IMAGE_PULL_SECRET_REGISTRY: ghcr.io
IMAGE_PULL_SECRET_USERNAME: $
Expand Down
27 changes: 26 additions & 1 deletion config/crd/bases/atlas.mongodb.com_atlasdatabaseusers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ spec:
description: AtlasDatabaseUserSpec defines the desired state of Database
User in Atlas
properties:
atlasProjectRef:
description: AtlasProjectRef holds the Atlas project ID the user belongs
to
properties:
id:
description: ID is the Atlas project ID
type: string
required:
- id
type: object
awsIamType:
default: NONE
description: |-
Expand All @@ -66,6 +76,18 @@ spec:
- USER
- ROLE
type: string
connectionSecret:
description: LocalObjectReference is a reference to an object in the
same namespace as the referent
properties:
name:
description: |-
Name of the resource being referred to
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
required:
- name
type: object
databaseName:
default: admin
description: DatabaseName is a Database against which Atlas authenticates
Expand Down Expand Up @@ -200,10 +222,13 @@ spec:
- CUSTOMER
type: string
required:
- projectRef
- roles
- username
type: object
x-kubernetes-validations:
- message: cannot define both atlasRef and projectRef at same time
rule: 'has(self.atlasRef) && !has(self.projectRef) ? true : !has(self.atlasRef)
&& has(self.projectRef)'
status:
description: AtlasDatabaseUserStatus defines the observed state of AtlasProject
properties:
Expand Down
59 changes: 59 additions & 0 deletions internal/mocks/translation/project_service.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions internal/translation/dbuser/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,10 @@ func (u *User) clearedSpecClone() *akov2.AtlasDatabaseUserSpec {
return nil
}
clone := *u.AtlasDatabaseUserSpec
clone.Project.Name = ""
clone.Project.Namespace = ""
clone.Project = nil
clone.PasswordSecret = nil
clone.ConnectionSecret = nil
clone.AtlasProjectRef = nil
return &clone
}

Expand Down
15 changes: 11 additions & 4 deletions internal/translation/dbuser/conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/timeutil"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/dbuser"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api"
akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common"
)
Expand Down Expand Up @@ -390,9 +391,12 @@ func TestDiffSpecs(t *testing.T) {
{Name: "lake1", Type: "DATA_LAKE"},
{Name: "lake2", Type: "DATA_LAKE"},
}
spec.Project.Name = "some-project"
spec.Project.Namespace = "some-namespace"
spec.Project = &common.ResourceRefNamespaced{
Name: "some-project",
Namespace: "some-namespace",
}
spec.PasswordSecret = &common.ResourceRef{Name: "some-secret-ref"}
spec.ConnectionSecret = &api.LocalObjectReference{Name: "some-local-secret-ref"}
return spec
}(),
},
Expand All @@ -405,9 +409,12 @@ func TestDiffSpecs(t *testing.T) {
{Name: "lake1", Type: "DATA_LAKE"},
{Name: "lake2", Type: "DATA_LAKE"},
}
spec.Project.Name = "another-project"
spec.Project.Namespace = "another-namespace"
spec.Project = &common.ResourceRefNamespaced{
Name: "another-project",
Namespace: "another-namespace",
}
spec.PasswordSecret = &common.ResourceRef{Name: "another-secret-ref"}
spec.ConnectionSecret = &api.LocalObjectReference{Name: "another-local-secret-ref"}
return spec
}(),
},
Expand Down
10 changes: 10 additions & 0 deletions internal/translation/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

type ProjectService interface {
GetProjectByName(ctx context.Context, name string) (*Project, error)
GetProject(ctx context.Context, ID string) (*Project, error)
CreateProject(ctx context.Context, project *Project) error
DeleteProject(ctx context.Context, project *Project) error
}
Expand All @@ -29,6 +30,15 @@ func (a *ProjectAPI) GetProjectByName(ctx context.Context, name string) (*Projec
return fromAtlas(group), err
}

func (a *ProjectAPI) GetProject(ctx context.Context, ID string) (*Project, error) {
group, _, err := a.projectAPI.GetProject(ctx, ID).Execute()
if err != nil {
return nil, err
}

return fromAtlas(group), err
}

func (a *ProjectAPI) CreateProject(ctx context.Context, project *Project) error {
group, _, err := a.projectAPI.CreateProject(ctx, toAtlas(project)).Execute()
if err != nil {
Expand Down
28 changes: 28 additions & 0 deletions pkg/api/credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package api

type LocalRef string

// +k8s:deepcopy-gen=false

// CredentialsProvider gives access to custom local credentials
type CredentialsProvider interface {
Credentials() *LocalObjectReference
}

// +k8s:deepcopy-gen=false

// ResourceWithCredentials is to be implemented by all CRDs using custom local credentials
type ResourceWithCredentials interface {
CredentialsProvider
GetName() string
GetNamespace() string
}

// LocalCredentialHolder is to be embedded by Specs of CRDs using custom local credentials
type LocalCredentialHolder struct {
ConnectionSecret *LocalObjectReference `json:"connectionSecret,omitempty"`
}

func (ch *LocalCredentialHolder) Credentials() *LocalObjectReference {
return ch.ConnectionSecret
}
8 changes: 8 additions & 0 deletions pkg/api/localref.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package api

// LocalObjectReference is a reference to an object in the same namespace as the referent
type LocalObjectReference struct {
// Name of the resource being referred to
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
Name string `json:"name"`
}
16 changes: 12 additions & 4 deletions pkg/api/v1/atlasdatabaseuser_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,15 @@ const (
)

// AtlasDatabaseUserSpec defines the desired state of Database User in Atlas
// +kubebuilder:validation:XValidation:rule="has(self.atlasRef) && !has(self.projectRef) ? true : !has(self.atlasRef) && has(self.projectRef)",message="cannot define both atlasRef and projectRef at same time"
type AtlasDatabaseUserSpec struct {
api.LocalCredentialHolder `json:",inline"`

// Project is a reference to AtlasProject resource the user belongs to
Project common.ResourceRefNamespaced `json:"projectRef"`
Project *common.ResourceRefNamespaced `json:"projectRef,omitempty"`

// AtlasProjectRef holds the Atlas project ID the user belongs to
AtlasProjectRef *ExternalProjectReference `json:"atlasProjectRef,omitempty"`

// DatabaseName is a Database against which Atlas authenticates the user. Default value is 'admin'.
// +kubebuilder:default=admin
Expand Down Expand Up @@ -111,8 +117,6 @@ type AtlasDatabaseUserSpec struct {
X509Type string `json:"x509Type,omitempty"`
}

var _ api.AtlasCustomResource = &AtlasDatabaseUser{}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:root=true
// +kubebuilder:printcolumn:name="Name",type=string,JSONPath=`.spec.name`
Expand Down Expand Up @@ -253,7 +257,7 @@ func NewDBUser(namespace, name, dbUserName, projectName string) *AtlasDatabaseUs
},
Spec: AtlasDatabaseUserSpec{
Username: dbUserName,
Project: common.ResourceRefNamespaced{Name: projectName},
Project: &common.ResourceRefNamespaced{Name: projectName},
PasswordSecret: &common.ResourceRef{},
Roles: []RoleSpec{},
Scopes: []ScopeSpec{},
Expand Down Expand Up @@ -296,6 +300,10 @@ func (p *AtlasDatabaseUser) WithDeleteAfterDate(date string) *AtlasDatabaseUser
return p
}

func (p *AtlasDatabaseUser) Credentials() *api.LocalObjectReference {
return p.Spec.Credentials()
}

func DefaultDBUser(namespace, username, projectName string) *AtlasDatabaseUser {
return NewDBUser(namespace, username, username, projectName).WithRole("clusterMonitor", "admin", "")
}
6 changes: 6 additions & 0 deletions pkg/api/v1/externalreference.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package v1

type ExternalProjectReference struct {
// ID is the Atlas project ID
ID string `json:"id"`
}
27 changes: 26 additions & 1 deletion pkg/api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions pkg/api/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading