mirror of https://github.com/docker/cli.git
Merge pull request #132 from mavenugo/stack-host
Host and Bridge network support in docker stack deploy
This commit is contained in:
commit
efaadcf465
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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 \
|
||||||
|
|
Loading…
Reference in New Issue