From 0c19045523edf661920490a8425afa42dd97232a Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Tue, 1 Nov 2016 05:49:39 +0000 Subject: [PATCH] api: allow creating a network of which name is the prefix of the ID of a swarm network Previously, it doesn't allow creating such a network: e.g. $ docker network inspect -f '{{.Id}}' ingress 84xh9knigj6zyt00u31e26nj3 $ docker network create 84 Error response from daemon: network with name 84 already exists Fix #27866 Signed-off-by: Akihiro Suda (cherry picked from commit edfbc3b8767ab2e89e73ba3142d2ddad295001e9) Signed-off-by: Victor Vieux --- api/server/router/network/network_routes.go | 2 +- daemon/cluster/cluster.go | 20 +++++++-- integration-cli/docker_cli_swarm_test.go | 47 +++++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/api/server/router/network/network_routes.go b/api/server/router/network/network_routes.go index 89ee5d5b35552..81b4d7da8629e 100644 --- a/api/server/router/network/network_routes.go +++ b/api/server/router/network/network_routes.go @@ -80,7 +80,7 @@ func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWr return err } - if _, err := n.clusterProvider.GetNetwork(create.Name); err == nil { + if nws, err := n.clusterProvider.GetNetworksByName(create.Name); err == nil && len(nws) > 0 { return libnetwork.NetworkNameError(create.Name) } diff --git a/daemon/cluster/cluster.go b/daemon/cluster/cluster.go index 21cd7f63a61cf..b5a626596daf8 100644 --- a/daemon/cluster/cluster.go +++ b/daemon/cluster/cluster.go @@ -1556,8 +1556,7 @@ func (c *Cluster) GetNetwork(input string) (apitypes.NetworkResource, error) { return convert.BasicNetworkFromGRPC(*network), nil } -// GetNetworks returns all current cluster managed networks. -func (c *Cluster) GetNetworks() ([]apitypes.NetworkResource, error) { +func (c *Cluster) getNetworks(filters *swarmapi.ListNetworksRequest_Filters) ([]apitypes.NetworkResource, error) { c.RLock() defer c.RUnlock() @@ -1568,7 +1567,7 @@ func (c *Cluster) GetNetworks() ([]apitypes.NetworkResource, error) { ctx, cancel := c.getRequestContext() defer cancel() - r, err := c.client.ListNetworks(ctx, &swarmapi.ListNetworksRequest{}) + r, err := c.client.ListNetworks(ctx, &swarmapi.ListNetworksRequest{Filters: filters}) if err != nil { return nil, err } @@ -1582,6 +1581,21 @@ func (c *Cluster) GetNetworks() ([]apitypes.NetworkResource, error) { return networks, nil } +// GetNetworks returns all current cluster managed networks. +func (c *Cluster) GetNetworks() ([]apitypes.NetworkResource, error) { + return c.getNetworks(nil) +} + +// GetNetworksByName returns cluster managed networks by name. +// It is ok to have multiple networks here. #18864 +func (c *Cluster) GetNetworksByName(name string) ([]apitypes.NetworkResource, error) { + // Note that swarmapi.GetNetworkRequest.Name is not functional. + // So we cannot just use that with c.GetNetwork. + return c.getNetworks(&swarmapi.ListNetworksRequest_Filters{ + Names: []string{name}, + }) +} + func attacherKey(target, containerID string) string { return containerID + ":" + target } diff --git a/integration-cli/docker_cli_swarm_test.go b/integration-cli/docker_cli_swarm_test.go index ed7a055bb685c..f86e977aa9b33 100644 --- a/integration-cli/docker_cli_swarm_test.go +++ b/integration-cli/docker_cli_swarm_test.go @@ -1184,3 +1184,50 @@ func (s *DockerTrustedSwarmSuite) TestTrustedServiceUpdate(c *check.C) { c.Assert(err, check.NotNil, check.Commentf(out)) c.Assert(string(out), checker.Contains, "Error: remote trust data does not exist", check.Commentf(out)) } + +// Test case for issue #27866, which did not allow NW name that is the prefix of a swarm NW ID. +// e.g. if the ingress ID starts with "n1", it was impossible to create a NW named "n1". +func (s *DockerSwarmSuite) TestSwarmNetworkCreateIssue27866(c *check.C) { + d := s.AddDaemon(c, true, true) + out, err := d.Cmd("network", "inspect", "-f", "{{.Id}}", "ingress") + c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) + ingressID := strings.TrimSpace(out) + c.Assert(ingressID, checker.Not(checker.Equals), "") + + // create a network of which name is the prefix of the ID of an overlay network + // (ingressID in this case) + newNetName := ingressID[0:2] + out, err = d.Cmd("network", "create", "--driver", "overlay", newNetName) + // In #27866, it was failing because of "network with name %s already exists" + c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) + out, err = d.Cmd("network", "rm", newNetName) + c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) +} + +// Test case for https://github.com/docker/docker/pull/27938#issuecomment-265768303 +// This test creates two networks with the same name sequentially, with various drivers. +// Since the operations in this test are done sequentially, the 2nd call should fail with +// "network with name FOO already exists". +// Note that it is to ok have multiple networks with the same name if the operations are done +// in parallel. (#18864) +func (s *DockerSwarmSuite) TestSwarmNetworkCreateDup(c *check.C) { + d := s.AddDaemon(c, true, true) + drivers := []string{"bridge", "overlay"} + for i, driver1 := range drivers { + nwName := fmt.Sprintf("network-test-%d", i) + for _, driver2 := range drivers { + c.Logf("Creating a network named %q with %q, then %q", + nwName, driver1, driver2) + out, err := d.Cmd("network", "create", "--driver", driver1, nwName) + c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) + out, err = d.Cmd("network", "create", "--driver", driver2, nwName) + c.Assert(out, checker.Contains, + fmt.Sprintf("network with name %s already exists", nwName)) + c.Assert(err, checker.NotNil) + c.Logf("As expected, the attempt to network %q with %q failed: %s", + nwName, driver2, out) + out, err = d.Cmd("network", "rm", nwName) + c.Assert(err, checker.IsNil, check.Commentf("out: %v", out)) + } + } +}