Skip to content

Commit f75129a

Browse files
committed
Added Merging of StatefulSet
1 parent b29af36 commit f75129a

File tree

4 files changed

+144
-133
lines changed

4 files changed

+144
-133
lines changed

pkg/kube/podtemplatespec/podspec_template.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package podtemplatespec
22

33
import (
4-
"github.com/mongodb/mongodb-kubernetes-operator/pkg/util/merge"
5-
64
"github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/container"
75
corev1 "k8s.io/api/core/v1"
86
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -226,11 +224,6 @@ func WithVolumeMounts(containerName string, volumeMounts ...corev1.VolumeMount)
226224
}
227225
}
228226

229-
func MergePodTemplateSpecs(defaultTemplate, overrideTemplate corev1.PodTemplateSpec) (corev1.PodTemplateSpec, error) {
230-
// TODO: remove in place of direct call to merge.PodTemplateSpecs
231-
return merge.PodTemplateSpecs(defaultTemplate, overrideTemplate), nil
232-
}
233-
234227
// findContainerByName will find either a container or init container by name in a pod template spec
235228
func findContainerByName(name string, podTemplateSpec *corev1.PodTemplateSpec) *corev1.Container {
236229
containerIdx := findIndexByName(name, podTemplateSpec.Spec.Containers)

pkg/kube/podtemplatespec/podspec_template_test.go

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package podtemplatespec
33
import (
44
"testing"
55

6+
"github.com/mongodb/mongodb-kubernetes-operator/pkg/util/merge"
7+
68
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
79

810
"github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/container"
@@ -115,8 +117,7 @@ func TestMerge(t *testing.T) {
115117
defaultSpec := getDefaultPodSpec()
116118
customSpec := getCustomPodSpec()
117119

118-
mergedSpec, err := MergePodTemplateSpecs(defaultSpec, customSpec)
119-
assert.NoError(t, err)
120+
mergedSpec := merge.PodTemplateSpecs(defaultSpec, customSpec)
120121

121122
initContainerDefault := getDefaultContainer()
122123
initContainerDefault.Name = "init-container-default"
@@ -178,35 +179,30 @@ func TestMergeFromEmpty(t *testing.T) {
178179
defaultPodSpec := corev1.PodTemplateSpec{}
179180
customPodSpecTemplate := getCustomPodSpec()
180181

181-
mergedPodTemplateSpec, err := MergePodTemplateSpecs(defaultPodSpec, customPodSpecTemplate)
182-
183-
assert.NoError(t, err)
182+
mergedPodTemplateSpec := merge.PodTemplateSpecs(defaultPodSpec, customPodSpecTemplate)
184183
assert.Equal(t, customPodSpecTemplate, mergedPodTemplateSpec)
185184
}
186185

187186
func TestMergeWithEmpty(t *testing.T) {
188187
defaultPodSpec := getDefaultPodSpec()
189188
customPodSpecTemplate := corev1.PodTemplateSpec{}
190189

191-
mergedPodTemplateSpec, err := MergePodTemplateSpecs(defaultPodSpec, customPodSpecTemplate)
190+
mergedPodTemplateSpec := merge.PodTemplateSpecs(defaultPodSpec, customPodSpecTemplate)
192191

193-
assert.NoError(t, err)
194192
assert.Equal(t, defaultPodSpec, mergedPodTemplateSpec)
195193
}
196194

197195
func TestMultipleMerges(t *testing.T) {
198196
defaultPodSpec := getDefaultPodSpec()
199197
customPodSpecTemplate := getCustomPodSpec()
200198

201-
referenceSpec, err := MergePodTemplateSpecs(defaultPodSpec, customPodSpecTemplate)
202-
assert.NoError(t, err)
199+
referenceSpec := merge.PodTemplateSpecs(defaultPodSpec, customPodSpecTemplate)
203200

204201
mergedSpec := defaultPodSpec
205202

206203
// multiple merges must give the same result
207204
for i := 0; i < 3; i++ {
208-
mergedSpec, err := MergePodTemplateSpecs(mergedSpec, customPodSpecTemplate)
209-
assert.NoError(t, err)
205+
mergedSpec := merge.PodTemplateSpecs(mergedSpec, customPodSpecTemplate)
210206
assert.Equal(t, referenceSpec, mergedSpec)
211207
}
212208
}
@@ -234,8 +230,7 @@ func TestMergeEnvironmentVariables(t *testing.T) {
234230
customSpec := getCustomPodSpec()
235231
customSpec.Spec.Containers = []corev1.Container{overrideOtherDefaultContainer}
236232

237-
mergedSpec, err := MergePodTemplateSpecs(defaultSpec, customSpec)
238-
assert.NoError(t, err)
233+
mergedSpec := merge.PodTemplateSpecs(defaultSpec, customSpec)
239234

240235
mergedContainer := mergedSpec.Spec.Containers[0]
241236

@@ -270,8 +265,7 @@ func TestMergeContainer(t *testing.T) {
270265
customSpec := getCustomPodSpec()
271266
customSpec.Spec.Containers = []corev1.Container{getCustomContainer(), overrideDefaultContainer, overrideOtherDefaultContainer}
272267

273-
mergedSpec, err := MergePodTemplateSpecs(defaultSpec, customSpec)
274-
assert.NoError(t, err)
268+
mergedSpec := merge.PodTemplateSpecs(defaultSpec, customSpec)
275269

276270
assert.Len(t, mergedSpec.Spec.Containers, 3)
277271
assert.Equal(t, getCustomContainer(), mergedSpec.Spec.Containers[1])
@@ -338,8 +332,7 @@ func TestMergeVolumes_DoesNotAddDuplicatesWithSameName(t *testing.T) {
338332
Name: "new-volume-3",
339333
})
340334

341-
mergedPodSpecTemplate, err := MergePodTemplateSpecs(defaultPodSpec, overridePodSpec)
342-
assert.NoError(t, err)
335+
mergedPodSpecTemplate := merge.PodTemplateSpecs(defaultPodSpec, overridePodSpec)
343336

344337
assert.Len(t, mergedPodSpecTemplate.Spec.Volumes, 3)
345338
assert.Equal(t, "new-volume", mergedPodSpecTemplate.Spec.Volumes[0].Name)

pkg/kube/statefulset/statefulset.go

Lines changed: 2 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
package statefulset
22

33
import (
4-
"sort"
5-
6-
"github.com/mongodb/mongodb-kubernetes-operator/pkg/util/contains"
7-
8-
"github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/podtemplatespec"
9-
10-
"github.com/imdario/mergo"
4+
"github.com/mongodb/mongodb-kubernetes-operator/pkg/util/merge"
115
apiErrors "k8s.io/apimachinery/pkg/api/errors"
126
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
137
"k8s.io/apimachinery/pkg/types"
@@ -280,109 +274,8 @@ func WithVolumeClaim(name string, f func(*corev1.PersistentVolumeClaim)) Modific
280274

281275
func WithCustomSpecs(spec appsv1.StatefulSetSpec) Modification {
282276
return func(set *appsv1.StatefulSet) {
283-
m, err := mergeStatefulSetSpecs(set.Spec, spec)
284-
if err != nil {
285-
return
286-
}
287-
set.Spec = m
288-
}
289-
}
290-
291-
func mergeStatefulSetSpecs(defaultSpec, overrideSpec appsv1.StatefulSetSpec) (appsv1.StatefulSetSpec, error) {
292-
// PodTemplateSpec needs to be manually merged
293-
mergedPodTemplateSpec, err := podtemplatespec.MergePodTemplateSpecs(defaultSpec.Template, overrideSpec.Template)
294-
if err != nil {
295-
return appsv1.StatefulSetSpec{}, err
296-
}
297-
298-
// VolumeClaimTemplates needs to be manually merged
299-
mergedVolumeClaimTemplates, err := mergeVolumeClaimTemplates(defaultSpec.VolumeClaimTemplates, overrideSpec.VolumeClaimTemplates)
300-
if err != nil {
301-
return appsv1.StatefulSetSpec{}, err
302-
}
303-
304-
// Merging the rest with mergo
305-
if err := mergo.Merge(&defaultSpec, overrideSpec, mergo.WithOverride); err != nil {
306-
return appsv1.StatefulSetSpec{}, err
307-
}
308-
309-
// Assigning merged vales AFTER the merge with mergo or they would be overwritten
310-
defaultSpec.Template = mergedPodTemplateSpec
311-
defaultSpec.VolumeClaimTemplates = mergedVolumeClaimTemplates
312-
return defaultSpec, nil
313-
}
314-
315-
func mergeSingleVolumeClaimTemplate(defaultPvc corev1.PersistentVolumeClaim, overridePvc corev1.PersistentVolumeClaim) corev1.PersistentVolumeClaim {
316-
317-
if overridePvc.Spec.VolumeMode != nil {
318-
defaultPvc.Spec.VolumeMode = overridePvc.Spec.VolumeMode
319-
}
320-
321-
if overridePvc.Spec.StorageClassName != nil {
322-
defaultPvc.Spec.StorageClassName = overridePvc.Spec.StorageClassName
323-
}
324-
325-
for _, accessMode := range overridePvc.Spec.AccessModes {
326-
if !contains.AccessMode(defaultPvc.Spec.AccessModes, accessMode) {
327-
defaultPvc.Spec.AccessModes = append(defaultPvc.Spec.AccessModes, accessMode)
328-
}
329-
}
330-
331-
if overridePvc.Spec.Selector != nil {
332-
defaultPvc.Spec.Selector = overridePvc.Spec.Selector
333-
}
334-
335-
if overridePvc.Spec.Resources.Limits != nil {
336-
defaultPvc.Spec.Resources.Limits = overridePvc.Spec.Resources.Limits
337-
}
338-
339-
if overridePvc.Spec.Resources.Requests != nil {
340-
defaultPvc.Spec.Resources.Requests = overridePvc.Spec.Resources.Requests
341-
}
342-
343-
if overridePvc.Spec.DataSource != nil {
344-
defaultPvc.Spec.DataSource = overridePvc.Spec.DataSource
345-
}
346-
347-
return defaultPvc
348-
}
349-
350-
func mergeVolumeClaimTemplates(defaultTemplates []corev1.PersistentVolumeClaim, overrideTemplates []corev1.PersistentVolumeClaim) ([]corev1.PersistentVolumeClaim, error) {
351-
defaultMountsMap := createVolumeClaimMap(defaultTemplates)
352-
overrideMountsMap := createVolumeClaimMap(overrideTemplates)
353-
354-
mergedMap := map[string]corev1.PersistentVolumeClaim{}
355-
356-
for _, vct := range defaultMountsMap {
357-
mergedMap[vct.Name] = vct
358-
}
359-
360-
for _, overrideClaim := range overrideMountsMap {
361-
if defaultClaim, ok := defaultMountsMap[overrideClaim.Name]; ok {
362-
mergedMap[overrideClaim.Name] = mergeSingleVolumeClaimTemplate(defaultClaim, overrideClaim)
363-
} else {
364-
mergedMap[overrideClaim.Name] = overrideClaim
365-
}
366-
}
367-
368-
var mergedVolumes []corev1.PersistentVolumeClaim
369-
for _, v := range mergedMap {
370-
mergedVolumes = append(mergedVolumes, v)
371-
}
372-
373-
sort.SliceStable(mergedVolumes, func(i, j int) bool {
374-
return mergedVolumes[i].Name < mergedVolumes[j].Name
375-
})
376-
377-
return mergedVolumes, nil
378-
}
379-
380-
func createVolumeClaimMap(volumeMounts []corev1.PersistentVolumeClaim) map[string]corev1.PersistentVolumeClaim {
381-
mountMap := make(map[string]corev1.PersistentVolumeClaim)
382-
for _, m := range volumeMounts {
383-
mountMap[m.Name] = m
277+
set.Spec = merge.StatefulSetSpecs(set.Spec, spec)
384278
}
385-
return mountMap
386279
}
387280

388281
func findVolumeClaimIndexByName(name string, pvcs []corev1.PersistentVolumeClaim) int {

pkg/util/merge/merge_statefulset.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package merge
2+
3+
import (
4+
"sort"
5+
6+
"github.com/mongodb/mongodb-kubernetes-operator/pkg/util/contains"
7+
appsv1 "k8s.io/api/apps/v1"
8+
corev1 "k8s.io/api/core/v1"
9+
)
10+
11+
// StatefulSets merges two StatefulSets together.
12+
func StatefulSets(defaultStatefulSet, overrideStatefulSet appsv1.StatefulSet) appsv1.StatefulSet {
13+
mergedSts := defaultStatefulSet
14+
mergedSts.Labels = StringToStringMap(defaultStatefulSet.Labels, overrideStatefulSet.Labels)
15+
if overrideStatefulSet.Namespace != "" {
16+
mergedSts.Namespace = overrideStatefulSet.Namespace
17+
}
18+
if overrideStatefulSet.Name != "" {
19+
mergedSts.Name = overrideStatefulSet.Name
20+
}
21+
mergedSts.Spec = StatefulSetSpecs(defaultStatefulSet.Spec, overrideStatefulSet.Spec)
22+
return mergedSts
23+
}
24+
25+
// StatefulSetSpecs merges two StatefulSetSpecs together.
26+
func StatefulSetSpecs(defaultSpec, overrideSpec appsv1.StatefulSetSpec) appsv1.StatefulSetSpec {
27+
mergedSpec := defaultSpec
28+
if overrideSpec.Replicas != nil {
29+
mergedSpec.Replicas = overrideSpec.Replicas
30+
}
31+
32+
if overrideSpec.Selector != nil {
33+
mergedSpec.Selector = overrideSpec.Selector
34+
}
35+
36+
if overrideSpec.PodManagementPolicy != "" {
37+
mergedSpec.PodManagementPolicy = overrideSpec.PodManagementPolicy
38+
}
39+
40+
if overrideSpec.RevisionHistoryLimit != nil {
41+
mergedSpec.RevisionHistoryLimit = overrideSpec.RevisionHistoryLimit
42+
}
43+
44+
if overrideSpec.UpdateStrategy.Type != "" {
45+
mergedSpec.UpdateStrategy.Type = overrideSpec.UpdateStrategy.Type
46+
}
47+
48+
if overrideSpec.UpdateStrategy.RollingUpdate != nil {
49+
mergedSpec.UpdateStrategy.RollingUpdate = overrideSpec.UpdateStrategy.RollingUpdate
50+
}
51+
52+
if overrideSpec.ServiceName != "" {
53+
mergedSpec.ServiceName = overrideSpec.ServiceName
54+
}
55+
56+
mergedSpec.Template = PodTemplateSpecs(defaultSpec.Template, overrideSpec.Template)
57+
mergedSpec.VolumeClaimTemplates = VolumeClaimTemplates(defaultSpec.VolumeClaimTemplates, overrideSpec.VolumeClaimTemplates)
58+
return mergedSpec
59+
}
60+
61+
func VolumeClaimTemplates(defaultTemplates []corev1.PersistentVolumeClaim, overrideTemplates []corev1.PersistentVolumeClaim) []corev1.PersistentVolumeClaim {
62+
defaultMountsMap := createVolumeClaimMap(defaultTemplates)
63+
overrideMountsMap := createVolumeClaimMap(overrideTemplates)
64+
65+
mergedMap := map[string]corev1.PersistentVolumeClaim{}
66+
67+
for _, vct := range defaultMountsMap {
68+
mergedMap[vct.Name] = vct
69+
}
70+
71+
for _, overrideClaim := range overrideMountsMap {
72+
if defaultClaim, ok := defaultMountsMap[overrideClaim.Name]; ok {
73+
mergedMap[overrideClaim.Name] = PersistentVolumeClaim(defaultClaim, overrideClaim)
74+
} else {
75+
mergedMap[overrideClaim.Name] = overrideClaim
76+
}
77+
}
78+
79+
var mergedVolumes []corev1.PersistentVolumeClaim
80+
for _, v := range mergedMap {
81+
mergedVolumes = append(mergedVolumes, v)
82+
}
83+
84+
sort.SliceStable(mergedVolumes, func(i, j int) bool {
85+
return mergedVolumes[i].Name < mergedVolumes[j].Name
86+
})
87+
88+
return mergedVolumes
89+
}
90+
91+
func createVolumeClaimMap(volumeMounts []corev1.PersistentVolumeClaim) map[string]corev1.PersistentVolumeClaim {
92+
mountMap := make(map[string]corev1.PersistentVolumeClaim)
93+
for _, m := range volumeMounts {
94+
mountMap[m.Name] = m
95+
}
96+
return mountMap
97+
}
98+
99+
func PersistentVolumeClaim(defaultPvc corev1.PersistentVolumeClaim, overridePvc corev1.PersistentVolumeClaim) corev1.PersistentVolumeClaim {
100+
101+
if overridePvc.Spec.VolumeMode != nil {
102+
defaultPvc.Spec.VolumeMode = overridePvc.Spec.VolumeMode
103+
}
104+
105+
if overridePvc.Spec.StorageClassName != nil {
106+
defaultPvc.Spec.StorageClassName = overridePvc.Spec.StorageClassName
107+
}
108+
109+
for _, accessMode := range overridePvc.Spec.AccessModes {
110+
if !contains.AccessMode(defaultPvc.Spec.AccessModes, accessMode) {
111+
defaultPvc.Spec.AccessModes = append(defaultPvc.Spec.AccessModes, accessMode)
112+
}
113+
}
114+
115+
if overridePvc.Spec.Selector != nil {
116+
defaultPvc.Spec.Selector = overridePvc.Spec.Selector
117+
}
118+
119+
if overridePvc.Spec.Resources.Limits != nil {
120+
defaultPvc.Spec.Resources.Limits = overridePvc.Spec.Resources.Limits
121+
}
122+
123+
if overridePvc.Spec.Resources.Requests != nil {
124+
defaultPvc.Spec.Resources.Requests = overridePvc.Spec.Resources.Requests
125+
}
126+
127+
if overridePvc.Spec.DataSource != nil {
128+
defaultPvc.Spec.DataSource = overridePvc.Spec.DataSource
129+
}
130+
131+
return defaultPvc
132+
}

0 commit comments

Comments
 (0)