Skip to content

Commit ed780e1

Browse files
committed
Change merge strategy for service volumes
Signed-off-by: Stoica-Marcu Floris-Andrei <floris.sm@gmail.com>
1 parent c7bafb8 commit ed780e1

2 files changed

Lines changed: 106 additions & 0 deletions

File tree

cli/compose/loader/merge.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig,
5858
reflect.TypeOf([]types.ServiceSecretConfig{}): mergeSlice(toServiceSecretConfigsMap, toServiceSecretConfigsSlice),
5959
reflect.TypeOf([]types.ServiceConfigObjConfig{}): mergeSlice(toServiceConfigObjConfigsMap, toSServiceConfigObjConfigsSlice),
6060
reflect.TypeOf(&types.UlimitsConfig{}): mergeUlimitsConfig,
61+
reflect.TypeOf([]types.ServiceVolumeConfig{}): mergeSlice(toServiceVolumeConfigsMap, toServiceVolumeConfigsSlice),
6162
reflect.TypeOf(&types.ServiceNetworkConfig{}): mergeServiceNetworkConfig,
6263
},
6364
}
@@ -116,6 +117,18 @@ func toServicePortConfigsMap(s interface{}) (map[interface{}]interface{}, error)
116117
return m, nil
117118
}
118119

120+
func toServiceVolumeConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
121+
volumes, ok := s.([]types.ServiceVolumeConfig)
122+
if !ok {
123+
return nil, errors.Errorf("not a serviceVolumeConfig slice: %v", s)
124+
}
125+
m := map[interface{}]interface{}{}
126+
for _, v := range volumes {
127+
m[v.Target] = v
128+
}
129+
return m, nil
130+
}
131+
119132
func toServiceSecretConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
120133
s := []types.ServiceSecretConfig{}
121134
for _, v := range m {
@@ -146,6 +159,16 @@ func toServicePortConfigsSlice(dst reflect.Value, m map[interface{}]interface{})
146159
return nil
147160
}
148161

162+
func toServiceVolumeConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
163+
s := []types.ServiceVolumeConfig{}
164+
for _, v := range m {
165+
s = append(s, v.(types.ServiceVolumeConfig))
166+
}
167+
sort.Slice(s, func(i, j int) bool { return s[i].Target < s[j].Target })
168+
dst.Set(reflect.ValueOf(s))
169+
return nil
170+
}
171+
149172
type tomapFn func(s interface{}) (map[interface{}]interface{}, error)
150173
type writeValueFromMapFn func(reflect.Value, map[interface{}]interface{}) error
151174

@@ -211,6 +234,14 @@ func mergeUlimitsConfig(dst, src reflect.Value) error {
211234
return nil
212235
}
213236

237+
//nolint: unparam
238+
func mergeServiceVolumeConfig(dst, src reflect.Value) error {
239+
if dst.Elem().FieldByName("target").String() == src.Elem().FieldByName("target").String() {
240+
dst.Set(src.Elem())
241+
}
242+
return nil
243+
}
244+
214245
//nolint: unparam
215246
func mergeServiceNetworkConfig(dst, src reflect.Value) error {
216247
if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() {

cli/compose/loader/merge_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,81 @@ func TestLoadMultipleNetworks(t *testing.T) {
10171017
}, config)
10181018
}
10191019

1020+
func TestLoadMultipleServiceVolumes(t *testing.T) {
1021+
base := map[string]interface{}{
1022+
"version": "3.7",
1023+
"services": map[string]interface{}{
1024+
"foo": map[string]interface{}{
1025+
"image": "baz",
1026+
"volumes": []interface{}{
1027+
map[string]interface{}{
1028+
"type": "volume",
1029+
"source": "sourceVolume",
1030+
"target": "/var/app",
1031+
},
1032+
},
1033+
},
1034+
},
1035+
"volumes": map[string]interface{}{
1036+
"sourceVolume": map[string]interface{}{},
1037+
},
1038+
"networks": map[string]interface{}{},
1039+
"secrets": map[string]interface{}{},
1040+
"configs": map[string]interface{}{},
1041+
}
1042+
override := map[string]interface{}{
1043+
"version": "3.7",
1044+
"services": map[string]interface{}{
1045+
"foo": map[string]interface{}{
1046+
"image": "baz",
1047+
"volumes": []interface{}{
1048+
map[string]interface{}{
1049+
"type": "volume",
1050+
"source": "/local",
1051+
"target": "/var/app",
1052+
},
1053+
},
1054+
},
1055+
},
1056+
"volumes": map[string]interface{}{},
1057+
"networks": map[string]interface{}{},
1058+
"secrets": map[string]interface{}{},
1059+
"configs": map[string]interface{}{},
1060+
}
1061+
configDetails := types.ConfigDetails{
1062+
ConfigFiles: []types.ConfigFile{
1063+
{Filename: "base.yml", Config: base},
1064+
{Filename: "override.yml", Config: override},
1065+
},
1066+
}
1067+
config, err := Load(configDetails)
1068+
assert.NilError(t, err)
1069+
assert.DeepEqual(t, &types.Config{
1070+
Filename: "base.yml",
1071+
Version: "3.7",
1072+
Services: []types.ServiceConfig{
1073+
{
1074+
Name: "foo",
1075+
Image: "baz",
1076+
Environment: types.MappingWithEquals{},
1077+
Volumes: []types.ServiceVolumeConfig{
1078+
{
1079+
Type: "volume",
1080+
Source: "/local",
1081+
Target: "/var/app",
1082+
},
1083+
},
1084+
},
1085+
},
1086+
Volumes: map[string]types.VolumeConfig{
1087+
"sourceVolume": {},
1088+
},
1089+
Secrets: map[string]types.SecretConfig{},
1090+
Configs: map[string]types.ConfigObjConfig{},
1091+
Networks: map[string]types.NetworkConfig{},
1092+
}, config)
1093+
}
1094+
10201095
func TestMergeUlimitsConfig(t *testing.T) {
10211096
specials := &specials{
10221097
m: map[reflect.Type]func(dst, src reflect.Value) error{

0 commit comments

Comments
 (0)