Skip to content

Commit

Permalink
Merge pull request #1980 from dmexe/network-aliases
Browse files Browse the repository at this point in the history
Add network_aliases for docker driver
  • Loading branch information
dadgar committed Dec 19, 2016
2 parents 8b5e151 + 49416eb commit feb6f53
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 11 deletions.
23 changes: 20 additions & 3 deletions client/driver/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ type DockerDriverConfig struct {
Args []string `mapstructure:"args"` // The arguments to the Command/Entrypoint
IpcMode string `mapstructure:"ipc_mode"` // The IPC mode of the container - host and none
NetworkMode string `mapstructure:"network_mode"` // The network mode of the container - host, nat and none
NetworkAliases []string `mapstructure:"network_aliases"` // The network-scoped alias for the container
PidMode string `mapstructure:"pid_mode"` // The PID mode of the container - host and none
UTSMode string `mapstructure:"uts_mode"` // The UTS mode of the container - host and none
UsernsMode string `mapstructure:"userns_mode"` // The User namespace mode of the container - host and none
Expand Down Expand Up @@ -165,6 +166,7 @@ func NewDockerDriverConfig(task *structs.Task, env *env.TaskEnvironment) (*Docke
dconf.Command = env.ReplaceEnv(dconf.Command)
dconf.IpcMode = env.ReplaceEnv(dconf.IpcMode)
dconf.NetworkMode = env.ReplaceEnv(dconf.NetworkMode)
dconf.NetworkAliases = env.ParseAndReplace(dconf.NetworkAliases)
dconf.PidMode = env.ReplaceEnv(dconf.PidMode)
dconf.UTSMode = env.ReplaceEnv(dconf.UTSMode)
dconf.Hostname = env.ReplaceEnv(dconf.Hostname)
Expand Down Expand Up @@ -272,6 +274,9 @@ func (d *DockerDriver) Validate(config map[string]interface{}) error {
"network_mode": &fields.FieldSchema{
Type: fields.TypeString,
},
"network_aliases": &fields.FieldSchema{
Type: fields.TypeArray,
},
"pid_mode": &fields.FieldSchema{
Type: fields.TypeString,
},
Expand Down Expand Up @@ -838,10 +843,22 @@ func (d *DockerDriver) createContainerConfig(ctx *ExecContext, task *structs.Tas
containerName := fmt.Sprintf("%s-%s", task.Name, ctx.AllocID)
d.logger.Printf("[DEBUG] driver.docker: setting container name to: %s", containerName)

networkingConfig := &docker.NetworkingConfig{
EndpointsConfig: make(map[string]*docker.EndpointConfig),
}

if len(driverConfig.NetworkAliases) > 0 {
networkingConfig.EndpointsConfig[hostConfig.NetworkMode] = &docker.EndpointConfig{
Aliases: driverConfig.NetworkAliases,
}
d.logger.Printf("[DEBUG] driver.docker: applied network aliases on the container: [%s]%+v", hostConfig.NetworkMode, driverConfig.NetworkAliases)
}

return docker.CreateContainerOptions{
Name: containerName,
Config: config,
HostConfig: hostConfig,
Name: containerName,
Config: config,
HostConfig: hostConfig,
NetworkingConfig: networkingConfig,
}, nil
}

Expand Down
69 changes: 61 additions & 8 deletions client/driver/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,11 @@ func dockerTask() (*structs.Task, int, int) {
// If there is a problem during setup this function will abort or skip the test
// and indicate the reason.
func dockerSetup(t *testing.T, task *structs.Task) (*docker.Client, DriverHandle, func()) {
if !testutil.DockerIsConnected(t) {
t.SkipNow()
}

client, err := docker.NewClientFromEnv()
if err != nil {
t.Fatalf("Failed to initialize client: %s\nStack\n%s", err, debug.Stack())
}
client := newTestDockerClient(t)
return dockerSetupWithClient(t, task, client)
}

func dockerSetupWithClient(t *testing.T, task *structs.Task, client *docker.Client) (*docker.Client, DriverHandle, func()) {
driverCtx, execCtx := testDriverContexts(task)
driverCtx.config.Options = map[string]string{"docker.cleanup.image": "false"}
driver := NewDockerDriver(driverCtx)
Expand All @@ -119,6 +115,18 @@ func dockerSetup(t *testing.T, task *structs.Task) (*docker.Client, DriverHandle
return client, handle, cleanup
}

func newTestDockerClient(t *testing.T) *docker.Client {
if !testutil.DockerIsConnected(t) {
t.SkipNow()
}

client, err := docker.NewClientFromEnv()
if err != nil {
t.Fatalf("Failed to initialize client: %s\nStack\n%s", err, debug.Stack())
}
return client
}

// This test should always pass, even if docker daemon is not available
func TestDockerDriver_Fingerprint(t *testing.T) {
driverCtx, execCtx := testDriverContexts(&structs.Task{Name: "foo", Resources: basicResources})
Expand Down Expand Up @@ -589,6 +597,51 @@ func TestDockerDriver_NetworkMode_Host(t *testing.T) {
}
}

func TestDockerDriver_NetworkAliases_Bridge(t *testing.T) {
// Because go-dockerclient doesn't provide api for query network aliases, just check that
// a container can be created with a 'network_aliases' property

// Create network, network-scoped alias is supported only for containers in user defined networks
client := newTestDockerClient(t)
networkOpts := docker.CreateNetworkOptions{Name: "foobar", Driver: "bridge"}
network, err := client.CreateNetwork(networkOpts)
if err != nil {
t.Fatalf("err: %v", err)
}
defer client.RemoveNetwork(network.ID)

expected := []string{"foobar"}
task := &structs.Task{
Name: "nc-demo",
Config: map[string]interface{}{
"image": "busybox",
"load": []string{"busybox.tar"},
"command": "/bin/nc",
"args": []string{"-l", "127.0.0.1", "-p", "0"},
"network_mode": network.Name,
"network_aliases": expected,
},
Resources: &structs.Resources{
MemoryMB: 256,
CPU: 512,
},
LogConfig: &structs.LogConfig{
MaxFiles: 10,
MaxFileSizeMB: 10,
},
}

client, handle, cleanup := dockerSetupWithClient(t, task, client)
defer cleanup()

waitForExist(t, client, handle.(*DockerHandle))

_, err = client.InspectContainer(handle.(*DockerHandle).ContainerID())
if err != nil {
t.Fatalf("err: %v", err)
}
}

func TestDockerDriver_Labels(t *testing.T) {
task, _, _ := dockerTask()
task.Config["labels"] = []map[string]string{
Expand Down
15 changes: 15 additions & 0 deletions website/source/docs/drivers/docker.html.md
Original file line number Diff line number Diff line change