Skip to content

CLOUDP-334941/connectionsecret-controller-scaffold #2575

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ install-credentials: set-namespace ## Install the Atlas credentials for the Oper

.PHONY: prepare-run
prepare-run: generate vet manifests run-kind install-crds install-credentials
rm bin/manager
rm -rf bin/manager
$(MAKE) manager VERSION=$(NEXT_VERSION)

.PHONY: run
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import (
akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/status"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/atlas"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/connectionsecret"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/customresource"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/reconciler"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/statushandler"
Expand Down Expand Up @@ -141,12 +140,7 @@ func (r *AtlasDatabaseUserReconciler) terminate(
}

// unmanage remove finalizer and release resource
func (r *AtlasDatabaseUserReconciler) unmanage(ctx *workflow.Context, projectID string, atlasDatabaseUser *akov2.AtlasDatabaseUser) (ctrl.Result, error) {
err := connectionsecret.RemoveStaleSecretsByUserName(ctx.Context, r.Client, projectID, atlasDatabaseUser.Spec.Username, *atlasDatabaseUser, r.Log)
if err != nil {
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.DatabaseUserConnectionSecretsNotDeleted, true, err)
}

func (r *AtlasDatabaseUserReconciler) unmanage(ctx *workflow.Context, atlasDatabaseUser *akov2.AtlasDatabaseUser) (ctrl.Result, error) {
if customresource.HaveFinalizer(atlasDatabaseUser, customresource.FinalizerLabel) {
err := customresource.ManageFinalizer(ctx.Context, r.Client, atlasDatabaseUser, customresource.UnsetFinalizer)
if err != nil {
Expand Down
42 changes: 6 additions & 36 deletions internal/controller/atlasdatabaseuser/databaseuser.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (

"github.com/mongodb/mongodb-atlas-kubernetes/v2/api"
akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/connectionsecret"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/customresource"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/workflow"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/timeutil"
Expand Down Expand Up @@ -84,18 +83,13 @@ func (r *AtlasDatabaseUserReconciler) dbuLifeCycle(ctx *workflow.Context, dbUser
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.Internal, true, err)
}

expired, err := isExpired(atlasDatabaseUser)
expired, err := IsExpired(atlasDatabaseUser)
if err != nil {
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.DatabaseUserInvalidSpec, false, err)
}
if expired {
err = connectionsecret.RemoveStaleSecretsByUserName(ctx.Context, r.Client, atlasProject.ID, atlasDatabaseUser.Spec.Username, *atlasDatabaseUser, r.Log)
if err != nil {
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.DatabaseUserConnectionSecretsNotDeleted, true, err)
}

ctx.SetConditionFromResult(api.DatabaseUserReadyType, workflow.Terminate(workflow.DatabaseUserExpired, errors.New("an expired user cannot be managed")))
return r.unmanage(ctx, atlasProject.ID, atlasDatabaseUser)
return r.unmanage(ctx, atlasDatabaseUser)
}

scopesAreValid, err := r.areDeploymentScopesValid(ctx, deploymentService, atlasProject.ID, atlasDatabaseUser)
Expand All @@ -117,7 +111,7 @@ func (r *AtlasDatabaseUserReconciler) dbuLifeCycle(ctx *workflow.Context, dbUser
case dbUserExists && wasDeleted:
return r.delete(ctx, dbUserService, atlasProject.ID, atlasDatabaseUser)
default:
return r.unmanage(ctx, atlasProject.ID, atlasDatabaseUser)
return r.unmanage(ctx, atlasDatabaseUser)
}
}

Expand All @@ -139,11 +133,6 @@ func (r *AtlasDatabaseUserReconciler) create(ctx *workflow.Context, dbUserServic
}

if wasRenamed(atlasDatabaseUser) {
err = connectionsecret.RemoveStaleSecretsByUserName(ctx.Context, r.Client, projectID, atlasDatabaseUser.Status.UserName, *atlasDatabaseUser, r.Log)
if err != nil {
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.DatabaseUserConnectionSecretsNotDeleted, true, err)
}

ctx.Log.Infow("'spec.username' has changed - removing the old user from Atlas", "newUserName", atlasDatabaseUser.Spec.Username, "oldUserName", atlasDatabaseUser.Status.UserName)
if err = r.removeOldUser(ctx.Context, dbUserService, projectID, atlasDatabaseUser); err != nil {
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.Internal, true, err)
Expand Down Expand Up @@ -183,7 +172,7 @@ func (r *AtlasDatabaseUserReconciler) delete(ctx *workflow.Context, dbUserServic
if customresource.IsResourcePolicyKeepOrDefault(atlasDatabaseUser, r.ObjectDeletionProtection) {
r.Log.Info("Not removing Atlas database user from Atlas as per configuration")

return r.unmanage(ctx, projectID, atlasDatabaseUser)
return r.unmanage(ctx, atlasDatabaseUser)
}

err := dbUserService.Delete(ctx.Context, atlasDatabaseUser.Spec.DatabaseName, projectID, atlasDatabaseUser.Spec.Username)
Expand All @@ -195,7 +184,7 @@ func (r *AtlasDatabaseUserReconciler) delete(ctx *workflow.Context, dbUserServic
r.Log.Info("Database user doesn't exist or is already deleted")
}

return r.unmanage(ctx, projectID, atlasDatabaseUser)
return r.unmanage(ctx, atlasDatabaseUser)
}

func (r *AtlasDatabaseUserReconciler) readiness(ctx *workflow.Context, deploymentService deployment.AtlasDeploymentsService,
Expand All @@ -205,19 +194,6 @@ func (r *AtlasDatabaseUserReconciler) readiness(ctx *workflow.Context, deploymen
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.Internal, true, err)
}

removedOrphanSecrets, err := connectionsecret.ReapOrphanConnectionSecrets(
ctx.Context, r.Client, atlasProject.ID, atlasDatabaseUser.Namespace, allDeploymentNames)
if err != nil {
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.Internal, true, err)
}
if len(removedOrphanSecrets) > 0 {
r.Log.Debugw("Removed orphan secrets bound to an non existent deployment",
"project", atlasProject.Name, "removed", len(removedOrphanSecrets))
for _, orphan := range removedOrphanSecrets {
r.Log.Debugw("Removed orphan", "secret", orphan)
}
}

deploymentsToCheck := allDeploymentNames
if atlasDatabaseUser.Spec.Scopes != nil {
deploymentsToCheck = filterScopeDeployments(atlasDatabaseUser, allDeploymentNames)
Expand All @@ -243,12 +219,6 @@ func (r *AtlasDatabaseUserReconciler) readiness(ctx *workflow.Context, deploymen
)
}

// TODO refactor connectionsecret package to follow state machine approach
result := connectionsecret.CreateOrUpdateConnectionSecrets(ctx, r.Client, deploymentService, r.EventRecorder, atlasProject, *atlasDatabaseUser)
if !result.IsOk() {
return r.terminate(ctx, atlasDatabaseUser, api.DatabaseUserReadyType, workflow.DatabaseUserConnectionSecretsNotCreated, true, errors.New(result.GetMessage()))
}

return r.ready(ctx, atlasDatabaseUser, passwordVersion)
}

Expand Down Expand Up @@ -304,7 +274,7 @@ func (r *AtlasDatabaseUserReconciler) removeOldUser(ctx context.Context, dbUserS
return err
}

func isExpired(atlasDatabaseUser *akov2.AtlasDatabaseUser) (bool, error) {
func IsExpired(atlasDatabaseUser *akov2.AtlasDatabaseUser) (bool, error) {
if atlasDatabaseUser.Spec.DeleteAfterDate == "" {
return false, nil
}
Expand Down
43 changes: 1 addition & 42 deletions internal/controller/atlasdatabaseuser/databaseuser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,6 @@ func TestDbuLifeCycle(t *testing.T) {
dService: func() deployment.AtlasDeploymentsService {
service := translation.NewAtlasDeploymentsServiceMock(t)
service.EXPECT().ListDeploymentNames(context.Background(), "").Return([]string{}, nil)
service.EXPECT().ListDeploymentConnections(context.Background(), "").Return([]deployment.Connection{}, nil)

return service
},
Expand Down Expand Up @@ -1213,7 +1212,6 @@ func TestUpdate(t *testing.T) {
dService: func() deployment.AtlasDeploymentsService {
service := translation.NewAtlasDeploymentsServiceMock(t)
service.EXPECT().ListDeploymentNames(context.Background(), "").Return([]string{}, nil)
service.EXPECT().ListDeploymentConnections(context.Background(), "").Return([]deployment.Connection{}, nil)

return service
},
Expand Down Expand Up @@ -1659,43 +1657,6 @@ func TestReadiness(t *testing.T) {
WithMessageRegexp("0 out of 1 deployments have applied database user changes"),
},
},
"failed to create connection secrets": {
wantErr: true,
dbUser: &akov2.AtlasDatabaseUser{
ObjectMeta: metav1.ObjectMeta{
Name: "user1",
Namespace: "default",
},
Spec: akov2.AtlasDatabaseUserSpec{
Username: "user1",
PasswordSecret: &common.ResourceRef{
Name: "user-pass",
},
Scopes: []akov2.ScopeSpec{
{
Name: "cluster2",
Type: akov2.DeploymentScopeType,
},
},
},
},
dService: func() deployment.AtlasDeploymentsService {
service := translation.NewAtlasDeploymentsServiceMock(t)
service.EXPECT().ListDeploymentNames(context.Background(), "").
Return([]string{"cluster1", "cluster2"}, nil)
service.EXPECT().DeploymentIsReady(context.Background(), "", "cluster2").
Return(true, nil)
service.EXPECT().ListDeploymentConnections(context.Background(), "").
Return(nil, errors.New("failed to list cluster connections"))

return service
},
expectedConditions: []api.Condition{
api.FalseCondition(api.DatabaseUserReadyType).
WithReason(string(workflow.DatabaseUserConnectionSecretsNotCreated)).
WithMessageRegexp("failed to list cluster connections"),
},
},
"resource is ready": {
dbUser: &akov2.AtlasDatabaseUser{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -1721,8 +1682,6 @@ func TestReadiness(t *testing.T) {
Return([]string{"cluster1", "cluster2"}, nil)
service.EXPECT().DeploymentIsReady(context.Background(), "", "cluster2").
Return(true, nil)
service.EXPECT().ListDeploymentConnections(context.Background(), "").
Return([]deployment.Connection{}, nil)

return service
},
Expand Down Expand Up @@ -2127,7 +2086,7 @@ func TestIsExpired(t *testing.T) {

for name, tt := range tests {
t.Run(name, func(t *testing.T) {
expired, err := isExpired(tt.dbUser)
expired, err := IsExpired(tt.dbUser)
assert.Equal(t, tt.err, err)
assert.Equal(t, tt.expected, expired)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (r *AtlasDataFederationReconciler) ensureConnectionSecrets(ctx *workflow.Co
connURLs = append(connURLs, fmt.Sprintf("mongodb://%s:%s@%s?ssl=true", dbUser.Spec.Username, password, host))
}

data := connectionsecret.ConnectionData{
data := connectionsecret.ConnSecretData{
DBUserName: dbUser.Spec.Username,
Password: password,
ConnURL: strings.Join(connURLs, ","),
Expand Down
95 changes: 2 additions & 93 deletions internal/controller/atlasdeployment/advanced_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,19 @@ import (
"errors"
"fmt"
"reflect"
"strings"

v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/fields"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/mongodb/mongodb-atlas-kubernetes/v2/api"
akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/api/v1/status"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/connectionsecret"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/customresource"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/workflow"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/indexer"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/stringutil"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/deployment"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/project"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/searchindex"
)

const FreeTier = "M0"

func (r *AtlasDeploymentReconciler) handleAdvancedDeployment(ctx *workflow.Context, projectService project.ProjectService, deploymentService deployment.AtlasDeploymentsService, akoDeployment, atlasDeployment deployment.Deployment) (ctrl.Result, error) {
func (r *AtlasDeploymentReconciler) handleAdvancedDeployment(ctx *workflow.Context, deploymentService deployment.AtlasDeploymentsService, akoDeployment, atlasDeployment deployment.Deployment) (ctrl.Result, error) {
if akoDeployment.GetCustomResource().Spec.UpgradeToDedicated && !atlasDeployment.IsDedicated() {
if atlasDeployment.GetState() == status.StateUPDATING {
return r.inProgress(ctx, akoDeployment.GetCustomResource(), atlasDeployment, workflow.DeploymentUpdating, "deployment is updating")
Expand Down Expand Up @@ -96,11 +86,6 @@ func (r *AtlasDeploymentReconciler) handleAdvancedDeployment(ctx *workflow.Conte
return transition(workflow.DeploymentAdvancedOptionsReady)
}

err := r.ensureConnectionSecrets(ctx, projectService, akoCluster, atlasCluster.GetConnection())
if err != nil {
return r.terminate(ctx, workflow.DeploymentConnectionSecretsNotCreated, err)
}

var results []workflow.DeprecatedResult
if !r.AtlasProvider.IsCloudGov() {
searchNodeResult := handleSearchNodes(ctx, akoCluster.GetCustomResource(), akoCluster.GetProjectID())
Expand Down Expand Up @@ -135,7 +120,7 @@ func (r *AtlasDeploymentReconciler) handleAdvancedDeployment(ctx *workflow.Conte
return r.transitionFromResult(ctx, deploymentService, akoCluster.GetProjectID(), akoCluster.GetCustomResource(), results[i])(workflow.Internal)
}
}
err = customresource.ApplyLastConfigApplied(ctx.Context, akoCluster.GetCustomResource(), r.Client)
err := customresource.ApplyLastConfigApplied(ctx.Context, akoCluster.GetCustomResource(), r.Client)
if err != nil {
return r.terminate(ctx, workflow.Internal, err)
}
Expand All @@ -152,82 +137,6 @@ func (r *AtlasDeploymentReconciler) handleAdvancedDeployment(ctx *workflow.Conte
}
}

func (r *AtlasDeploymentReconciler) ensureConnectionSecrets(ctx *workflow.Context, projectService project.ProjectService, deploymentInAKO deployment.Deployment, connection *status.ConnectionStrings) error {
databaseUsers := &akov2.AtlasDatabaseUserList{}
listOpts := &client.ListOptions{
FieldSelector: fields.OneTermEqualSelector(indexer.AtlasDatabaseUserByProject, deploymentInAKO.GetProjectID()),
}
err := r.Client.List(ctx.Context, databaseUsers, listOpts)
if err != nil {
return err
}

secrets := make([]string, 0)
for _, dbUser := range databaseUsers.Items {
found := false
for _, c := range dbUser.Status.Conditions {
if c.Type == api.ReadyType && c.Status == v1.ConditionTrue {
found = true
break
}
}

if !found {
ctx.Log.Debugw("AtlasDatabaseUser not ready - not creating connection secret", "user.name", dbUser.Name)
continue
}

scopes := dbUser.GetScopes(akov2.DeploymentScopeType)
if len(scopes) != 0 && !stringutil.Contains(scopes, deploymentInAKO.GetName()) {
continue
}

password, err := dbUser.ReadPassword(ctx.Context, r.Client)
if err != nil {
return err
}

data := connectionsecret.ConnectionData{
DBUserName: dbUser.Spec.Username,
Password: password,
ConnURL: connection.Standard,
SrvConnURL: connection.StandardSrv,
}
if connection.Private != "" {
data.PrivateConnURLs = append(data.PrivateConnURLs, connectionsecret.PrivateLinkConnURLs{
PvtConnURL: connection.Private,
PvtSrvConnURL: connection.PrivateSrv,
})
}

for _, pe := range connection.PrivateEndpoint {
data.PrivateConnURLs = append(data.PrivateConnURLs, connectionsecret.PrivateLinkConnURLs{
PvtConnURL: pe.ConnectionString,
PvtSrvConnURL: pe.SRVConnectionString,
PvtShardConnURL: pe.SRVShardOptimizedConnectionString,
})
}

project, err := projectService.GetProject(ctx.Context, deploymentInAKO.GetProjectID())
if err != nil {
return err
}

ctx.Log.Debugw("Creating a connection Secret", "data", data)
secretName, err := connectionsecret.Ensure(ctx.Context, r.Client, dbUser.Namespace, project.Name, deploymentInAKO.GetProjectID(), deploymentInAKO.GetName(), data)
if err != nil {
return err
}
secrets = append(secrets, secretName)
}

if len(secrets) > 0 {
r.EventRecorder.Eventf(deploymentInAKO.GetCustomResource(), "Normal", "ConnectionSecretsEnsured", "Connection Secrets were created/updated: %s", strings.Join(secrets, ", "))
}

return nil
}

func (r *AtlasDeploymentReconciler) ensureAdvancedOptions(ctx *workflow.Context, deploymentService deployment.AtlasDeploymentsService, deploymentInAKO, deploymentInAtlas *deployment.Cluster) transitionFn {
if deploymentInAKO.IsTenant() {
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import (
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/mocks/translation"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/pointer"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/deployment"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/project"
)

func TestHandleAdvancedDeployment(t *testing.T) {
Expand Down Expand Up @@ -975,8 +974,7 @@ func TestHandleAdvancedDeployment(t *testing.T) {
}

deploymentInAKO := deployment.NewDeployment("project-id", tt.atlasDeployment).(*deployment.Cluster)
var projectService project.ProjectService // nil projetc service
result, err := reconciler.handleAdvancedDeployment(ctx, projectService, tt.deploymentService(), deploymentInAKO, tt.deploymentInAtlas)
result, err := reconciler.handleAdvancedDeployment(ctx, tt.deploymentService(), deploymentInAKO, tt.deploymentInAtlas)
//require.NoError(t, err)
assert.Equal(t, tt.expectedResult, workflowRes{
res: result,
Expand Down
Loading
Loading