Skip to content

Commit

Permalink
normalization creates implicit default network only when used by so…
Browse files Browse the repository at this point in the history
…me service

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
  • Loading branch information
ndeloof authored and glours committed Apr 23, 2024
1 parent 8472f87 commit ced6565
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 13 deletions.
47 changes: 37 additions & 10 deletions loader/normalize.go
Expand Up @@ -26,18 +26,12 @@ import (

// Normalize compose project by moving deprecated attributes to their canonical position and injecting implicit defaults
func Normalize(dict map[string]any, env types.Mapping) (map[string]any, error) {
dict["networks"] = normalizeNetworks(dict)
normalizeNetworks(dict)

if d, ok := dict["services"]; ok {
services := d.(map[string]any)
for name, s := range services {
service := s.(map[string]any)
_, hasNetworks := service["networks"]
_, hasNetworkMode := service["network_mode"]
if !hasNetworks && !hasNetworkMode {
// Service without explicit network attachment are implicitly exposed on default network
service["networks"] = map[string]any{"default": nil}
}

if service["pull_policy"] == types.PullPolicyIfNotPresent {
service["pull_policy"] = types.PullPolicyMissing
Expand Down Expand Up @@ -137,18 +131,51 @@ func Normalize(dict map[string]any, env types.Mapping) (map[string]any, error) {
return dict, nil
}

func normalizeNetworks(dict map[string]any) map[string]any {
func normalizeNetworks(dict map[string]any) {
var networks map[string]any
if n, ok := dict["networks"]; ok {
networks = n.(map[string]any)
} else {
networks = map[string]any{}
}
if _, ok := networks["default"]; !ok {

// implicit `default` network must be introduced only if actually used by some service
usesDefaultNetwork := false

if s, ok := dict["services"]; ok {
services := s.(map[string]any)
for name, se := range services {
service := se.(map[string]any)
if _, ok := service["network_mode"]; ok {
continue
}
if n, ok := service["networks"]; !ok {
// If none explicitly declared, service is connected to default network
service["networks"] = map[string]any{"default": nil}
usesDefaultNetwork = true
} else {
net := n.(map[string]any)
if len(net) == 0 {
// networks section declared but empty (corner case)
service["networks"] = map[string]any{"default": nil}
usesDefaultNetwork = true
} else if _, ok := net["default"]; ok {
usesDefaultNetwork = true
}
}
services[name] = service
}
dict["services"] = services
}

if _, ok := networks["default"]; !ok && usesDefaultNetwork {
// If not declared explicitly, Compose model involves an implicit "default" network
networks["default"] = nil
}
return networks

if len(networks) > 0 {
dict["networks"] = networks
}
}

func resolve(a any, fn func(s string) (string, bool)) (any, bool) {
Expand Down
67 changes: 64 additions & 3 deletions loader/normalize_test.go
Expand Up @@ -88,9 +88,6 @@ volumes:

expected := `
name: myProject
networks:
default:
name: myProject_default
volumes:
myExternalVol:
name: myExternalVol
Expand Down Expand Up @@ -275,3 +272,67 @@ networks:
assert.NilError(t, err)
assert.DeepEqual(t, expect, model)
}

func TestNormalizeDefaultNetwork(t *testing.T) {
project := `
name: myProject
services:
test:
image: test
`

expected := `
name: myProject
networks:
default:
name: myProject_default
services:
test:
image: test
networks:
default: null
`
var model map[string]any
err := yaml.Unmarshal([]byte(project), &model)
assert.NilError(t, err)
model, err = Normalize(model, nil)
assert.NilError(t, err)

var expect map[string]any
err = yaml.Unmarshal([]byte(expected), &expect)
assert.NilError(t, err)
assert.DeepEqual(t, expect, model)
}

func TestNormalizeCustomNetwork(t *testing.T) {
project := `
name: myProject
services:
test:
networks:
my_network: null
networks:
my_network: null
`

expected := `
name: myProject
networks:
my_network:
name: myProject_my_network
services:
test:
networks:
my_network: null
`
var model map[string]any
err := yaml.Unmarshal([]byte(project), &model)
assert.NilError(t, err)
model, err = Normalize(model, nil)
assert.NilError(t, err)

var expect map[string]any
err = yaml.Unmarshal([]byte(expected), &expect)
assert.NilError(t, err)
assert.DeepEqual(t, expect, model)
}

0 comments on commit ced6565

Please sign in to comment.