Skip to content

Commit 5f15071

Browse files
authored
CLOUDP-101809: Respect value of storage.dbPath (#753)
1 parent d0d5466 commit 5f15071

File tree

9 files changed

+156
-24
lines changed

9 files changed

+156
-24
lines changed

api/v1/mongodbcommunity_types.go

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package v1
33
import (
44
"encoding/json"
55
"fmt"
6+
"github.com/stretchr/objx"
67
"net/url"
78
"strings"
89

@@ -405,6 +406,14 @@ type MongoDBCommunity struct {
405406
Status MongoDBCommunityStatus `json:"status,omitempty"`
406407
}
407408

409+
func (m MongoDBCommunity) GetMongodConfiguration() map[string]interface{} {
410+
mongodConfig := objx.New(map[string]interface{}{})
411+
for k, v := range m.Spec.AdditionalMongodConfig.Object {
412+
mongodConfig.Set(k, v)
413+
}
414+
return mongodConfig
415+
}
416+
408417
func (m MongoDBCommunity) GetAgentPasswordSecretNamespacedName() types.NamespacedName {
409418
return types.NamespacedName{Name: m.Name + "-agent-password", Namespace: m.Namespace}
410419
}

controllers/construct/build_statefulset_test.go

+20-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func TestMultipleCalls_DoNotCauseSideEffects(t *testing.T) {
6161
}
6262

6363
func TestMongod_Container(t *testing.T) {
64-
c := container.New(mongodbContainer("4.2", []corev1.VolumeMount{}))
64+
c := container.New(mongodbContainer("4.2", []corev1.VolumeMount{}, map[string]interface{}{}))
6565

6666
t.Run("Has correct Env vars", func(t *testing.T) {
6767
assert.Len(t, c.Env, 1)
@@ -78,6 +78,25 @@ func TestMongod_Container(t *testing.T) {
7878
})
7979
}
8080

81+
func TestGetDbPath(t *testing.T) {
82+
t.Run("Test default is used if unspecifed", func(t *testing.T) {
83+
m := map[string]interface{}{}
84+
path := GetDBDataDir(m)
85+
assert.Equal(t, defaultDataDir, path)
86+
})
87+
88+
t.Run("Test storage.dbPath is used if specified", func(t *testing.T) {
89+
m := map[string]interface{}{
90+
"storage": map[string]interface{}{
91+
"dbPath": "/data/db",
92+
},
93+
}
94+
95+
path := GetDBDataDir(m)
96+
assert.Equal(t, "/data/db", path)
97+
})
98+
}
99+
81100
func assertStatefulSetIsBuiltCorrectly(t *testing.T, mdb mdbv1.MongoDBCommunity, sts *appsv1.StatefulSet) {
82101
assert.Len(t, sts.Spec.Template.Spec.Containers, 2)
83102
assert.Len(t, sts.Spec.Template.Spec.InitContainers, 2)

controllers/construct/mongodbstatefulset.go

+21-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package construct
22

33
import (
44
"fmt"
5+
"github.com/stretchr/objx"
56
"os"
67
"strings"
78

@@ -43,8 +44,9 @@ const (
4344
ReadinessProbeImageEnv = "READINESS_PROBE_IMAGE"
4445
ManagedSecurityContextEnv = "MANAGED_SECURITY_CONTEXT"
4546

46-
automationconfFilePath = "/data/automation-mongod.conf"
47-
keyfileFilePath = "/var/lib/mongodb-mms-automation/authentication/keyfile"
47+
defaultDataDir = "/data"
48+
automationMongodConfFileName = "automation-mongod.conf"
49+
keyfileFilePath = "/var/lib/mongodb-mms-automation/authentication/keyfile"
4850

4951
automationAgentOptions = " -skipMongoStart -noDaemonize -useLocalMongoDbTools"
5052

@@ -82,6 +84,9 @@ type MongoDBStatefulSetOwner interface {
8284
DataVolumeName() string
8385
// LogsVolumeName returns the name that the data volume should have
8486
LogsVolumeName() string
87+
88+
// GetMongodConfiguration returns the MongoDB configuration for each member.
89+
GetMongodConfiguration() map[string]interface{}
8590
}
8691

8792
// BuildMongoDBReplicaSetStatefulSetModificationFunction builds the parts of the replica set that are common between every resource that implements
@@ -122,14 +127,14 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe
122127
singleModeVolumeClaim := func(s *appsv1.StatefulSet) {}
123128
if mdb.HasSeparateDataAndLogsVolumes() {
124129
logVolumeMount := statefulset.CreateVolumeMount(mdb.LogsVolumeName(), automationconfig.DefaultAgentLogPath)
125-
dataVolumeMount := statefulset.CreateVolumeMount(mdb.DataVolumeName(), "/data")
130+
dataVolumeMount := statefulset.CreateVolumeMount(mdb.DataVolumeName(), GetDBDataDir(mdb.GetMongodConfiguration()))
126131
dataVolumeClaim = statefulset.WithVolumeClaim(mdb.DataVolumeName(), dataPvc(mdb.DataVolumeName()))
127132
logVolumeClaim = statefulset.WithVolumeClaim(mdb.LogsVolumeName(), logsPvc(mdb.LogsVolumeName()))
128133
mongodbAgentVolumeMounts = append(mongodbAgentVolumeMounts, dataVolumeMount, logVolumeMount)
129134
mongodVolumeMounts = append(mongodVolumeMounts, dataVolumeMount, logVolumeMount)
130135
} else {
131136
mounts := []corev1.VolumeMount{
132-
statefulset.CreateVolumeMount(mdb.DataVolumeName(), "/data", statefulset.WithSubPath("data")),
137+
statefulset.CreateVolumeMount(mdb.DataVolumeName(), GetDBDataDir(mdb.GetMongodConfiguration()), statefulset.WithSubPath("data")),
133138
statefulset.CreateVolumeMount(mdb.DataVolumeName(), automationconfig.DefaultAgentLogPath, statefulset.WithSubPath("logs")),
134139
}
135140
mongodbAgentVolumeMounts = append(mongodbAgentVolumeMounts, mounts...)
@@ -165,7 +170,7 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe
165170
podtemplatespec.WithVolume(keyFileVolume),
166171
podtemplatespec.WithServiceAccount(mongodbDatabaseServiceAccountName),
167172
podtemplatespec.WithContainer(AgentName, mongodbAgentContainer(mdb.AutomationConfigSecretName(), mongodbAgentVolumeMounts)),
168-
podtemplatespec.WithContainer(MongodbName, mongodbContainer(mdb.GetMongoDBVersion(), mongodVolumeMounts)),
173+
podtemplatespec.WithContainer(MongodbName, mongodbContainer(mdb.GetMongoDBVersion(), mongodVolumeMounts, mdb.GetMongodConfiguration())),
169174
podtemplatespec.WithInitContainer(versionUpgradeHookName, versionUpgradeHookInit([]corev1.VolumeMount{hooksVolumeMount})),
170175
podtemplatespec.WithInitContainer(ReadinessProbeContainerName, readinessProbeInit([]corev1.VolumeMount{scriptsVolumeMount})),
171176
),
@@ -276,7 +281,16 @@ func getMongoDBImage(version string) string {
276281
return fmt.Sprintf("%s/%s:%s", repoUrl, mongoImageName, version)
277282
}
278283

279-
func mongodbContainer(version string, volumeMounts []corev1.VolumeMount) container.Modification {
284+
// GetDBDataDir returns the db path which should be used.
285+
func GetDBDataDir(additionalMongoDBConfig objx.Map) string {
286+
if additionalMongoDBConfig == nil {
287+
return defaultDataDir
288+
}
289+
return additionalMongoDBConfig.Get("storage.dbPath").Str(defaultDataDir)
290+
}
291+
292+
func mongodbContainer(version string, volumeMounts []corev1.VolumeMount, additionalMongoDBConfig map[string]interface{}) container.Modification {
293+
filePath := GetDBDataDir(additionalMongoDBConfig) + "/" + automationMongodConfFileName
280294
mongoDbCommand := fmt.Sprintf(`
281295
#run post-start hook to handle version changes
282296
/hooks/version-upgrade
@@ -291,7 +305,7 @@ tail -F /var/log/mongodb-mms-automation/mongodb.log > /dev/stdout &
291305
# start mongod with this configuration
292306
exec mongod -f %s;
293307
294-
`, automationconfFilePath, keyfileFilePath, automationconfFilePath)
308+
`, filePath, keyfileFilePath, filePath)
295309

296310
containerCommand := []string{
297311
"/bin/sh",

controllers/replica_set_controller.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"github.com/imdario/mergo"
8+
"github.com/stretchr/objx"
79
"os"
810

911
"github.com/mongodb/mongodb-kubernetes-operator/controllers/predicates"
@@ -25,13 +27,10 @@ import (
2527

2628
"github.com/pkg/errors"
2729

28-
"github.com/imdario/mergo"
29-
"github.com/mongodb/mongodb-kubernetes-operator/pkg/authentication/scram"
30-
"github.com/stretchr/objx"
31-
3230
"github.com/mongodb/mongodb-kubernetes-operator/controllers/construct"
3331
"github.com/mongodb/mongodb-kubernetes-operator/controllers/validation"
3432
"github.com/mongodb/mongodb-kubernetes-operator/controllers/watch"
33+
"github.com/mongodb/mongodb-kubernetes-operator/pkg/authentication/scram"
3534

3635
"github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/annotations"
3736
"github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/podtemplatespec"
@@ -441,6 +440,7 @@ func buildAutomationConfig(mdb mdbv1.MongoDBCommunity, auth automationconfig.Aut
441440
SetFCV(mdb.Spec.FeatureCompatibilityVersion).
442441
SetOptions(automationconfig.Options{DownloadBase: "/var/lib/mongodb-mms-automation"}).
443442
SetAuth(auth).
443+
SetDataDir(construct.GetDBDataDir(mdb.GetMongodConfiguration())).
444444
AddModifications(getMongodConfigModification(mdb)).
445445
AddModifications(modifications...).
446446
Build()

controllers/replicaset_controller_test.go

+39-6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/container"
78
"io/ioutil"
89
"os"
910
"reflect"
@@ -611,7 +612,7 @@ func TestReplicaSet_IsScaledUpToDesiredMembers_WhenFirstCreated(t *testing.T) {
611612
}
612613

613614
func TestVolumeClaimTemplates_Configuration(t *testing.T) {
614-
sts := performReconciliationAndGetStatefulSet(t, "volume_claim_templates_mdb.yaml")
615+
sts, _ := performReconciliationAndGetStatefulSet(t, "volume_claim_templates_mdb.yaml")
615616

616617
assert.Len(t, sts.Spec.VolumeClaimTemplates, 3)
617618

@@ -626,7 +627,7 @@ func TestVolumeClaimTemplates_Configuration(t *testing.T) {
626627
}
627628

628629
func TestChangeDataVolume_Configuration(t *testing.T) {
629-
sts := performReconciliationAndGetStatefulSet(t, "change_data_volume.yaml")
630+
sts, _ := performReconciliationAndGetStatefulSet(t, "change_data_volume.yaml")
630631
assert.Len(t, sts.Spec.VolumeClaimTemplates, 2)
631632

632633
dataVolume := sts.Spec.VolumeClaimTemplates[0]
@@ -639,7 +640,7 @@ func TestChangeDataVolume_Configuration(t *testing.T) {
639640
}
640641

641642
func TestCustomStorageClass_Configuration(t *testing.T) {
642-
sts := performReconciliationAndGetStatefulSet(t, "custom_storage_class.yaml")
643+
sts, _ := performReconciliationAndGetStatefulSet(t, "custom_storage_class.yaml")
643644

644645
dataVolume := sts.Spec.VolumeClaimTemplates[0]
645646

@@ -655,7 +656,7 @@ func TestCustomStorageClass_Configuration(t *testing.T) {
655656
}
656657

657658
func TestCustomTaintsAndTolerations_Configuration(t *testing.T) {
658-
sts := performReconciliationAndGetStatefulSet(t, "tolerations_example.yaml")
659+
sts, _ := performReconciliationAndGetStatefulSet(t, "tolerations_example.yaml")
659660

660661
assert.Len(t, sts.Spec.Template.Spec.Tolerations, 2)
661662
assert.Equal(t, "example-key", sts.Spec.Template.Spec.Tolerations[0].Key)
@@ -667,7 +668,39 @@ func TestCustomTaintsAndTolerations_Configuration(t *testing.T) {
667668
assert.Equal(t, corev1.TaintEffectNoExecute, sts.Spec.Template.Spec.Tolerations[1].Effect)
668669
}
669670

670-
func performReconciliationAndGetStatefulSet(t *testing.T, filePath string) appsv1.StatefulSet {
671+
func TestCustomDataDir_Configuration(t *testing.T) {
672+
sts, c := performReconciliationAndGetStatefulSet(t, "specify_data_dir.yaml")
673+
674+
agentContainer := container.GetByName("mongodb-agent", sts.Spec.Template.Spec.Containers)
675+
assert.NotNil(t, agentContainer)
676+
assertVolumeMountPath(t, agentContainer.VolumeMounts, "data-volume", "/some/path/db")
677+
678+
mongoContainer := container.GetByName("mongod", sts.Spec.Template.Spec.Containers)
679+
assert.NotNil(t, mongoContainer)
680+
681+
lastCommand := mongoContainer.Command[len(agentContainer.Command)-1]
682+
assert.Contains(t, lastCommand, "/some/path/db", "startup command should be using the newly specified path")
683+
684+
ac, err := automationconfig.ReadFromSecret(c, types.NamespacedName{Name: "example-mongodb-config", Namespace: "test-ns"})
685+
assert.NoError(t, err)
686+
687+
for _, p := range ac.Processes {
688+
actualStoragePath := p.Args26.Get("storage.dbPath").String()
689+
assert.Equal(t, "/some/path/db", actualStoragePath, "process dbPath should have been set")
690+
}
691+
}
692+
693+
func assertVolumeMountPath(t *testing.T, mounts []corev1.VolumeMount, name, path string) {
694+
for _, v := range mounts {
695+
if v.Name == name {
696+
assert.Equal(t, path, v.MountPath)
697+
return
698+
}
699+
}
700+
t.Fatalf("volume with name %s was not present!", name)
701+
}
702+
703+
func performReconciliationAndGetStatefulSet(t *testing.T, filePath string) (appsv1.StatefulSet, client.Client) {
671704
mdb, err := loadTestFixture(filePath)
672705
assert.NoError(t, err)
673706
mgr := client.NewManager(&mdb)
@@ -678,7 +711,7 @@ func performReconciliationAndGetStatefulSet(t *testing.T, filePath string) appsv
678711

679712
sts, err := mgr.Client.GetStatefulSet(mdb.NamespacedName())
680713
assert.NoError(t, err)
681-
return sts
714+
return sts, mgr.Client
682715
}
683716

684717
func generatePasswordsForAllUsers(mdb mdbv1.MongoDBCommunity, c client.Client) error {
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
apiVersion: mongodbcommunity.mongodb.com/v1
3+
kind: MongoDBCommunity
4+
metadata:
5+
name: example-mongodb
6+
namespace: test-ns
7+
spec:
8+
members: 3
9+
type: ReplicaSet
10+
version: "4.2.6"
11+
security:
12+
authentication:
13+
modes: ["SCRAM"]
14+
users:
15+
- name: my-user
16+
db: admin
17+
passwordSecretRef:
18+
name: my-user-password
19+
roles:
20+
- name: clusterAdmin
21+
db: admin
22+
- name: userAdminAnyDatabase
23+
db: admin
24+
scramCredentialsSecretName: my-scram
25+
additionalMongodConfig:
26+
storage.dbPath: /some/path/db

docs/RELEASE_NOTES.md

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
- MongoDB database of the statefulSet is managed using distinct Role, ServiceAccount and RoleBinding.
77
- TLS Secret can also contain a single "tls.pem" entry, containing the concatenation of the certificate and key
88
- If a TLS secret contains all of "tls.key", "tls.crt" and "tls.pem" entries, the operator will raise an error if the "tls.pem" one is not equal to the concatenation of "tls.crt" with "tls.key"
9+
10+
## MongoDBCommunity Resource
11+
* Changes
12+
* Specifying `spec.additionalMongodConfig.storage.dbPath` will now be respected correctly.
13+
14+
915
## Updated Image Tags
1016

1117
- mongodb-kubernetes-operator:0.7.1

pkg/automationconfig/automation_config_builder.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type Builder struct {
4747
cafilePath string
4848
sslConfig *TLS
4949
tlsConfig *TLS
50+
dataDir string
5051
}
5152

5253
func NewBuilder() *Builder {
@@ -108,6 +109,11 @@ func (b *Builder) SetName(name string) *Builder {
108109
return b
109110
}
110111

112+
func (b *Builder) SetDataDir(dataDir string) *Builder {
113+
b.dataDir = dataDir
114+
return b
115+
}
116+
111117
func (b *Builder) SetFCV(fcv string) *Builder {
112118
b.fcv = fcv
113119
return b
@@ -209,6 +215,12 @@ func (b *Builder) Build() (AutomationConfig, error) {
209215
if err := b.setFeatureCompatibilityVersionIfUpgradeIsHappening(); err != nil {
210216
return AutomationConfig{}, errors.Errorf("can't build the automation config: %s", err)
211217
}
218+
219+
dataDir := DefaultMongoDBDataDir
220+
if b.dataDir != "" {
221+
dataDir = b.dataDir
222+
}
223+
212224
totalVotes := 0
213225
for i, h := range hostnames {
214226

@@ -226,7 +238,7 @@ func (b *Builder) Build() (AutomationConfig, error) {
226238
}
227239

228240
process.SetPort(27017)
229-
process.SetStoragePath(DefaultMongoDBDataDir)
241+
process.SetStoragePath(dataDir)
230242
process.SetReplicaSetName(b.name)
231243

232244
for _, mod := range b.processModifications {

test/e2e/replica_set_mongod_config/replica_set_mongod_config_test.go

+18-5
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,30 @@ func TestReplicaSet(t *testing.T) {
3737
t.Fatal(err)
3838
}
3939

40-
// Override the journal compressor setting
41-
setting := "storage.wiredTiger.engineConfig.journalCompressor"
42-
value := "zlib"
40+
settings := []string{
41+
"storage.wiredTiger.engineConfig.journalCompressor",
42+
"storage.dbPath",
43+
}
44+
45+
values := []string{
46+
"zlib",
47+
"/some/path/db",
48+
}
49+
50+
// Override the journal compressor and dbPath settings
4351
mongodConfig := objx.New(map[string]interface{}{})
44-
mongodConfig.Set(setting, value)
52+
for i := range settings {
53+
mongodConfig.Set(settings[i], values[i])
54+
}
55+
4556
mdb.Spec.AdditionalMongodConfig.Object = mongodConfig
4657

4758
t.Run("Create MongoDB Resource", mongodbtests.CreateMongoDBResource(&mdb, ctx))
4859
t.Run("Basic tests", mongodbtests.BasicFunctionality(&mdb))
4960
t.Run("Ensure Authentication", tester.EnsureAuthenticationIsConfigured(3))
5061
t.Run("Test Basic Connectivity", tester.ConnectivitySucceeds())
5162
t.Run("AutomationConfig has the correct version", mongodbtests.AutomationConfigVersionHasTheExpectedVersion(&mdb, 1))
52-
t.Run("Mongod config has been set", tester.EnsureMongodConfig(setting, value))
63+
for i := range settings {
64+
t.Run(fmt.Sprintf("Mongod setting %s has been set", settings[i]), tester.EnsureMongodConfig(settings[i], values[i]))
65+
}
5366
}

0 commit comments

Comments
 (0)