Skip to content

Commit 5a8e677

Browse files
committed
add custom merge function for IPAM config
Signed-off-by: Guillaume Lours <[email protected]>
1 parent f17ec54 commit 5a8e677

File tree

4 files changed

+131
-4
lines changed

4 files changed

+131
-4
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
github.com/docker/go-units v0.5.0
99
github.com/google/go-cmp v0.5.9
1010
github.com/mattn/go-shellwords v1.0.12
11+
github.com/mitchellh/copystructure v1.2.0
1112
github.com/mitchellh/mapstructure v1.5.0
1213
github.com/opencontainers/go-digest v1.0.0
1314
github.com/pkg/errors v0.9.1
@@ -22,7 +23,6 @@ require (
2223

2324
require (
2425
github.com/davecgh/go-spew v1.1.1 // indirect
25-
github.com/mitchellh/copystructure v1.2.0 // indirect
2626
github.com/mitchellh/reflectwalk v1.0.2 // indirect
2727
github.com/pmezard/go-difflib v1.0.0 // indirect
2828
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect

override/merge.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type merger func(any, any, tree.Path) (any, error)
3939
var mergeSpecials = map[tree.Path]merger{}
4040

4141
func init() {
42+
mergeSpecials["networks.*.ipam.config"] = mergeIPAMConfig
4243
mergeSpecials["services.*.annotations"] = mergeToSequence
4344
mergeSpecials["services.*.build"] = mergeBuild
4445
mergeSpecials["services.*.build.args"] = mergeToSequence
@@ -197,6 +198,41 @@ func mergeUlimit(_ any, o any, p tree.Path) (any, error) {
197198
return o, nil
198199
}
199200

201+
func mergeIPAMConfig(c any, o any, path tree.Path) (any, error) {
202+
var ipamConfigs []any
203+
for _, original := range c.([]any) {
204+
right := convertIntoMapping(original, nil)
205+
for _, override := range o.([]any) {
206+
left := convertIntoMapping(override, nil)
207+
if left["subnet"] != right["subnet"] {
208+
// check if left is already in ipamConfigs, add it if not and continue with the next config
209+
if !slices.ContainsFunc(ipamConfigs, func(a any) bool {
210+
return a.(map[string]any)["subnet"] == left["subnet"]
211+
}) {
212+
ipamConfigs = append(ipamConfigs, left)
213+
continue
214+
}
215+
}
216+
merged, err := mergeMappings(right, left, path)
217+
if err != nil {
218+
return nil, err
219+
}
220+
// find index of potential previous config with the same subnet in ipamConfigs
221+
indexIfExist := slices.IndexFunc(ipamConfigs, func(a any) bool {
222+
return a.(map[string]any)["subnet"] == merged["subnet"]
223+
})
224+
// if a previous config is already in ipamConfigs, replace it
225+
if indexIfExist >= 0 {
226+
ipamConfigs[indexIfExist] = merged
227+
} else {
228+
// or add the new config to ipamConfigs
229+
ipamConfigs = append(ipamConfigs, merged)
230+
}
231+
}
232+
}
233+
return ipamConfigs, nil
234+
}
235+
200236
func convertIntoMapping(a any, defaultValue any) map[string]any {
201237
switch v := a.(type) {
202238
case map[string]any:

override/merge_networks_test.go

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
"testing"
2121
)
2222

23-
func Test_mergeYamlNetworkSequence(t *testing.T) {
23+
func Test_mergeYamlServiceNetworkSequence(t *testing.T) {
2424
assertMergeYaml(t, `
2525
services:
2626
test:
@@ -43,7 +43,7 @@ services:
4343
`)
4444
}
4545

46-
func Test_mergeYamlNetworksMapping(t *testing.T) {
46+
func Test_mergeYamlServiceNetworksMapping(t *testing.T) {
4747
assertMergeYaml(t, `
4848
services:
4949
test:
@@ -92,7 +92,7 @@ services:
9292
`)
9393
}
9494

95-
func Test_mergeYamlNetworkstMixed(t *testing.T) {
95+
func Test_mergeYamlServiceNetworksMixed(t *testing.T) {
9696
assertMergeYaml(t, `
9797
services:
9898
test:
@@ -137,3 +137,92 @@ services:
137137
- alias3
138138
`)
139139
}
140+
141+
func Test_mergeYamlNetworks(t *testing.T) {
142+
assertMergeYaml(t, `
143+
services:
144+
test:
145+
image: foo
146+
networks:
147+
network1:
148+
ipam:
149+
config:
150+
- subnet: 172.28.0.0/16
151+
ip_range: 172.28.5.0/24
152+
gateway: 172.28.5.254
153+
aux_addresses:
154+
host1: 172.28.1.5
155+
host2: 172.28.1.6
156+
host3: 172.28.1.7
157+
options:
158+
foo: bar
159+
baz: "0"
160+
labels:
161+
com.example.description: "Financial transaction network"
162+
com.example.department: "Finance"
163+
com.example.label-with-empty-value: ""
164+
`, `
165+
services:
166+
test:
167+
image: foo
168+
networks:
169+
network1:
170+
ipam:
171+
config:
172+
- subnet: 172.28.0.0/16
173+
ip_range: 172.28.5.1/24
174+
gateway: 172.28.5.254
175+
aux_addresses:
176+
host1: 172.28.1.5
177+
host2: 172.28.1.4
178+
host4: 172.28.1.10
179+
- subnet: 172.28.10.0/16
180+
ip_range: 172.28.10.1/24
181+
gateway: 172.28.10.254
182+
aux_addresses:
183+
host1: 172.28.10.5
184+
host2: 172.28.10.4
185+
host3: 172.28.10.10
186+
options:
187+
bar: foo
188+
baz: "0"
189+
labels:
190+
com.example.description: "Financial transaction network"
191+
com.example.department-new: "New"
192+
com.example.label-with-empty-value: ""
193+
network2:
194+
`, `
195+
services:
196+
test:
197+
image: foo
198+
networks:
199+
network1:
200+
ipam:
201+
config:
202+
- subnet: 172.28.0.0/16
203+
ip_range: 172.28.5.1/24
204+
gateway: 172.28.5.254
205+
aux_addresses:
206+
host1: 172.28.1.5
207+
host2: 172.28.1.4
208+
host3: 172.28.1.7
209+
host4: 172.28.1.10
210+
- subnet: 172.28.10.0/16
211+
ip_range: 172.28.10.1/24
212+
gateway: 172.28.10.254
213+
aux_addresses:
214+
host1: 172.28.10.5
215+
host2: 172.28.10.4
216+
host3: 172.28.10.10
217+
options:
218+
foo: bar
219+
bar: foo
220+
baz: "0"
221+
labels:
222+
com.example.description: "Financial transaction network"
223+
com.example.department: "Finance"
224+
com.example.label-with-empty-value: ""
225+
com.example.department-new: "New"
226+
network2:
227+
`)
228+
}

override/uncity.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ type indexer func(any, tree.Path) (string, error)
3131
var unique = map[tree.Path]indexer{}
3232

3333
func init() {
34+
unique["networks.*.labels"] = keyValueIndexer
35+
unique["networks.*.ipam.options"] = keyValueIndexer
3436
unique["services.*.annotations"] = keyValueIndexer
3537
unique["services.*.build.args"] = keyValueIndexer
3638
unique["services.*.build.additional_contexts"] = keyValueIndexer

0 commit comments

Comments
 (0)