mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-01-09 09:05:26 +00:00
Fix IPv6 host aliases for kubernetes (#2992)
Closes #2991 [Tests](https://github.com/woodpecker-ci/woodpecker/pull/2993#issuecomment-1868048169) --------- Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
parent
cd9d425a0d
commit
253d702bc7
10 changed files with 131 additions and 69 deletions
|
@ -88,8 +88,12 @@ func toHostConfig(step *types.Step) *container.HostConfig {
|
||||||
if len(step.DNSSearch) != 0 {
|
if len(step.DNSSearch) != 0 {
|
||||||
config.DNSSearch = step.DNSSearch
|
config.DNSSearch = step.DNSSearch
|
||||||
}
|
}
|
||||||
|
extraHosts := []string{}
|
||||||
|
for _, hostAlias := range step.ExtraHosts {
|
||||||
|
extraHosts = append(extraHosts, hostAlias.Name+":"+hostAlias.IP)
|
||||||
|
}
|
||||||
if len(step.ExtraHosts) != 0 {
|
if len(step.ExtraHosts) != 0 {
|
||||||
config.ExtraHosts = step.ExtraHosts
|
config.ExtraHosts = extraHosts
|
||||||
}
|
}
|
||||||
if len(step.Devices) != 0 {
|
if len(step.Devices) != 0 {
|
||||||
config.Devices = toDev(step.Devices)
|
config.Devices = toDev(step.Devices)
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
@ -166,8 +165,7 @@ func (e *kube) SetupWorkflow(ctx context.Context, conf *types.Config, taskUUID s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extraHosts := []string{}
|
extraHosts := []types.HostAlias{}
|
||||||
|
|
||||||
for _, stage := range conf.Stages {
|
for _, stage := range conf.Stages {
|
||||||
if stage.Alias == "services" {
|
if stage.Alias == "services" {
|
||||||
for _, step := range stage.Steps {
|
for _, step := range stage.Steps {
|
||||||
|
@ -175,12 +173,12 @@ func (e *kube) SetupWorkflow(ctx context.Context, conf *types.Config, taskUUID s
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
extraHosts = append(extraHosts, step.Networks[0].Aliases[0]+":"+svc.Spec.ClusterIP)
|
hostAlias := types.HostAlias{Name: step.Networks[0].Aliases[0], IP: svc.Spec.ClusterIP}
|
||||||
|
extraHosts = append(extraHosts, hostAlias)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Trace().Msgf("Adding extra hosts: %v", extraHosts)
|
||||||
log.Trace().Msgf("Adding extra hosts: %s", strings.Join(extraHosts, ", "))
|
|
||||||
for _, stage := range conf.Stages {
|
for _, stage := range conf.Stages {
|
||||||
for _, step := range stage.Steps {
|
for _, step := range stage.Steps {
|
||||||
step.ExtraHosts = extraHosts
|
step.ExtraHosts = extraHosts
|
||||||
|
|
|
@ -36,17 +36,16 @@ const (
|
||||||
|
|
||||||
func mkPod(namespace, name, image, workDir, goos, serviceAccountName string,
|
func mkPod(namespace, name, image, workDir, goos, serviceAccountName string,
|
||||||
pool, privileged bool,
|
pool, privileged bool,
|
||||||
commands, vols, extraHosts []string,
|
commands, vols []string,
|
||||||
labels, annotations, env, nodeSelector map[string]string,
|
labels, annotations, env, nodeSelector map[string]string,
|
||||||
tolerations []types.Toleration, resources types.Resources,
|
extraHosts []types.HostAlias, tolerations []types.Toleration, resources types.Resources,
|
||||||
securityContext *types.SecurityContext, securityContextConfig SecurityContextConfig,
|
securityContext *types.SecurityContext, securityContextConfig SecurityContextConfig,
|
||||||
) (*v1.Pod, error) {
|
) (*v1.Pod, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
meta := podMeta(name, namespace, labels, annotations)
|
meta := podMeta(name, namespace, labels, annotations)
|
||||||
|
|
||||||
spec, err := podSpec(serviceAccountName, vols, extraHosts, env,
|
spec, err := podSpec(serviceAccountName, vols, env, nodeSelector, extraHosts, tolerations, securityContext, securityContextConfig)
|
||||||
nodeSelector, tolerations, securityContext, securityContextConfig)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -86,7 +85,8 @@ func podMeta(name, namespace string, labels, annotations map[string]string) meta
|
||||||
return meta
|
return meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func podSpec(serviceAccountName string, vols, extraHosts []string, env, backendNodeSelector map[string]string, backendTolerations []types.Toleration,
|
func podSpec(serviceAccountName string, vols []string, env, backendNodeSelector map[string]string,
|
||||||
|
extraHosts []types.HostAlias, backendTolerations []types.Toleration,
|
||||||
securityContext *types.SecurityContext, securityContextConfig SecurityContextConfig,
|
securityContext *types.SecurityContext, securityContextConfig SecurityContextConfig,
|
||||||
) (v1.PodSpec, error) {
|
) (v1.PodSpec, error) {
|
||||||
var err error
|
var err error
|
||||||
|
@ -195,7 +195,7 @@ func volumeMount(name, path string) v1.VolumeMount {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here is the service IPs (placed in /etc/hosts in the Pod)
|
// Here is the service IPs (placed in /etc/hosts in the Pod)
|
||||||
func hostAliases(extraHosts []string) []v1.HostAlias {
|
func hostAliases(extraHosts []types.HostAlias) []v1.HostAlias {
|
||||||
hostAliases := []v1.HostAlias{}
|
hostAliases := []v1.HostAlias{}
|
||||||
for _, extraHost := range extraHosts {
|
for _, extraHost := range extraHosts {
|
||||||
hostAlias := hostAlias(extraHost)
|
hostAlias := hostAlias(extraHost)
|
||||||
|
@ -204,11 +204,10 @@ func hostAliases(extraHosts []string) []v1.HostAlias {
|
||||||
return hostAliases
|
return hostAliases
|
||||||
}
|
}
|
||||||
|
|
||||||
func hostAlias(extraHost string) v1.HostAlias {
|
func hostAlias(extraHost types.HostAlias) v1.HostAlias {
|
||||||
host := strings.Split(extraHost, ":")
|
|
||||||
return v1.HostAlias{
|
return v1.HostAlias{
|
||||||
IP: host[1],
|
IP: extraHost.IP,
|
||||||
Hostnames: []string{host[0]},
|
Hostnames: []string{extraHost.Name},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,9 +357,9 @@ func startPod(ctx context.Context, engine *kube, step *types.Step) (*v1.Pod, err
|
||||||
|
|
||||||
pod, err := mkPod(engine.config.Namespace, podName, step.Image, step.WorkingDir, engine.goos, step.BackendOptions.Kubernetes.ServiceAccountName,
|
pod, err := mkPod(engine.config.Namespace, podName, step.Image, step.WorkingDir, engine.goos, step.BackendOptions.Kubernetes.ServiceAccountName,
|
||||||
step.Pull, step.Privileged,
|
step.Pull, step.Privileged,
|
||||||
step.Commands, step.Volumes, step.ExtraHosts,
|
step.Commands, step.Volumes,
|
||||||
engine.config.PodLabels, engine.config.PodAnnotations, step.Environment, step.BackendOptions.Kubernetes.NodeSelector,
|
engine.config.PodLabels, engine.config.PodAnnotations, step.Environment, step.BackendOptions.Kubernetes.NodeSelector,
|
||||||
step.BackendOptions.Kubernetes.Tolerations, step.BackendOptions.Kubernetes.Resources, step.BackendOptions.Kubernetes.SecurityContext, engine.config.SecurityContext)
|
step.ExtraHosts, step.BackendOptions.Kubernetes.Tolerations, step.BackendOptions.Kubernetes.Resources, step.BackendOptions.Kubernetes.SecurityContext, engine.config.SecurityContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,9 +108,9 @@ func TestTinyPod(t *testing.T) {
|
||||||
|
|
||||||
pod, err := mkPod("woodpecker", "wp-01he8bebctabr3kgk0qj36d2me-0", "gradle:8.4.0-jdk21", "/woodpecker/src", "linux/amd64", "",
|
pod, err := mkPod("woodpecker", "wp-01he8bebctabr3kgk0qj36d2me-0", "gradle:8.4.0-jdk21", "/woodpecker/src", "linux/amd64", "",
|
||||||
false, false,
|
false, false,
|
||||||
[]string{"gradle build"}, []string{"workspace:/woodpecker/src"}, nil,
|
[]string{"gradle build"}, []string{"workspace:/woodpecker/src"},
|
||||||
nil, nil, map[string]string{"CI": "woodpecker"}, nil,
|
nil, nil, map[string]string{"CI": "woodpecker"}, nil,
|
||||||
nil,
|
nil, nil,
|
||||||
types.Resources{Requests: nil, Limits: nil}, nil, SecurityContextConfig{},
|
types.Resources{Requests: nil, Limits: nil}, nil, SecurityContextConfig{},
|
||||||
)
|
)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -228,17 +228,27 @@ func TestFullPod(t *testing.T) {
|
||||||
"hostnames": [
|
"hostnames": [
|
||||||
"cloudflare"
|
"cloudflare"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ip": "2606:4700:4700::64",
|
||||||
|
"hostnames": [
|
||||||
|
"cf.v6"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"status": {}
|
"status": {}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
hostAliases := []types.HostAlias{
|
||||||
|
{Name: "cloudflare", IP: "1.1.1.1"},
|
||||||
|
{Name: "cf.v6", IP: "2606:4700:4700::64"},
|
||||||
|
}
|
||||||
pod, err := mkPod("woodpecker", "wp-01he8bebctabr3kgk0qj36d2me-0", "meltwater/drone-cache", "/woodpecker/src", "linux/amd64", "wp-svc-acc",
|
pod, err := mkPod("woodpecker", "wp-01he8bebctabr3kgk0qj36d2me-0", "meltwater/drone-cache", "/woodpecker/src", "linux/amd64", "wp-svc-acc",
|
||||||
true, true,
|
true, true,
|
||||||
[]string{"go get", "go test"}, []string{"woodpecker-cache:/woodpecker/src/cache"}, []string{"cloudflare:1.1.1.1"},
|
[]string{"go get", "go test"}, []string{"woodpecker-cache:/woodpecker/src/cache"},
|
||||||
map[string]string{"app": "test"}, map[string]string{"apparmor.security": "runtime/default"}, map[string]string{"CGO": "0"}, map[string]string{"storage": "ssd"},
|
map[string]string{"app": "test"}, map[string]string{"apparmor.security": "runtime/default"}, map[string]string{"CGO": "0"}, map[string]string{"storage": "ssd"},
|
||||||
[]types.Toleration{{Key: "net-port", Value: "100Mbit", Effect: types.TaintEffectNoSchedule}},
|
hostAliases, []types.Toleration{{Key: "net-port", Value: "100Mbit", Effect: types.TaintEffectNoSchedule}},
|
||||||
types.Resources{Requests: map[string]string{"memory": "128Mi", "cpu": "1000m"}, Limits: map[string]string{"memory": "256Mi", "cpu": "2"}},
|
types.Resources{Requests: map[string]string{"memory": "128Mi", "cpu": "1000m"}, Limits: map[string]string{"memory": "256Mi", "cpu": "2"}},
|
||||||
&types.SecurityContext{Privileged: newBool(true), RunAsNonRoot: newBool(true), RunAsUser: newInt64(101), RunAsGroup: newInt64(101), FSGroup: newInt64(101)},
|
&types.SecurityContext{Privileged: newBool(true), RunAsNonRoot: newBool(true), RunAsUser: newInt64(101), RunAsGroup: newInt64(101), FSGroup: newInt64(101)},
|
||||||
SecurityContextConfig{RunAsNonRoot: false},
|
SecurityContextConfig{RunAsNonRoot: false},
|
||||||
|
|
|
@ -18,3 +18,8 @@ package types
|
||||||
type Network struct {
|
type Network struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HostAlias struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
IP string `json:"ip,omitempty"`
|
||||||
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ type Step struct {
|
||||||
Environment map[string]string `json:"environment,omitempty"`
|
Environment map[string]string `json:"environment,omitempty"`
|
||||||
Entrypoint []string `json:"entrypoint,omitempty"`
|
Entrypoint []string `json:"entrypoint,omitempty"`
|
||||||
Commands []string `json:"commands,omitempty"`
|
Commands []string `json:"commands,omitempty"`
|
||||||
ExtraHosts []string `json:"extra_hosts,omitempty"`
|
ExtraHosts []HostAlias `json:"extra_hosts,omitempty"`
|
||||||
Volumes []string `json:"volumes,omitempty"`
|
Volumes []string `json:"volumes,omitempty"`
|
||||||
Tmpfs []string `json:"tmpfs,omitempty"`
|
Tmpfs []string `json:"tmpfs,omitempty"`
|
||||||
Devices []string `json:"devices,omitempty"`
|
Devices []string `json:"devices,omitempty"`
|
||||||
|
|
|
@ -82,14 +82,15 @@ func TestCompilerCompile(t *testing.T) {
|
||||||
Name: "test_clone",
|
Name: "test_clone",
|
||||||
Alias: "clone",
|
Alias: "clone",
|
||||||
Steps: []*backend_types.Step{{
|
Steps: []*backend_types.Step{{
|
||||||
Name: "test_clone",
|
Name: "test_clone",
|
||||||
Alias: "clone",
|
Alias: "clone",
|
||||||
Type: backend_types.StepTypeClone,
|
Type: backend_types.StepTypeClone,
|
||||||
Image: constant.DefaultCloneImage,
|
Image: constant.DefaultCloneImage,
|
||||||
OnSuccess: true,
|
OnSuccess: true,
|
||||||
Failure: "fail",
|
Failure: "fail",
|
||||||
Volumes: []string{defaultVolumes[0].Name + ":"},
|
Volumes: []string{defaultVolumes[0].Name + ":"},
|
||||||
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"clone"}}},
|
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"clone"}}},
|
||||||
|
ExtraHosts: []backend_types.HostAlias{},
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,14 +127,15 @@ func TestCompilerCompile(t *testing.T) {
|
||||||
Name: "test_stage_0",
|
Name: "test_stage_0",
|
||||||
Alias: "dummy",
|
Alias: "dummy",
|
||||||
Steps: []*backend_types.Step{{
|
Steps: []*backend_types.Step{{
|
||||||
Name: "test_step_0",
|
Name: "test_step_0",
|
||||||
Alias: "dummy",
|
Alias: "dummy",
|
||||||
Type: backend_types.StepTypePlugin,
|
Type: backend_types.StepTypePlugin,
|
||||||
Image: "dummy_img",
|
Image: "dummy_img",
|
||||||
OnSuccess: true,
|
OnSuccess: true,
|
||||||
Failure: "fail",
|
Failure: "fail",
|
||||||
Volumes: []string{defaultVolumes[0].Name + ":"},
|
Volumes: []string{defaultVolumes[0].Name + ":"},
|
||||||
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"dummy"}}},
|
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"dummy"}}},
|
||||||
|
ExtraHosts: []backend_types.HostAlias{},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
|
@ -161,39 +163,42 @@ func TestCompilerCompile(t *testing.T) {
|
||||||
Name: "test_stage_0",
|
Name: "test_stage_0",
|
||||||
Alias: "echo env",
|
Alias: "echo env",
|
||||||
Steps: []*backend_types.Step{{
|
Steps: []*backend_types.Step{{
|
||||||
Name: "test_step_0",
|
Name: "test_step_0",
|
||||||
Alias: "echo env",
|
Alias: "echo env",
|
||||||
Type: backend_types.StepTypeCommands,
|
Type: backend_types.StepTypeCommands,
|
||||||
Image: "bash",
|
Image: "bash",
|
||||||
Commands: []string{"env"},
|
Commands: []string{"env"},
|
||||||
OnSuccess: true,
|
OnSuccess: true,
|
||||||
Failure: "fail",
|
Failure: "fail",
|
||||||
Volumes: []string{defaultVolumes[0].Name + ":"},
|
Volumes: []string{defaultVolumes[0].Name + ":"},
|
||||||
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"echo env"}}},
|
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"echo env"}}},
|
||||||
|
ExtraHosts: []backend_types.HostAlias{},
|
||||||
}},
|
}},
|
||||||
}, {
|
}, {
|
||||||
Name: "test_stage_1",
|
Name: "test_stage_1",
|
||||||
Alias: "parallel echo 1",
|
Alias: "parallel echo 1",
|
||||||
Steps: []*backend_types.Step{{
|
Steps: []*backend_types.Step{{
|
||||||
Name: "test_step_1",
|
Name: "test_step_1",
|
||||||
Alias: "parallel echo 1",
|
Alias: "parallel echo 1",
|
||||||
Type: backend_types.StepTypeCommands,
|
Type: backend_types.StepTypeCommands,
|
||||||
Image: "bash",
|
Image: "bash",
|
||||||
Commands: []string{"echo 1"},
|
Commands: []string{"echo 1"},
|
||||||
OnSuccess: true,
|
OnSuccess: true,
|
||||||
Failure: "fail",
|
Failure: "fail",
|
||||||
Volumes: []string{defaultVolumes[0].Name + ":"},
|
Volumes: []string{defaultVolumes[0].Name + ":"},
|
||||||
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 1"}}},
|
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 1"}}},
|
||||||
|
ExtraHosts: []backend_types.HostAlias{},
|
||||||
}, {
|
}, {
|
||||||
Name: "test_step_2",
|
Name: "test_step_2",
|
||||||
Alias: "parallel echo 2",
|
Alias: "parallel echo 2",
|
||||||
Type: backend_types.StepTypeCommands,
|
Type: backend_types.StepTypeCommands,
|
||||||
Image: "bash",
|
Image: "bash",
|
||||||
Commands: []string{"echo 2"},
|
Commands: []string{"echo 2"},
|
||||||
OnSuccess: true,
|
OnSuccess: true,
|
||||||
Failure: "fail",
|
Failure: "fail",
|
||||||
Volumes: []string{defaultVolumes[0].Name + ":"},
|
Volumes: []string{defaultVolumes[0].Name + ":"},
|
||||||
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 2"}}},
|
Networks: []backend_types.Conn{{Name: "test_default", Aliases: []string{"parallel echo 2"}}},
|
||||||
|
ExtraHosts: []backend_types.HostAlias{},
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,6 +55,16 @@ func (c *Compiler) createProcess(name string, container *yaml_types.Container, s
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extraHosts := make([]backend_types.HostAlias, len(container.ExtraHosts))
|
||||||
|
for i, extraHost := range container.ExtraHosts {
|
||||||
|
name, ip, ok := strings.Cut(extraHost, ":")
|
||||||
|
if !ok {
|
||||||
|
return nil, &ErrExtraHostFormat{host: extraHost}
|
||||||
|
}
|
||||||
|
extraHosts[i].Name = name
|
||||||
|
extraHosts[i].IP = ip
|
||||||
|
}
|
||||||
|
|
||||||
var volumes []string
|
var volumes []string
|
||||||
if !c.local {
|
if !c.local {
|
||||||
volumes = append(volumes, workspace)
|
volumes = append(volumes, workspace)
|
||||||
|
@ -173,7 +183,7 @@ func (c *Compiler) createProcess(name string, container *yaml_types.Container, s
|
||||||
WorkingDir: workingdir,
|
WorkingDir: workingdir,
|
||||||
Environment: environment,
|
Environment: environment,
|
||||||
Commands: container.Commands,
|
Commands: container.Commands,
|
||||||
ExtraHosts: container.ExtraHosts,
|
ExtraHosts: extraHosts,
|
||||||
Volumes: volumes,
|
Volumes: volumes,
|
||||||
Tmpfs: container.Tmpfs,
|
Tmpfs: container.Tmpfs,
|
||||||
Devices: container.Devices,
|
Devices: container.Devices,
|
||||||
|
|
30
pipeline/frontend/yaml/compiler/errors.go
Normal file
30
pipeline/frontend/yaml/compiler/errors.go
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2023 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package compiler
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type ErrExtraHostFormat struct {
|
||||||
|
host string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *ErrExtraHostFormat) Error() string {
|
||||||
|
return fmt.Sprintf("extra host %s is in wrong format", err.host)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ErrExtraHostFormat) Is(target error) bool {
|
||||||
|
_, ok := target.(*ErrExtraHostFormat) //nolint:errorlint
|
||||||
|
return ok
|
||||||
|
}
|
|
@ -45,6 +45,7 @@ environment:
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- somehost:162.242.195.82
|
- somehost:162.242.195.82
|
||||||
- otherhost:50.31.209.229
|
- otherhost:50.31.209.229
|
||||||
|
- ipv6:2001:db8::10
|
||||||
name: my-build-container
|
name: my-build-container
|
||||||
network_mode: bridge
|
network_mode: bridge
|
||||||
networks:
|
networks:
|
||||||
|
@ -84,7 +85,7 @@ func TestUnmarshalContainer(t *testing.T) {
|
||||||
DNS: base.StringOrSlice{"8.8.8.8"},
|
DNS: base.StringOrSlice{"8.8.8.8"},
|
||||||
DNSSearch: base.StringOrSlice{"example.com"},
|
DNSSearch: base.StringOrSlice{"example.com"},
|
||||||
Environment: base.SliceOrMap{"RACK_ENV": "development", "SHOW": "true"},
|
Environment: base.SliceOrMap{"RACK_ENV": "development", "SHOW": "true"},
|
||||||
ExtraHosts: []string{"somehost:162.242.195.82", "otherhost:50.31.209.229"},
|
ExtraHosts: []string{"somehost:162.242.195.82", "otherhost:50.31.209.229", "ipv6:2001:db8::10"},
|
||||||
Image: "golang:latest",
|
Image: "golang:latest",
|
||||||
MemLimit: base.MemStringOrInt(1024),
|
MemLimit: base.MemStringOrInt(1024),
|
||||||
MemSwapLimit: base.MemStringOrInt(1024),
|
MemSwapLimit: base.MemStringOrInt(1024),
|
||||||
|
|
Loading…
Reference in a new issue