Merge pull request #132 from mavenugo/stack-host

Host and Bridge network support in docker stack deploy
This commit is contained in:
Vincent Demeester 2017-05-31 15:07:56 -07:00 committed by GitHub
commit efaadcf465
5 changed files with 136 additions and 21 deletions

View File

@ -13,6 +13,7 @@ import (
"github.com/docker/cli/cli/compose/loader" "github.com/docker/cli/cli/compose/loader"
composetypes "github.com/docker/cli/cli/compose/types" composetypes "github.com/docker/cli/cli/compose/types"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm"
apiclient "github.com/docker/docker/client" apiclient "github.com/docker/docker/client"
dockerclient "github.com/docker/docker/client" dockerclient "github.com/docker/docker/client"
@ -64,7 +65,7 @@ func deployCompose(ctx context.Context, dockerCli command.Cli, opts deployOption
serviceNetworks := getServicesDeclaredNetworks(config.Services) serviceNetworks := getServicesDeclaredNetworks(config.Services)
networks, externalNetworks := convert.Networks(namespace, config.Networks, serviceNetworks) networks, externalNetworks := convert.Networks(namespace, config.Networks, serviceNetworks)
if err := validateExternalNetworks(ctx, dockerCli, externalNetworks); err != nil { if err := validateExternalNetworks(ctx, dockerCli.Client(), externalNetworks); err != nil {
return err return err
} }
if err := createNetworks(ctx, dockerCli, namespace, networks); err != nil { if err := createNetworks(ctx, dockerCli, namespace, networks); err != nil {
@ -75,7 +76,7 @@ func deployCompose(ctx context.Context, dockerCli command.Cli, opts deployOption
if err != nil { if err != nil {
return err return err
} }
if err := createSecrets(ctx, dockerCli, namespace, secrets); err != nil { if err := createSecrets(ctx, dockerCli, secrets); err != nil {
return err return err
} }
@ -83,7 +84,7 @@ func deployCompose(ctx context.Context, dockerCli command.Cli, opts deployOption
if err != nil { if err != nil {
return err return err
} }
if err := createConfigs(ctx, dockerCli, namespace, configs); err != nil { if err := createConfigs(ctx, dockerCli, configs); err != nil {
return err return err
} }
@ -169,30 +170,26 @@ func getConfigFile(filename string) (*composetypes.ConfigFile, error) {
func validateExternalNetworks( func validateExternalNetworks(
ctx context.Context, ctx context.Context,
dockerCli command.Cli, client dockerclient.NetworkAPIClient,
externalNetworks []string) error { externalNetworks []string,
client := dockerCli.Client() ) error {
for _, networkName := range externalNetworks { for _, networkName := range externalNetworks {
network, err := client.NetworkInspect(ctx, networkName, false) network, err := client.NetworkInspect(ctx, networkName, false)
if err != nil { switch {
if dockerclient.IsErrNetworkNotFound(err) { case dockerclient.IsErrNotFound(err):
return errors.Errorf("network %q is declared as external, but could not be found. You need to create the network before the stack is deployed (with overlay driver)", networkName) return errors.Errorf("network %q is declared as external, but could not be found. You need to create a swarm-scoped network before the stack is deployed", networkName)
} case err != nil:
return err return err
} case container.NetworkMode(networkName).IsUserDefined() && network.Scope != "swarm":
if network.Scope != "swarm" { return errors.Errorf("network %q is declared as external, but it is not in the right scope: %q instead of \"swarm\"", networkName, network.Scope)
return errors.Errorf("network %q is declared as external, but it is not in the right scope: %q instead of %q", networkName, network.Scope, "swarm")
} }
} }
return nil return nil
} }
func createSecrets( func createSecrets(
ctx context.Context, ctx context.Context,
dockerCli command.Cli, dockerCli command.Cli,
namespace convert.Namespace,
secrets []swarm.SecretSpec, secrets []swarm.SecretSpec,
) error { ) error {
client := dockerCli.Client() client := dockerCli.Client()
@ -219,7 +216,6 @@ func createSecrets(
func createConfigs( func createConfigs(
ctx context.Context, ctx context.Context,
dockerCli command.Cli, dockerCli command.Cli,
namespace convert.Namespace,
configs []swarm.ConfigSpec, configs []swarm.ConfigSpec,
) error { ) error {
client := dockerCli.Client() client := dockerCli.Client()

View File

@ -5,9 +5,14 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/docker/cli/cli/internal/test/network"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/testutil"
"github.com/docker/docker/pkg/testutil/tempfile" "github.com/docker/docker/pkg/testutil/tempfile"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/net/context"
) )
func TestGetConfigDetails(t *testing.T) { func TestGetConfigDetails(t *testing.T) {
@ -26,3 +31,55 @@ services:
assert.Len(t, details.ConfigFiles, 1) assert.Len(t, details.ConfigFiles, 1)
assert.Len(t, details.Environment, len(os.Environ())) assert.Len(t, details.Environment, len(os.Environ()))
} }
type notFound struct {
error
}
func (n notFound) NotFound() bool {
return true
}
func TestValidateExternalNetworks(t *testing.T) {
var testcases = []struct {
inspectResponse types.NetworkResource
inspectError error
expectedMsg string
network string
}{
{
inspectError: notFound{},
expectedMsg: "could not be found. You need to create a swarm-scoped network",
},
{
inspectError: errors.New("Unexpected"),
expectedMsg: "Unexpected",
},
{
network: "host",
},
{
network: "user",
expectedMsg: "is not in the right scope",
},
{
network: "user",
inspectResponse: types.NetworkResource{Scope: "swarm"},
},
}
for _, testcase := range testcases {
fakeClient := &network.FakeClient{
NetworkInspectFunc: func(_ context.Context, _ string, _ bool) (types.NetworkResource, error) {
return testcase.inspectResponse, testcase.inspectError
},
}
networks := []string{testcase.network}
err := validateExternalNetworks(context.Background(), fakeClient, networks)
if testcase.expectedMsg == "" {
assert.NoError(t, err)
} else {
testutil.ErrorContains(t, err, testcase.expectedMsg)
}
}
}

View File

@ -223,10 +223,16 @@ func convertServiceNetworks(
if networkConfig.External.External { if networkConfig.External.External {
target = networkConfig.External.Name target = networkConfig.External.Name
} }
nets = append(nets, swarm.NetworkAttachmentConfig{ netAttachConfig := swarm.NetworkAttachmentConfig{
Target: target, Target: target,
Aliases: append(aliases, name), Aliases: aliases,
}) }
// Only add default aliases to user defined networks. Other networks do
// not support aliases.
if container.NetworkMode(target).IsUserDefined() {
netAttachConfig.Aliases = append(netAttachConfig.Aliases, name)
}
nets = append(nets, netAttachConfig)
} }
sort.Sort(byNetworkTarget(nets)) sort.Sort(byNetworkTarget(nets))

View File

@ -0,0 +1,56 @@
package network
import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
"golang.org/x/net/context"
)
// FakeClient is a fake NetworkAPIClient
type FakeClient struct {
NetworkInspectFunc func(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, error)
}
// NetworkConnect fakes connecting to a network
func (c *FakeClient) NetworkConnect(ctx context.Context, networkID, container string, config *network.EndpointSettings) error {
return nil
}
// NetworkCreate fakes creating a network
func (c *FakeClient) NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error) {
return types.NetworkCreateResponse{}, nil
}
// NetworkDisconnect fakes disconencting from a network
func (c *FakeClient) NetworkDisconnect(ctx context.Context, networkID, container string, force bool) error {
return nil
}
// NetworkInspect fakes inspecting a network
func (c *FakeClient) NetworkInspect(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, error) {
if c.NetworkInspectFunc != nil {
return c.NetworkInspectFunc(ctx, networkID, verbose)
}
return types.NetworkResource{}, nil
}
// NetworkInspectWithRaw fakes inspecting a network with a raw response
func (c *FakeClient) NetworkInspectWithRaw(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, []byte, error) {
return types.NetworkResource{}, nil, nil
}
// NetworkList fakes listing networks
func (c *FakeClient) NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error) {
return nil, nil
}
// NetworkRemove fakes removing networks
func (c *FakeClient) NetworkRemove(ctx context.Context, networkID string) error {
return nil
}
// NetworksPrune fakes pruning networks
func (c *FakeClient) NetworksPrune(ctx context.Context, pruneFilter filters.Args) (types.NetworksPruneReport, error) {
return types.NetworksPruneReport{}, nil
}

View File

@ -3,7 +3,7 @@
set -e set -e
filewatcher \ filewatcher \
-L 5 \ -L 6 \
-x '**/*.swp' \ -x '**/*.swp' \
-x .git \ -x .git \
-x build \ -x build \