Change merge strategy for service volumes

Signed-off-by: Stoica-Marcu Floris-Andrei <floris.sm@gmail.com>
This commit is contained in:
Stoica-Marcu Floris-Andrei 2020-09-24 04:37:13 +03:00 committed by Sebastiaan van Stijn
parent dfc214115b
commit fbea85d472
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
2 changed files with 106 additions and 0 deletions

View File

@ -58,6 +58,7 @@ func mergeServices(base, override []types.ServiceConfig) ([]types.ServiceConfig,
reflect.TypeOf([]types.ServiceSecretConfig{}): mergeSlice(toServiceSecretConfigsMap, toServiceSecretConfigsSlice), reflect.TypeOf([]types.ServiceSecretConfig{}): mergeSlice(toServiceSecretConfigsMap, toServiceSecretConfigsSlice),
reflect.TypeOf([]types.ServiceConfigObjConfig{}): mergeSlice(toServiceConfigObjConfigsMap, toSServiceConfigObjConfigsSlice), reflect.TypeOf([]types.ServiceConfigObjConfig{}): mergeSlice(toServiceConfigObjConfigsMap, toSServiceConfigObjConfigsSlice),
reflect.TypeOf(&types.UlimitsConfig{}): mergeUlimitsConfig, reflect.TypeOf(&types.UlimitsConfig{}): mergeUlimitsConfig,
reflect.TypeOf([]types.ServiceVolumeConfig{}): mergeSlice(toServiceVolumeConfigsMap, toServiceVolumeConfigsSlice),
reflect.TypeOf(&types.ServiceNetworkConfig{}): mergeServiceNetworkConfig, reflect.TypeOf(&types.ServiceNetworkConfig{}): mergeServiceNetworkConfig,
}, },
} }
@ -116,6 +117,18 @@ func toServicePortConfigsMap(s interface{}) (map[interface{}]interface{}, error)
return m, nil return m, nil
} }
func toServiceVolumeConfigsMap(s interface{}) (map[interface{}]interface{}, error) {
volumes, ok := s.([]types.ServiceVolumeConfig)
if !ok {
return nil, errors.Errorf("not a serviceVolumeConfig slice: %v", s)
}
m := map[interface{}]interface{}{}
for _, v := range volumes {
m[v.Target] = v
}
return m, nil
}
func toServiceSecretConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error { func toServiceSecretConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
s := []types.ServiceSecretConfig{} s := []types.ServiceSecretConfig{}
for _, v := range m { for _, v := range m {
@ -146,6 +159,16 @@ func toServicePortConfigsSlice(dst reflect.Value, m map[interface{}]interface{})
return nil return nil
} }
func toServiceVolumeConfigsSlice(dst reflect.Value, m map[interface{}]interface{}) error {
s := []types.ServiceVolumeConfig{}
for _, v := range m {
s = append(s, v.(types.ServiceVolumeConfig))
}
sort.Slice(s, func(i, j int) bool { return s[i].Target < s[j].Target })
dst.Set(reflect.ValueOf(s))
return nil
}
type tomapFn func(s interface{}) (map[interface{}]interface{}, error) type tomapFn func(s interface{}) (map[interface{}]interface{}, error)
type writeValueFromMapFn func(reflect.Value, map[interface{}]interface{}) error type writeValueFromMapFn func(reflect.Value, map[interface{}]interface{}) error
@ -211,6 +234,14 @@ func mergeUlimitsConfig(dst, src reflect.Value) error {
return nil return nil
} }
//nolint: unparam
func mergeServiceVolumeConfig(dst, src reflect.Value) error {
if dst.Elem().FieldByName("target").String() == src.Elem().FieldByName("target").String() {
dst.Set(src.Elem())
}
return nil
}
//nolint: unparam //nolint: unparam
func mergeServiceNetworkConfig(dst, src reflect.Value) error { func mergeServiceNetworkConfig(dst, src reflect.Value) error {
if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() { if src.Interface() != reflect.Zero(reflect.TypeOf(src.Interface())).Interface() {

View File

@ -1017,6 +1017,81 @@ func TestLoadMultipleNetworks(t *testing.T) {
}, config) }, config)
} }
func TestLoadMultipleServiceVolumes(t *testing.T) {
base := map[string]interface{}{
"version": "3.7",
"services": map[string]interface{}{
"foo": map[string]interface{}{
"image": "baz",
"volumes": []interface{}{
map[string]interface{}{
"type": "volume",
"source": "sourceVolume",
"target": "/var/app",
},
},
},
},
"volumes": map[string]interface{}{
"sourceVolume": map[string]interface{}{},
},
"networks": map[string]interface{}{},
"secrets": map[string]interface{}{},
"configs": map[string]interface{}{},
}
override := map[string]interface{}{
"version": "3.7",
"services": map[string]interface{}{
"foo": map[string]interface{}{
"image": "baz",
"volumes": []interface{}{
map[string]interface{}{
"type": "volume",
"source": "/local",
"target": "/var/app",
},
},
},
},
"volumes": map[string]interface{}{},
"networks": map[string]interface{}{},
"secrets": map[string]interface{}{},
"configs": map[string]interface{}{},
}
configDetails := types.ConfigDetails{
ConfigFiles: []types.ConfigFile{
{Filename: "base.yml", Config: base},
{Filename: "override.yml", Config: override},
},
}
config, err := Load(configDetails)
assert.NilError(t, err)
assert.DeepEqual(t, &types.Config{
Filename: "base.yml",
Version: "3.7",
Services: []types.ServiceConfig{
{
Name: "foo",
Image: "baz",
Environment: types.MappingWithEquals{},
Volumes: []types.ServiceVolumeConfig{
{
Type: "volume",
Source: "/local",
Target: "/var/app",
},
},
},
},
Volumes: map[string]types.VolumeConfig{
"sourceVolume": {},
},
Secrets: map[string]types.SecretConfig{},
Configs: map[string]types.ConfigObjConfig{},
Networks: map[string]types.NetworkConfig{},
}, config)
}
func TestMergeUlimitsConfig(t *testing.T) { func TestMergeUlimitsConfig(t *testing.T) {
specials := &specials{ specials := &specials{
m: map[reflect.Type]func(dst, src reflect.Value) error{ m: map[reflect.Type]func(dst, src reflect.Value) error{