Skip to content

Commit

Permalink
docker stack: allow '=' separator in extra_hosts
Browse files Browse the repository at this point in the history
extra_hosts in the compose file format allows '=' as a separator, and brackets
around IP addresses, the engine API doesn't.

So, transform the values when reading a compose file for 'docker stack'.

Signed-off-by: Rob Murray <rob.murray@docker.com>
  • Loading branch information
robmry committed Feb 7, 2024
1 parent 79fa65e commit ab9d208
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 12 deletions.
52 changes: 41 additions & 11 deletions cli/compose/loader/loader.go
Expand Up @@ -328,7 +328,7 @@ func createTransformHook(additionalTransformers ...Transformer) mapstructure.Dec
reflect.TypeOf(types.MappingWithEquals{}): transformMappingOrListFunc("=", true),
reflect.TypeOf(types.Labels{}): transformMappingOrListFunc("=", false),
reflect.TypeOf(types.MappingWithColon{}): transformMappingOrListFunc(":", false),
reflect.TypeOf(types.HostsList{}): transformListOrMappingFunc(":", false),
reflect.TypeOf(types.HostsList{}): transformHostsList,
reflect.TypeOf(types.ServiceVolumeConfig{}): transformServiceVolumeConfig,
reflect.TypeOf(types.BuildConfig{}): transformBuildConfig,
reflect.TypeOf(types.Duration(0)): transformStringToDuration,
Expand Down Expand Up @@ -808,28 +808,58 @@ var transformStringList TransformerFunc = func(data any) (any, error) {
}
}

func transformMappingOrListFunc(sep string, allowNil bool) TransformerFunc {
return func(data any) (any, error) {
return transformMappingOrList(data, sep, allowNil), nil
}
}
var transformHostsList TransformerFunc = func(data any) (any, error) {
// Transform pairs of host and IP addr that may be represented as a map, or a list
// of '=' or ':' separated strings, into a list of ':' separated strings.
l := transformListOrMapping(data, ":", false, []string{"=", ":"})

func transformListOrMappingFunc(sep string, allowNil bool) TransformerFunc {
return func(data any) (any, error) {
return transformListOrMapping(data, sep, allowNil), nil
// Remove brackets from IP addresses if present (for example "[::1]" -> "::1").
hl := l.([]string)
result := make([]string, 0, len(hl))
for _, hip := range hl {
host, ip, _ := strings.Cut(hip, ":")
if len(ip) > 2 && ip[0] == '[' && ip[len(ip)-1] == ']' {
ip = ip[1 : len(ip)-1]
}
result = append(result, fmt.Sprintf("%s:%s", host, ip))
}
return result, nil
}

func transformListOrMapping(listOrMapping any, sep string, allowNil bool) any {
func transformListOrMapping(listOrMapping any, sep string, allowNil bool, allowSeps []string) any {
switch value := listOrMapping.(type) {
case map[string]any:
return toStringList(value, sep, allowNil)
case []any:
return listOrMapping
result := make([]string, 0, len(value))
for _, entry := range value {
for i, allowSep := range allowSeps {
entry := fmt.Sprint(entry)
k, v, ok := strings.Cut(entry, allowSep)
if ok {
// Entry uses this allowed separator. Add it to the result, using
// sep as a separator.
result = append(result, fmt.Sprintf("%s%s%s", k, sep, v))
break
} else if i == len(allowSeps)-1 {
// No more separators to try, keep the entry if allowNil.
if allowNil {
result = append(result, k)
}
}
}
}
return result
}
panic(errors.Errorf("expected a map or a list, got %T: %#v", listOrMapping, listOrMapping))
}

func transformMappingOrListFunc(sep string, allowNil bool) TransformerFunc {
return func(data any) (any, error) {
return transformMappingOrList(data, sep, allowNil), nil
}
}

func transformMappingOrList(mappingOrList any, sep string, allowNil bool) any {
switch values := mappingOrList.(type) {
case map[string]any:
Expand Down
11 changes: 10 additions & 1 deletion cli/compose/loader/loader_test.go
Expand Up @@ -1302,12 +1302,14 @@ services:
extra_hosts:
"zulu": "162.242.195.82"
"alpha": "50.31.209.229"
"beta": "[fd20:f8a7:6e5b::2]"
"host.docker.internal": "host-gateway"
`)
assert.NilError(t, err)

expected := types.HostsList{
"alpha:50.31.209.229",
"beta:fd20:f8a7:6e5b::2",
"host.docker.internal:host-gateway",
"zulu:162.242.195.82",
}
Expand All @@ -1324,16 +1326,23 @@ services:
image: busybox
extra_hosts:
- "zulu:162.242.195.82"
- "whiskey=162.242.195.83"
- "alpha:50.31.209.229"
- "zulu:ff02::1"
- "host.docker.internal:host-gateway"
- "whiskey=ff02::2"
- "foxtrot=[ff02::3]"
- "host.docker.internal=host-gateway"
- "noaddress"
`)
assert.NilError(t, err)

expected := types.HostsList{
"zulu:162.242.195.82",
"whiskey:162.242.195.83",
"alpha:50.31.209.229",
"zulu:ff02::1",
"whiskey:ff02::2",
"foxtrot:ff02::3",
"host.docker.internal:host-gateway",
}

Expand Down

0 comments on commit ab9d208

Please sign in to comment.