From f81c59ae9b49c66e298ccb5f16bcb7a2f4a28c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Wed, 3 Jul 2024 18:10:50 +0100 Subject: [PATCH 1/4] feat: customize connection string secret annotations --- api/v1/mongodbcommunity_types.go | 17 +++++++++++------ ...bcommunity.mongodb.com_mongodbcommunity.yaml | 7 +++++++ controllers/mongodb_users.go | 1 + pkg/authentication/authtypes/authtypes.go | 3 +++ pkg/kube/secret/secret_builder.go | 7 +++++++ 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/api/v1/mongodbcommunity_types.go b/api/v1/mongodbcommunity_types.go index f1e7f8710..117429bac 100644 --- a/api/v1/mongodbcommunity_types.go +++ b/api/v1/mongodbcommunity_types.go @@ -489,6 +489,10 @@ type MongoDBUser struct { // +optional ConnectionStringSecretNamespace string `json:"connectionStringSecretNamespace,omitempty"` + // ConnectionStringSecretAnnotations is the annotations of the secret object created by the operator which exposes the connection strings for the user. + // +optional + ConnectionStringSecretAnnotations map[string]string `json:"connectionStringSecretAnnotations,omitempty"` + // Additional options to be appended to the connection string. // These options apply only to this user and will override any existing options in the resource. // +kubebuilder:validation:Type=object @@ -789,12 +793,13 @@ func (m *MongoDBCommunity) GetAuthUsers() []authtypes.User { } users[i] = authtypes.User{ - Username: u.Name, - Database: u.DB, - Roles: roles, - ConnectionStringSecretName: u.GetConnectionStringSecretName(m.Name), - ConnectionStringSecretNamespace: u.GetConnectionStringSecretNamespace(m.Namespace), - ConnectionStringOptions: u.AdditionalConnectionStringConfig.Object, + Username: u.Name, + Database: u.DB, + Roles: roles, + ConnectionStringSecretName: u.GetConnectionStringSecretName(m.Name), + ConnectionStringSecretNamespace: u.GetConnectionStringSecretNamespace(m.Namespace), + ConnectionStringSecretAnnotations: u.ConnectionStringSecretAnnotations, + ConnectionStringOptions: u.AdditionalConnectionStringConfig.Object, } if u.DB != constants.ExternalDB { diff --git a/config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml b/config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml index e7c3faa69..d126ba112 100644 --- a/config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml +++ b/config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml @@ -552,6 +552,13 @@ spec: nullable: true type: object x-kubernetes-preserve-unknown-fields: true + connectionStringSecretAnnotations: + additionalProperties: + type: string + description: ConnectionStringSecretAnnotations is the annotations + of the secret object created by the operator which exposes + the connection strings for the user. + type: object connectionStringSecretName: description: |- ConnectionStringSecretName is the name of the secret object created by the operator which exposes the connection strings for the user. diff --git a/controllers/mongodb_users.go b/controllers/mongodb_users.go index cd99734ba..b029d05cf 100644 --- a/controllers/mongodb_users.go +++ b/controllers/mongodb_users.go @@ -77,6 +77,7 @@ func (r ReplicaSetReconciler) updateConnectionStringSecrets(ctx context.Context, SetField("username", user.Username). SetField("password", pwd). SetOwnerReferences(mdb.GetOwnerReferences()). + SetAnnotations(user.ConnectionStringSecretAnnotations). Build() if err := secret.CreateOrUpdate(ctx, r.client, connectionStringSecret); err != nil { diff --git a/pkg/authentication/authtypes/authtypes.go b/pkg/authentication/authtypes/authtypes.go index 12d7b0cbb..c5e3b91ee 100644 --- a/pkg/authentication/authtypes/authtypes.go +++ b/pkg/authentication/authtypes/authtypes.go @@ -73,6 +73,9 @@ type User struct { // ConnectionStringSecretNamespace is the namespace of the secret object created by the operator which exposes the connection strings for the user. ConnectionStringSecretNamespace string `json:"connectionStringSecretNamespace,omitempty"` + // ConnectionStringSecretAnnotations is the annotations of the secret object created by the operator which exposes the connection strings for the user. + ConnectionStringSecretAnnotations map[string]string + // ConnectionStringOptions contains connection string options for this user // These options will be appended at the end of the connection string and // will override any existing options from the resources. diff --git a/pkg/kube/secret/secret_builder.go b/pkg/kube/secret/secret_builder.go index f5c3b4c2b..0ed71ba2a 100644 --- a/pkg/kube/secret/secret_builder.go +++ b/pkg/kube/secret/secret_builder.go @@ -11,6 +11,7 @@ type builder struct { labels map[string]string name string namespace string + annotations map[string]string ownerReferences []metav1.OwnerReference } @@ -24,6 +25,11 @@ func (b *builder) SetNamespace(namespace string) *builder { return b } +func (b *builder) SetAnnotations(annotations map[string]string) *builder { + b.annotations = annotations + return b +} + func (b *builder) SetField(key, value string) *builder { b.data[key] = []byte(value) return b @@ -72,6 +78,7 @@ func (b builder) Build() corev1.Secret { Namespace: b.namespace, OwnerReferences: b.ownerReferences, Labels: b.labels, + Annotations: b.annotations, }, Data: b.data, Type: b.dataType, From 0a975734f7f686e1ff9bd59f6c6044ace3ddf553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Fri, 5 Jul 2024 16:35:38 +0100 Subject: [PATCH 2/4] docs(users): add connectionStringSecretAnnotations property --- docs/users.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/users.md b/docs/users.md index 96a44570a..47d9fe75e 100644 --- a/docs/users.md +++ b/docs/users.md @@ -42,6 +42,7 @@ You cannot disable SCRAM authentication. | `spec.users.roles` | array of objects | Configures roles assigned to the user. | Yes | | `spec.users.roles.role.name` | string | Name of the role. Valid values are [built-in roles](https://www.mongodb.com/docs/manual/reference/built-in-roles/#built-in-roles) and [custom roles](deploy-configure.md#define-a-custom-database-role) that you have defined. | Yes | | `spec.users.roles.role.db` | string | Database that the role applies to. | Yes | + | `spec.users.connectionStringSecretAnnotations` | object | Annotations of the secret object created by the operator which exposes the connection strings for the user. | No | ```yaml --- From 4ed2242d6abfd543ea53294c1fdf73f78086dc22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 14 Oct 2024 01:42:37 +0100 Subject: [PATCH 3/4] test: add e2e test for connection string secret annotations --- test/e2e/mongodbtests/mongodbtests.go | 13 ++++++++++++ ...lica_set_connection_string_options_test.go | 20 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/test/e2e/mongodbtests/mongodbtests.go b/test/e2e/mongodbtests/mongodbtests.go index aad73a450..502635096 100644 --- a/test/e2e/mongodbtests/mongodbtests.go +++ b/test/e2e/mongodbtests/mongodbtests.go @@ -205,6 +205,7 @@ func ConnectionStringSecretsAreConfigured(ctx context.Context, mdb *mdbv1.MongoD assert.NoError(t, err) assertEqualOwnerReference(t, "Secret", secretNamespacedName, secret.GetOwnerReferences(), expectedOwnerReference) + containsMetadata(t, secret.ObjectMeta, map[string]string{}, user.ConnectionStringSecretAnnotations, "secret "+secretNamespacedName.Name) } } } @@ -684,6 +685,18 @@ func AddConnectionStringOptionToUser(ctx context.Context, mdb *mdbv1.MongoDBComm } } +func AddConnectionStringAnnotationsToUser(ctx context.Context, mdb *mdbv1.MongoDBCommunity, annotations map[string]string) func(t *testing.T) { + return func(t *testing.T) { + t.Logf("Adding %v to connection string annotations", annotations) + err := e2eutil.UpdateMongoDBResource(ctx, mdb, func(db *mdbv1.MongoDBCommunity) { + db.Spec.Users[0].ConnectionStringSecretAnnotations = annotations + }) + if err != nil { + t.Fatal(err) + } + } +} + func StatefulSetContainerConditionIsTrue(ctx context.Context, mdb *mdbv1.MongoDBCommunity, containerName string, condition func(c corev1.Container) bool) func(*testing.T) { return func(t *testing.T) { sts := appsv1.StatefulSet{} diff --git a/test/e2e/replica_set_connection_string_options/replica_set_connection_string_options_test.go b/test/e2e/replica_set_connection_string_options/replica_set_connection_string_options_test.go index 6358f9d3a..ea71755a5 100644 --- a/test/e2e/replica_set_connection_string_options/replica_set_connection_string_options_test.go +++ b/test/e2e/replica_set_connection_string_options/replica_set_connection_string_options_test.go @@ -108,4 +108,24 @@ func TestReplicaSetWithConnectionString(t *testing.T) { tester.ConnectivityRejected(ctx, WithURI(mongodbtests.GetSrvConnectionStringForUser(ctx, mdb, scramUser)))) }) + /** + Connection String Annotations options. + */ + t.Run("Connection String With Annotations", func(t *testing.T) { + t.Run("Resetting Connection String Options", mongodbtests.ResetConnectionStringOptions(ctx, &mdb)) + t.Run("Test Add New Connection String Annotations to Resource", mongodbtests.AddConnectionStringAnnotationsToUser(ctx, &mdb, map[string]string{"mongodbcommunity.mongodb.com/test-annotation": "test-value"})) + t.Run("Test Secrets Are Updated", mongodbtests.MongoDBReachesRunningPhase(ctx, &mdb)) + + scramUser = mdb.GetAuthUsers()[0] + t.Run("Test Basic Connectivity", tester.ConnectivitySucceeds()) + t.Run("Test SRV Connectivity", tester.ConnectivitySucceeds(WithURI(mdb.MongoSRVURI("")), WithoutTls(), WithReplicaSet(mdb.Name))) + t.Run("Test Basic Connectivity with generated connection string secret", + tester.ConnectivitySucceeds(WithURI(mongodbtests.GetConnectionStringForUser(ctx, mdb, scramUser)))) + t.Run("Test SRV Connectivity with generated connection string secret", + tester.ConnectivitySucceeds(WithURI(mongodbtests.GetSrvConnectionStringForUser(ctx, mdb, scramUser)))) + + ownerRef := mdb.GetOwnerReferences()[0] + t.Run("Test Connection String Annotations are as expected", mongodbtests.ConnectionStringSecretsAreConfigured(ctx, &mdb, ownerRef)) + }) + } From 4075d85d8709308110b63c9ca650d6e142690af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lima?= Date: Mon, 14 Oct 2024 01:44:38 +0100 Subject: [PATCH 4/4] chore: add autogenerated deepcopy code --- api/v1/zz_generated.deepcopy.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index bf58f2b77..1754b7600 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -314,6 +314,13 @@ func (in *MongoDBUser) DeepCopyInto(out *MongoDBUser) { *out = make([]Role, len(*in)) copy(*out, *in) } + if in.ConnectionStringSecretAnnotations != nil { + in, out := &in.ConnectionStringSecretAnnotations, &out.ConnectionStringSecretAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } in.AdditionalConnectionStringConfig.DeepCopyInto(&out.AdditionalConnectionStringConfig) }