diff --git a/cli/command/stack/deploy_composefile.go b/cli/command/stack/deploy_composefile.go index 8e5dfed4d5..1f50ae1a1d 100644 --- a/cli/command/stack/deploy_composefile.go +++ b/cli/command/stack/deploy_composefile.go @@ -171,13 +171,18 @@ func validateExternalNetworks( externalNetworks []string, ) error { for _, networkName := range externalNetworks { + if !container.NetworkMode(networkName).IsUserDefined() { + // Networks that are not user defined always exist on all nodes as + // local-scoped networks, so there's no need to inspect them. + continue + } network, err := client.NetworkInspect(ctx, networkName, types.NetworkInspectOptions{}) switch { case dockerclient.IsErrNotFound(err): 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 - case container.NetworkMode(networkName).IsUserDefined() && network.Scope != "swarm": + case 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) } } diff --git a/cli/command/stack/deploy_composefile_test.go b/cli/command/stack/deploy_composefile_test.go index 5d4813bc05..f303fc8865 100644 --- a/cli/command/stack/deploy_composefile_test.go +++ b/cli/command/stack/deploy_composefile_test.go @@ -42,6 +42,8 @@ func (n notFound) NotFound() bool { func TestValidateExternalNetworks(t *testing.T) { var testcases = []struct { + inspected bool + noInspect bool inspectResponse types.NetworkResource inspectError error expectedMsg string @@ -56,7 +58,8 @@ func TestValidateExternalNetworks(t *testing.T) { expectedMsg: "Unexpected", }, { - network: "host", + noInspect: true, + network: "host", }, { network: "user", @@ -71,11 +74,15 @@ func TestValidateExternalNetworks(t *testing.T) { for _, testcase := range testcases { fakeClient := &network.FakeClient{ NetworkInspectFunc: func(_ context.Context, _ string, _ types.NetworkInspectOptions) (types.NetworkResource, error) { + testcase.inspected = true return testcase.inspectResponse, testcase.inspectError }, } networks := []string{testcase.network} err := validateExternalNetworks(context.Background(), fakeClient, networks) + if testcase.noInspect && testcase.inspected { + assert.Fail(t, "expected no network inspect operation but one occurent") + } if testcase.expectedMsg == "" { assert.NoError(t, err) } else {