diff --git a/api/v1/mongodbcommunity_types.go b/api/v1/mongodbcommunity_types.go index 0b33194e8..e9becd1ab 100644 --- a/api/v1/mongodbcommunity_types.go +++ b/api/v1/mongodbcommunity_types.go @@ -323,7 +323,14 @@ type AuthenticationRestriction struct { // AutomationConfigOverride contains fields which will be overridden in the operator created config. type AutomationConfigOverride struct { - Processes []OverrideProcess `json:"processes"` + Processes []OverrideProcess `json:"processes,omitempty"` + ReplicaSet OverrideReplicaSet `json:"replicaSet,omitempty"` +} + +type OverrideReplicaSet struct { + // +kubebuilder:validation:Type=object + // +kubebuilder:pruning:PreserveUnknownFields + Settings MapWrapper `json:"settings,omitempty"` } // Note: We do not use the automationconfig.Process type directly here as unmarshalling cannot happen directly diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 29c743df9..3ba0ad464 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -117,6 +117,7 @@ func (in *AutomationConfigOverride) DeepCopyInto(out *AutomationConfigOverride) (*in)[i].DeepCopyInto(&(*out)[i]) } } + in.ReplicaSet.DeepCopyInto(&out.ReplicaSet) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutomationConfigOverride. @@ -358,6 +359,22 @@ func (in *OverrideProcess) DeepCopy() *OverrideProcess { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OverrideReplicaSet) DeepCopyInto(out *OverrideReplicaSet) { + *out = *in + in.Settings.DeepCopyInto(&out.Settings) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OverrideReplicaSet. +func (in *OverrideReplicaSet) DeepCopy() *OverrideReplicaSet { + if in == nil { + return nil + } + out := new(OverrideReplicaSet) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Privilege) DeepCopyInto(out *Privilege) { *out = *in diff --git a/config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml b/config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml index f62f7465e..863cdb301 100644 --- a/config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml +++ b/config/crd/bases/mongodbcommunity.mongodb.com_mongodbcommunity.yaml @@ -180,8 +180,16 @@ spec: - name type: object type: array - required: - - processes + replicaSet: + properties: + settings: + description: MapWrapper is a wrapper for a map to be used + by other structs. The CRD generator does not support map[string]interface{} + on the top level and hence we need to work around this with + a wrapping struct. + type: object + x-kubernetes-preserve-unknown-fields: true + type: object type: object featureCompatibilityVersion: description: FeatureCompatibilityVersion configures the feature compatibility diff --git a/config/samples/mongodb.com_v1_mongodbcommunity_override_ac_setting.yaml b/config/samples/mongodb.com_v1_mongodbcommunity_override_ac_setting.yaml new file mode 100644 index 000000000..0a8a1566a --- /dev/null +++ b/config/samples/mongodb.com_v1_mongodbcommunity_override_ac_setting.yaml @@ -0,0 +1,42 @@ +--- +apiVersion: mongodbcommunity.mongodb.com/v1 +kind: MongoDBCommunity +metadata: + name: example-mongodb +spec: + members: 3 + type: ReplicaSet + version: "6.0.5" + security: + authentication: + modes: ["SCRAM"] + # to override ReplicaSet Configuration settings: + # https://www.mongodb.com/docs/manual/reference/replica-configuration/#replica-set-configuration-document-example + automationConfig: + replicaSet: + settings: + electionTimeoutMillis: 20 + users: + - name: my-user + db: admin + passwordSecretRef: # a reference to the secret that will be used to generate the user's password + name: my-user-password + roles: + - name: clusterAdmin + db: admin + - name: userAdminAnyDatabase + db: admin + scramCredentialsSecretName: my-scram + additionalMongodConfig: + storage.wiredTiger.engineConfig.journalCompressor: zlib + +# the user credentials will be generated from this secret +# once the credentials are generated, this secret is no longer required +--- +apiVersion: v1 +kind: Secret +metadata: + name: my-user-password +type: Opaque +stringData: + password: diff --git a/controllers/replica_set_controller.go b/controllers/replica_set_controller.go index e6abbe388..e643fa942 100644 --- a/controllers/replica_set_controller.go +++ b/controllers/replica_set_controller.go @@ -539,6 +539,11 @@ func buildAutomationConfig(mdb mdbv1.MongoDBCommunity, auth automationconfig.Aut arbitersCount = mdb.Status.CurrentMongoDBArbiters } + var acOverrideSettings map[string]interface{} + if mdb.Spec.AutomationConfigOverride != nil { + acOverrideSettings = mdb.Spec.AutomationConfigOverride.ReplicaSet.Settings.Object + } + return automationconfig.NewBuilder(). IsEnterprise(guessEnterprise(mdb)). SetTopology(automationconfig.ReplicaSetTopology). @@ -553,6 +558,7 @@ func buildAutomationConfig(mdb mdbv1.MongoDBCommunity, auth automationconfig.Aut SetFCV(mdb.Spec.FeatureCompatibilityVersion). SetOptions(automationconfig.Options{DownloadBase: "/var/lib/mongodb-mms-automation"}). SetAuth(auth). + SetSettings(acOverrideSettings). SetMemberOptions(mdb.Spec.MemberConfig). SetDataDir(mdb.GetMongodConfiguration().GetDBDataDir()). AddModifications(getMongodConfigModification(mdb)). diff --git a/pkg/automationconfig/automation_config.go b/pkg/automationconfig/automation_config.go index d81702432..37a087e89 100644 --- a/pkg/automationconfig/automation_config.go +++ b/pkg/automationconfig/automation_config.go @@ -259,11 +259,12 @@ type ReplSetForceConfig struct { } type ReplicaSet struct { - Id string `json:"_id"` - Members []ReplicaSetMember `json:"members"` - ProtocolVersion string `json:"protocolVersion"` - NumberArbiters int `json:"numberArbiters"` - Force *ReplSetForceConfig `json:"force,omitempty"` + Id string `json:"_id"` + Members []ReplicaSetMember `json:"members"` + ProtocolVersion string `json:"protocolVersion"` + NumberArbiters int `json:"numberArbiters"` + Force *ReplSetForceConfig `json:"force,omitempty"` + Settings map[string]interface{} `json:"settings,omitempty"` } type ReplicaSetMember struct { diff --git a/pkg/automationconfig/automation_config_builder.go b/pkg/automationconfig/automation_config_builder.go index 80df8aec0..bc0e9222e 100644 --- a/pkg/automationconfig/automation_config_builder.go +++ b/pkg/automationconfig/automation_config_builder.go @@ -53,6 +53,7 @@ type Builder struct { port int memberOptions []MemberOptions forceReconfigureToVersion *int64 + settings map[string]interface{} } func NewBuilder() *Builder { @@ -192,6 +193,11 @@ func (b *Builder) SetAuth(auth Auth) *Builder { return b } +func (b *Builder) SetSettings(settings map[string]interface{}) *Builder { + b.settings = settings + return b +} + func (b *Builder) SetForceReconfigureToVersion(version int64) *Builder { b.forceReconfigureToVersion = &version return b @@ -375,6 +381,7 @@ func (b *Builder) Build() (AutomationConfig, error) { ProtocolVersion: "1", NumberArbiters: b.arbiters, Force: replSetForceConfig, + Settings: b.settings, }, }, MonitoringVersions: b.monitoringVersions, diff --git a/test/e2e/mongodbtests/mongodbtests.go b/test/e2e/mongodbtests/mongodbtests.go index 2f33ab00a..f01396cd1 100644 --- a/test/e2e/mongodbtests/mongodbtests.go +++ b/test/e2e/mongodbtests/mongodbtests.go @@ -398,6 +398,13 @@ func AutomationConfigHasLogRotationConfig(mdb *mdbv1.MongoDBCommunity, lrc *auto } } +func AutomationConfigHasSettings(mdb *mdbv1.MongoDBCommunity, settings map[string]interface{}) func(t *testing.T) { + return func(t *testing.T) { + currentAc := getAutomationConfig(t, mdb) + assert.Equal(t, currentAc.ReplicaSets[0].Settings, settings) + } +} + // AutomationConfigReplicaSetsHaveExpectedArbiters verifies that the automation config has the expected version. func AutomationConfigReplicaSetsHaveExpectedArbiters(mdb *mdbv1.MongoDBCommunity, expectedArbiters int) func(t *testing.T) { return func(t *testing.T) { diff --git a/test/e2e/replica_set/replica_set_test.go b/test/e2e/replica_set/replica_set_test.go index cfee78364..c353a6a07 100644 --- a/test/e2e/replica_set/replica_set_test.go +++ b/test/e2e/replica_set/replica_set_test.go @@ -5,6 +5,7 @@ import ( "os" "testing" + v1 "github.com/mongodb/mongodb-kubernetes-operator/api/v1" "github.com/mongodb/mongodb-kubernetes-operator/pkg/automationconfig" e2eutil "github.com/mongodb/mongodb-kubernetes-operator/test/e2e" "github.com/mongodb/mongodb-kubernetes-operator/test/e2e/mongodbtests" @@ -77,6 +78,13 @@ func TestReplicaSet(t *testing.T) { } mdb.Spec.MemberConfig = memberOptions + settings := map[string]interface{}{ + "electionTimeoutMillis": float64(20), + } + mdb.Spec.AutomationConfigOverride = &v1.AutomationConfigOverride{ + ReplicaSet: v1.OverrideReplicaSet{Settings: v1.MapWrapper{Object: settings}}, + } + tester, err := FromResource(t, mdb) if err != nil { t.Fatal(err) @@ -94,5 +102,6 @@ func TestReplicaSet(t *testing.T) { tester.ConnectivitySucceeds(WithURI(mongodbtests.GetSrvConnectionStringForUser(mdb, scramUser)))) t.Run("Ensure Authentication", tester.EnsureAuthenticationIsConfigured(3)) t.Run("AutomationConfig has the correct version", mongodbtests.AutomationConfigVersionHasTheExpectedVersion(&mdb, 1)) - t.Run("AutomationCondig has correct member options", mongodbtests.AutomationConfigHasVoteTagPriorityConfigured(&mdb, memberOptions)) + t.Run("AutomationConfig has correct member options", mongodbtests.AutomationConfigHasVoteTagPriorityConfigured(&mdb, memberOptions)) + t.Run("AutomationConfig has correct settings", mongodbtests.AutomationConfigHasSettings(&mdb, settings)) }