github.com/endophage/docker@v1.4.2-0.20161027011718-242853499895/integration-cli/docker_cli_network_unix_test.go (about)

     1  // +build !windows
     2  
     3  package main
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"net"
    10  	"net/http"
    11  	"net/http/httptest"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  	"time"
    16  
    17  	"github.com/docker/docker/api/types"
    18  	"github.com/docker/docker/api/types/versions/v1p20"
    19  	"github.com/docker/docker/pkg/integration/checker"
    20  	icmd "github.com/docker/docker/pkg/integration/cmd"
    21  	"github.com/docker/docker/pkg/stringid"
    22  	"github.com/docker/docker/runconfig"
    23  	"github.com/docker/libnetwork/driverapi"
    24  	remoteapi "github.com/docker/libnetwork/drivers/remote/api"
    25  	"github.com/docker/libnetwork/ipamapi"
    26  	remoteipam "github.com/docker/libnetwork/ipams/remote/api"
    27  	"github.com/docker/libnetwork/netlabel"
    28  	"github.com/go-check/check"
    29  	"github.com/vishvananda/netlink"
    30  )
    31  
    32  const dummyNetworkDriver = "dummy-network-driver"
    33  const dummyIPAMDriver = "dummy-ipam-driver"
    34  
    35  var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest
    36  
    37  func init() {
    38  	check.Suite(&DockerNetworkSuite{
    39  		ds: &DockerSuite{},
    40  	})
    41  }
    42  
    43  type DockerNetworkSuite struct {
    44  	server *httptest.Server
    45  	ds     *DockerSuite
    46  	d      *Daemon
    47  }
    48  
    49  func (s *DockerNetworkSuite) SetUpTest(c *check.C) {
    50  	s.d = NewDaemon(c)
    51  }
    52  
    53  func (s *DockerNetworkSuite) TearDownTest(c *check.C) {
    54  	s.d.Stop()
    55  	s.ds.TearDownTest(c)
    56  }
    57  
    58  func (s *DockerNetworkSuite) SetUpSuite(c *check.C) {
    59  	mux := http.NewServeMux()
    60  	s.server = httptest.NewServer(mux)
    61  	c.Assert(s.server, check.NotNil, check.Commentf("Failed to start an HTTP Server"))
    62  	setupRemoteNetworkDrivers(c, mux, s.server.URL, dummyNetworkDriver, dummyIPAMDriver)
    63  }
    64  
    65  func setupRemoteNetworkDrivers(c *check.C, mux *http.ServeMux, url, netDrv, ipamDrv string) {
    66  
    67  	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
    68  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
    69  		fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
    70  	})
    71  
    72  	// Network driver implementation
    73  	mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
    74  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
    75  		fmt.Fprintf(w, `{"Scope":"local"}`)
    76  	})
    77  
    78  	mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
    79  		err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
    80  		if err != nil {
    81  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
    82  			return
    83  		}
    84  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
    85  		fmt.Fprintf(w, "null")
    86  	})
    87  
    88  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
    89  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
    90  		fmt.Fprintf(w, "null")
    91  	})
    92  
    93  	mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
    94  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
    95  		fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
    96  	})
    97  
    98  	mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
    99  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   100  
   101  		veth := &netlink.Veth{
   102  			LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0"}
   103  		if err := netlink.LinkAdd(veth); err != nil {
   104  			fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
   105  		} else {
   106  			fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
   107  		}
   108  	})
   109  
   110  	mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   111  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   112  		fmt.Fprintf(w, "null")
   113  	})
   114  
   115  	mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   116  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   117  		if link, err := netlink.LinkByName("cnt0"); err == nil {
   118  			netlink.LinkDel(link)
   119  		}
   120  		fmt.Fprintf(w, "null")
   121  	})
   122  
   123  	// IPAM Driver implementation
   124  	var (
   125  		poolRequest       remoteipam.RequestPoolRequest
   126  		poolReleaseReq    remoteipam.ReleasePoolRequest
   127  		addressRequest    remoteipam.RequestAddressRequest
   128  		addressReleaseReq remoteipam.ReleaseAddressRequest
   129  		lAS               = "localAS"
   130  		gAS               = "globalAS"
   131  		pool              = "172.28.0.0/16"
   132  		poolID            = lAS + "/" + pool
   133  		gw                = "172.28.255.254/16"
   134  	)
   135  
   136  	mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   137  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   138  		fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
   139  	})
   140  
   141  	mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   142  		err := json.NewDecoder(r.Body).Decode(&poolRequest)
   143  		if err != nil {
   144  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   145  			return
   146  		}
   147  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   148  		if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
   149  			fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
   150  		} else if poolRequest.Pool != "" && poolRequest.Pool != pool {
   151  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
   152  		} else {
   153  			fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
   154  		}
   155  	})
   156  
   157  	mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   158  		err := json.NewDecoder(r.Body).Decode(&addressRequest)
   159  		if err != nil {
   160  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   161  			return
   162  		}
   163  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   164  		// make sure libnetwork is now querying on the expected pool id
   165  		if addressRequest.PoolID != poolID {
   166  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   167  		} else if addressRequest.Address != "" {
   168  			fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
   169  		} else {
   170  			fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
   171  		}
   172  	})
   173  
   174  	mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   175  		err := json.NewDecoder(r.Body).Decode(&addressReleaseReq)
   176  		if err != nil {
   177  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   178  			return
   179  		}
   180  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   181  		// make sure libnetwork is now asking to release the expected address from the expected poolid
   182  		if addressRequest.PoolID != poolID {
   183  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   184  		} else if addressReleaseReq.Address != gw {
   185  			fmt.Fprintf(w, `{"Error":"unknown address"}`)
   186  		} else {
   187  			fmt.Fprintf(w, "null")
   188  		}
   189  	})
   190  
   191  	mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
   192  		err := json.NewDecoder(r.Body).Decode(&poolReleaseReq)
   193  		if err != nil {
   194  			http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
   195  			return
   196  		}
   197  		w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
   198  		// make sure libnetwork is now asking to release the expected poolid
   199  		if addressRequest.PoolID != poolID {
   200  			fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
   201  		} else {
   202  			fmt.Fprintf(w, "null")
   203  		}
   204  	})
   205  
   206  	err := os.MkdirAll("/etc/docker/plugins", 0755)
   207  	c.Assert(err, checker.IsNil)
   208  
   209  	fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
   210  	err = ioutil.WriteFile(fileName, []byte(url), 0644)
   211  	c.Assert(err, checker.IsNil)
   212  
   213  	ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
   214  	err = ioutil.WriteFile(ipamFileName, []byte(url), 0644)
   215  	c.Assert(err, checker.IsNil)
   216  }
   217  
   218  func (s *DockerNetworkSuite) TearDownSuite(c *check.C) {
   219  	if s.server == nil {
   220  		return
   221  	}
   222  
   223  	s.server.Close()
   224  
   225  	err := os.RemoveAll("/etc/docker/plugins")
   226  	c.Assert(err, checker.IsNil)
   227  }
   228  
   229  func assertNwIsAvailable(c *check.C, name string) {
   230  	if !isNwPresent(c, name) {
   231  		c.Fatalf("Network %s not found in network ls o/p", name)
   232  	}
   233  }
   234  
   235  func assertNwNotAvailable(c *check.C, name string) {
   236  	if isNwPresent(c, name) {
   237  		c.Fatalf("Found network %s in network ls o/p", name)
   238  	}
   239  }
   240  
   241  func isNwPresent(c *check.C, name string) bool {
   242  	out, _ := dockerCmd(c, "network", "ls")
   243  	lines := strings.Split(out, "\n")
   244  	for i := 1; i < len(lines)-1; i++ {
   245  		netFields := strings.Fields(lines[i])
   246  		if netFields[1] == name {
   247  			return true
   248  		}
   249  	}
   250  	return false
   251  }
   252  
   253  // assertNwList checks network list retrieved with ls command
   254  // equals to expected network list
   255  // note: out should be `network ls [option]` result
   256  func assertNwList(c *check.C, out string, expectNws []string) {
   257  	lines := strings.Split(out, "\n")
   258  	var nwList []string
   259  	for _, line := range lines[1 : len(lines)-1] {
   260  		netFields := strings.Fields(line)
   261  		// wrap all network name in nwList
   262  		nwList = append(nwList, netFields[1])
   263  	}
   264  
   265  	// network ls should contains all expected networks
   266  	c.Assert(nwList, checker.DeepEquals, expectNws)
   267  }
   268  
   269  func getNwResource(c *check.C, name string) *types.NetworkResource {
   270  	out, _ := dockerCmd(c, "network", "inspect", name)
   271  	nr := []types.NetworkResource{}
   272  	err := json.Unmarshal([]byte(out), &nr)
   273  	c.Assert(err, check.IsNil)
   274  	return &nr[0]
   275  }
   276  
   277  func (s *DockerNetworkSuite) TestDockerNetworkLsDefault(c *check.C) {
   278  	defaults := []string{"bridge", "host", "none"}
   279  	for _, nn := range defaults {
   280  		assertNwIsAvailable(c, nn)
   281  	}
   282  }
   283  
   284  func (s *DockerSuite) TestNetworkLsFormat(c *check.C) {
   285  	testRequires(c, DaemonIsLinux)
   286  	out, _ := dockerCmd(c, "network", "ls", "--format", "{{.Name}}")
   287  	lines := strings.Split(strings.TrimSpace(string(out)), "\n")
   288  
   289  	expected := []string{"bridge", "host", "none"}
   290  	var names []string
   291  	names = append(names, lines...)
   292  	c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
   293  }
   294  
   295  func (s *DockerSuite) TestNetworkLsFormatDefaultFormat(c *check.C) {
   296  	testRequires(c, DaemonIsLinux)
   297  
   298  	config := `{
   299  		"networksFormat": "{{ .Name }} default"
   300  }`
   301  	d, err := ioutil.TempDir("", "integration-cli-")
   302  	c.Assert(err, checker.IsNil)
   303  	defer os.RemoveAll(d)
   304  
   305  	err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644)
   306  	c.Assert(err, checker.IsNil)
   307  
   308  	out, _ := dockerCmd(c, "--config", d, "network", "ls")
   309  	lines := strings.Split(strings.TrimSpace(string(out)), "\n")
   310  
   311  	expected := []string{"bridge default", "host default", "none default"}
   312  	var names []string
   313  	names = append(names, lines...)
   314  	c.Assert(expected, checker.DeepEquals, names, check.Commentf("Expected array with truncated names: %v, got: %v", expected, names))
   315  }
   316  
   317  func (s *DockerNetworkSuite) TestDockerNetworkCreatePredefined(c *check.C) {
   318  	predefined := []string{"bridge", "host", "none", "default"}
   319  	for _, net := range predefined {
   320  		// predefined networks can't be created again
   321  		out, _, err := dockerCmdWithError("network", "create", net)
   322  		c.Assert(err, checker.NotNil, check.Commentf("%v", out))
   323  	}
   324  }
   325  
   326  func (s *DockerNetworkSuite) TestDockerNetworkCreateHostBind(c *check.C) {
   327  	dockerCmd(c, "network", "create", "--subnet=192.168.10.0/24", "--gateway=192.168.10.1", "-o", "com.docker.network.bridge.host_binding_ipv4=192.168.10.1", "testbind")
   328  	assertNwIsAvailable(c, "testbind")
   329  
   330  	out, _ := runSleepingContainer(c, "--net=testbind", "-p", "5000:5000")
   331  	id := strings.TrimSpace(out)
   332  	c.Assert(waitRun(id), checker.IsNil)
   333  	out, _ = dockerCmd(c, "ps")
   334  	c.Assert(out, checker.Contains, "192.168.10.1:5000->5000/tcp")
   335  }
   336  
   337  func (s *DockerNetworkSuite) TestDockerNetworkRmPredefined(c *check.C) {
   338  	predefined := []string{"bridge", "host", "none", "default"}
   339  	for _, net := range predefined {
   340  		// predefined networks can't be removed
   341  		out, _, err := dockerCmdWithError("network", "rm", net)
   342  		c.Assert(err, checker.NotNil, check.Commentf("%v", out))
   343  	}
   344  }
   345  
   346  func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) {
   347  	testNet := "testnet1"
   348  	testLabel := "foo"
   349  	testValue := "bar"
   350  	out, _ := dockerCmd(c, "network", "create", "dev")
   351  	defer func() {
   352  		dockerCmd(c, "network", "rm", "dev")
   353  		dockerCmd(c, "network", "rm", testNet)
   354  	}()
   355  	networkID := strings.TrimSpace(out)
   356  
   357  	// filter with partial ID
   358  	// only show 'dev' network
   359  	out, _ = dockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5])
   360  	assertNwList(c, out, []string{"dev"})
   361  
   362  	out, _ = dockerCmd(c, "network", "ls", "-f", "name=dge")
   363  	assertNwList(c, out, []string{"bridge"})
   364  
   365  	// only show built-in network (bridge, none, host)
   366  	out, _ = dockerCmd(c, "network", "ls", "-f", "type=builtin")
   367  	assertNwList(c, out, []string{"bridge", "host", "none"})
   368  
   369  	// only show custom networks (dev)
   370  	out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom")
   371  	assertNwList(c, out, []string{"dev"})
   372  
   373  	// show all networks with filter
   374  	// it should be equivalent of ls without option
   375  	out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom", "-f", "type=builtin")
   376  	assertNwList(c, out, []string{"bridge", "dev", "host", "none"})
   377  
   378  	out, _ = dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
   379  	assertNwIsAvailable(c, testNet)
   380  
   381  	out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel)
   382  	assertNwList(c, out, []string{testNet})
   383  
   384  	out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel+"="+testValue)
   385  	assertNwList(c, out, []string{testNet})
   386  
   387  	out, _ = dockerCmd(c, "network", "ls", "-f", "label=nonexistent")
   388  	outArr := strings.Split(strings.TrimSpace(out), "\n")
   389  	c.Assert(len(outArr), check.Equals, 1, check.Commentf("%s\n", out))
   390  
   391  	out, _ = dockerCmd(c, "network", "ls", "-f", "driver=null")
   392  	assertNwList(c, out, []string{"none"})
   393  
   394  	out, _ = dockerCmd(c, "network", "ls", "-f", "driver=host")
   395  	assertNwList(c, out, []string{"host"})
   396  
   397  	out, _ = dockerCmd(c, "network", "ls", "-f", "driver=bridge")
   398  	assertNwList(c, out, []string{"bridge", "dev", testNet})
   399  }
   400  
   401  func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *check.C) {
   402  	dockerCmd(c, "network", "create", "test")
   403  	assertNwIsAvailable(c, "test")
   404  
   405  	dockerCmd(c, "network", "rm", "test")
   406  	assertNwNotAvailable(c, "test")
   407  }
   408  
   409  func (s *DockerNetworkSuite) TestDockerNetworkCreateLabel(c *check.C) {
   410  	testNet := "testnetcreatelabel"
   411  	testLabel := "foo"
   412  	testValue := "bar"
   413  
   414  	dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
   415  	assertNwIsAvailable(c, testNet)
   416  
   417  	out, _, err := dockerCmdWithError("network", "inspect", "--format={{ .Labels."+testLabel+" }}", testNet)
   418  	c.Assert(err, check.IsNil)
   419  	c.Assert(strings.TrimSpace(out), check.Equals, testValue)
   420  
   421  	dockerCmd(c, "network", "rm", testNet)
   422  	assertNwNotAvailable(c, testNet)
   423  }
   424  
   425  func (s *DockerSuite) TestDockerNetworkDeleteNotExists(c *check.C) {
   426  	out, _, err := dockerCmdWithError("network", "rm", "test")
   427  	c.Assert(err, checker.NotNil, check.Commentf("%v", out))
   428  }
   429  
   430  func (s *DockerSuite) TestDockerNetworkDeleteMultiple(c *check.C) {
   431  	dockerCmd(c, "network", "create", "testDelMulti0")
   432  	assertNwIsAvailable(c, "testDelMulti0")
   433  	dockerCmd(c, "network", "create", "testDelMulti1")
   434  	assertNwIsAvailable(c, "testDelMulti1")
   435  	dockerCmd(c, "network", "create", "testDelMulti2")
   436  	assertNwIsAvailable(c, "testDelMulti2")
   437  	out, _ := dockerCmd(c, "run", "-d", "--net", "testDelMulti2", "busybox", "top")
   438  	containerID := strings.TrimSpace(out)
   439  	waitRun(containerID)
   440  
   441  	// delete three networks at the same time, since testDelMulti2
   442  	// contains active container, its deletion should fail.
   443  	out, _, err := dockerCmdWithError("network", "rm", "testDelMulti0", "testDelMulti1", "testDelMulti2")
   444  	// err should not be nil due to deleting testDelMulti2 failed.
   445  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
   446  	// testDelMulti2 should fail due to network has active endpoints
   447  	c.Assert(out, checker.Contains, "has active endpoints")
   448  	assertNwNotAvailable(c, "testDelMulti0")
   449  	assertNwNotAvailable(c, "testDelMulti1")
   450  	// testDelMulti2 can't be deleted, so it should exist
   451  	assertNwIsAvailable(c, "testDelMulti2")
   452  }
   453  
   454  func (s *DockerSuite) TestDockerNetworkInspect(c *check.C) {
   455  	out, _ := dockerCmd(c, "network", "inspect", "host")
   456  	networkResources := []types.NetworkResource{}
   457  	err := json.Unmarshal([]byte(out), &networkResources)
   458  	c.Assert(err, check.IsNil)
   459  	c.Assert(networkResources, checker.HasLen, 1)
   460  
   461  	out, _ = dockerCmd(c, "network", "inspect", "--format={{ .Name }}", "host")
   462  	c.Assert(strings.TrimSpace(out), check.Equals, "host")
   463  }
   464  
   465  func (s *DockerSuite) TestDockerNetworkInspectWithID(c *check.C) {
   466  	out, _ := dockerCmd(c, "network", "create", "test2")
   467  	networkID := strings.TrimSpace(out)
   468  	assertNwIsAvailable(c, "test2")
   469  	out, _ = dockerCmd(c, "network", "inspect", "--format={{ .Id }}", "test2")
   470  	c.Assert(strings.TrimSpace(out), check.Equals, networkID)
   471  
   472  	out, _ = dockerCmd(c, "network", "inspect", "--format={{ .ID }}", "test2")
   473  	c.Assert(strings.TrimSpace(out), check.Equals, networkID)
   474  }
   475  
   476  func (s *DockerSuite) TestDockerInspectMultipleNetwork(c *check.C) {
   477  	result := dockerCmdWithResult("network", "inspect", "host", "none")
   478  	c.Assert(result, icmd.Matches, icmd.Success)
   479  
   480  	networkResources := []types.NetworkResource{}
   481  	err := json.Unmarshal([]byte(result.Stdout()), &networkResources)
   482  	c.Assert(err, check.IsNil)
   483  	c.Assert(networkResources, checker.HasLen, 2)
   484  
   485  	// Should print an error, return an exitCode 1 *but* should print the host network
   486  	result = dockerCmdWithResult("network", "inspect", "host", "nonexistent")
   487  	c.Assert(result, icmd.Matches, icmd.Expected{
   488  		ExitCode: 1,
   489  		Err:      "Error: No such network: nonexistent",
   490  		Out:      "host",
   491  	})
   492  
   493  	networkResources = []types.NetworkResource{}
   494  	err = json.Unmarshal([]byte(result.Stdout()), &networkResources)
   495  	c.Assert(networkResources, checker.HasLen, 1)
   496  
   497  	// Should print an error and return an exitCode, nothing else
   498  	result = dockerCmdWithResult("network", "inspect", "nonexistent")
   499  	c.Assert(result, icmd.Matches, icmd.Expected{
   500  		ExitCode: 1,
   501  		Err:      "Error: No such network: nonexistent",
   502  		Out:      "[]",
   503  	})
   504  }
   505  
   506  func (s *DockerSuite) TestDockerInspectNetworkWithContainerName(c *check.C) {
   507  	dockerCmd(c, "network", "create", "brNetForInspect")
   508  	assertNwIsAvailable(c, "brNetForInspect")
   509  	defer func() {
   510  		dockerCmd(c, "network", "rm", "brNetForInspect")
   511  		assertNwNotAvailable(c, "brNetForInspect")
   512  	}()
   513  
   514  	out, _ := dockerCmd(c, "run", "-d", "--name", "testNetInspect1", "--net", "brNetForInspect", "busybox", "top")
   515  	c.Assert(waitRun("testNetInspect1"), check.IsNil)
   516  	containerID := strings.TrimSpace(out)
   517  	defer func() {
   518  		// we don't stop container by name, because we'll rename it later
   519  		dockerCmd(c, "stop", containerID)
   520  	}()
   521  
   522  	out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect")
   523  	networkResources := []types.NetworkResource{}
   524  	err := json.Unmarshal([]byte(out), &networkResources)
   525  	c.Assert(err, check.IsNil)
   526  	c.Assert(networkResources, checker.HasLen, 1)
   527  	container, ok := networkResources[0].Containers[containerID]
   528  	c.Assert(ok, checker.True)
   529  	c.Assert(container.Name, checker.Equals, "testNetInspect1")
   530  
   531  	// rename container and check docker inspect output update
   532  	newName := "HappyNewName"
   533  	dockerCmd(c, "rename", "testNetInspect1", newName)
   534  
   535  	// check whether network inspect works properly
   536  	out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect")
   537  	newNetRes := []types.NetworkResource{}
   538  	err = json.Unmarshal([]byte(out), &newNetRes)
   539  	c.Assert(err, check.IsNil)
   540  	c.Assert(newNetRes, checker.HasLen, 1)
   541  	container1, ok := newNetRes[0].Containers[containerID]
   542  	c.Assert(ok, checker.True)
   543  	c.Assert(container1.Name, checker.Equals, newName)
   544  
   545  }
   546  
   547  func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
   548  	dockerCmd(c, "network", "create", "test")
   549  	assertNwIsAvailable(c, "test")
   550  	nr := getNwResource(c, "test")
   551  
   552  	c.Assert(nr.Name, checker.Equals, "test")
   553  	c.Assert(len(nr.Containers), checker.Equals, 0)
   554  
   555  	// run a container
   556  	out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
   557  	c.Assert(waitRun("test"), check.IsNil)
   558  	containerID := strings.TrimSpace(out)
   559  
   560  	// connect the container to the test network
   561  	dockerCmd(c, "network", "connect", "test", containerID)
   562  
   563  	// inspect the network to make sure container is connected
   564  	nr = getNetworkResource(c, nr.ID)
   565  	c.Assert(len(nr.Containers), checker.Equals, 1)
   566  	c.Assert(nr.Containers[containerID], check.NotNil)
   567  
   568  	// check if container IP matches network inspect
   569  	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
   570  	c.Assert(err, check.IsNil)
   571  	containerIP := findContainerIP(c, "test", "test")
   572  	c.Assert(ip.String(), checker.Equals, containerIP)
   573  
   574  	// disconnect container from the network
   575  	dockerCmd(c, "network", "disconnect", "test", containerID)
   576  	nr = getNwResource(c, "test")
   577  	c.Assert(nr.Name, checker.Equals, "test")
   578  	c.Assert(len(nr.Containers), checker.Equals, 0)
   579  
   580  	// run another container
   581  	out, _ = dockerCmd(c, "run", "-d", "--net", "test", "--name", "test2", "busybox", "top")
   582  	c.Assert(waitRun("test2"), check.IsNil)
   583  	containerID = strings.TrimSpace(out)
   584  
   585  	nr = getNwResource(c, "test")
   586  	c.Assert(nr.Name, checker.Equals, "test")
   587  	c.Assert(len(nr.Containers), checker.Equals, 1)
   588  
   589  	// force disconnect the container to the test network
   590  	dockerCmd(c, "network", "disconnect", "-f", "test", containerID)
   591  
   592  	nr = getNwResource(c, "test")
   593  	c.Assert(nr.Name, checker.Equals, "test")
   594  	c.Assert(len(nr.Containers), checker.Equals, 0)
   595  
   596  	dockerCmd(c, "network", "rm", "test")
   597  	assertNwNotAvailable(c, "test")
   598  }
   599  
   600  func (s *DockerNetworkSuite) TestDockerNetworkIPAMMultipleNetworks(c *check.C) {
   601  	// test0 bridge network
   602  	dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test1")
   603  	assertNwIsAvailable(c, "test1")
   604  
   605  	// test2 bridge network does not overlap
   606  	dockerCmd(c, "network", "create", "--subnet=192.169.0.0/16", "test2")
   607  	assertNwIsAvailable(c, "test2")
   608  
   609  	// for networks w/o ipam specified, docker will choose proper non-overlapping subnets
   610  	dockerCmd(c, "network", "create", "test3")
   611  	assertNwIsAvailable(c, "test3")
   612  	dockerCmd(c, "network", "create", "test4")
   613  	assertNwIsAvailable(c, "test4")
   614  	dockerCmd(c, "network", "create", "test5")
   615  	assertNwIsAvailable(c, "test5")
   616  
   617  	// test network with multiple subnets
   618  	// bridge network doesn't support multiple subnets. hence, use a dummy driver that supports
   619  
   620  	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", "test6")
   621  	assertNwIsAvailable(c, "test6")
   622  
   623  	// test network with multiple subnets with valid ipam combinations
   624  	// also check same subnet across networks when the driver supports it.
   625  	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver,
   626  		"--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16",
   627  		"--gateway=192.168.0.100", "--gateway=192.170.0.100",
   628  		"--ip-range=192.168.1.0/24",
   629  		"--aux-address", "a=192.168.1.5", "--aux-address", "b=192.168.1.6",
   630  		"--aux-address", "c=192.170.1.5", "--aux-address", "d=192.170.1.6",
   631  		"test7")
   632  	assertNwIsAvailable(c, "test7")
   633  
   634  	// cleanup
   635  	for i := 1; i < 8; i++ {
   636  		dockerCmd(c, "network", "rm", fmt.Sprintf("test%d", i))
   637  	}
   638  }
   639  
   640  func (s *DockerNetworkSuite) TestDockerNetworkCustomIPAM(c *check.C) {
   641  	// Create a bridge network using custom ipam driver
   642  	dockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "br0")
   643  	assertNwIsAvailable(c, "br0")
   644  
   645  	// Verify expected network ipam fields are there
   646  	nr := getNetworkResource(c, "br0")
   647  	c.Assert(nr.Driver, checker.Equals, "bridge")
   648  	c.Assert(nr.IPAM.Driver, checker.Equals, dummyIPAMDriver)
   649  
   650  	// remove network and exercise remote ipam driver
   651  	dockerCmd(c, "network", "rm", "br0")
   652  	assertNwNotAvailable(c, "br0")
   653  }
   654  
   655  func (s *DockerNetworkSuite) TestDockerNetworkIPAMOptions(c *check.C) {
   656  	// Create a bridge network using custom ipam driver and options
   657  	dockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "--ipam-opt", "opt1=drv1", "--ipam-opt", "opt2=drv2", "br0")
   658  	assertNwIsAvailable(c, "br0")
   659  
   660  	// Verify expected network ipam options
   661  	nr := getNetworkResource(c, "br0")
   662  	opts := nr.IPAM.Options
   663  	c.Assert(opts["opt1"], checker.Equals, "drv1")
   664  	c.Assert(opts["opt2"], checker.Equals, "drv2")
   665  }
   666  
   667  func (s *DockerNetworkSuite) TestDockerNetworkInspectDefault(c *check.C) {
   668  	nr := getNetworkResource(c, "none")
   669  	c.Assert(nr.Driver, checker.Equals, "null")
   670  	c.Assert(nr.Scope, checker.Equals, "local")
   671  	c.Assert(nr.Internal, checker.Equals, false)
   672  	c.Assert(nr.EnableIPv6, checker.Equals, false)
   673  	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
   674  	c.Assert(len(nr.IPAM.Config), checker.Equals, 0)
   675  
   676  	nr = getNetworkResource(c, "host")
   677  	c.Assert(nr.Driver, checker.Equals, "host")
   678  	c.Assert(nr.Scope, checker.Equals, "local")
   679  	c.Assert(nr.Internal, checker.Equals, false)
   680  	c.Assert(nr.EnableIPv6, checker.Equals, false)
   681  	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
   682  	c.Assert(len(nr.IPAM.Config), checker.Equals, 0)
   683  
   684  	nr = getNetworkResource(c, "bridge")
   685  	c.Assert(nr.Driver, checker.Equals, "bridge")
   686  	c.Assert(nr.Scope, checker.Equals, "local")
   687  	c.Assert(nr.Internal, checker.Equals, false)
   688  	c.Assert(nr.EnableIPv6, checker.Equals, false)
   689  	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
   690  	c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
   691  	c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil)
   692  	c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil)
   693  }
   694  
   695  func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomUnspecified(c *check.C) {
   696  	// if unspecified, network subnet will be selected from inside preferred pool
   697  	dockerCmd(c, "network", "create", "test01")
   698  	assertNwIsAvailable(c, "test01")
   699  
   700  	nr := getNetworkResource(c, "test01")
   701  	c.Assert(nr.Driver, checker.Equals, "bridge")
   702  	c.Assert(nr.Scope, checker.Equals, "local")
   703  	c.Assert(nr.Internal, checker.Equals, false)
   704  	c.Assert(nr.EnableIPv6, checker.Equals, false)
   705  	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
   706  	c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
   707  	c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil)
   708  	c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil)
   709  
   710  	dockerCmd(c, "network", "rm", "test01")
   711  	assertNwNotAvailable(c, "test01")
   712  }
   713  
   714  func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomSpecified(c *check.C) {
   715  	dockerCmd(c, "network", "create", "--driver=bridge", "--ipv6", "--subnet=172.28.0.0/16", "--ip-range=172.28.5.0/24", "--gateway=172.28.5.254", "br0")
   716  	assertNwIsAvailable(c, "br0")
   717  
   718  	nr := getNetworkResource(c, "br0")
   719  	c.Assert(nr.Driver, checker.Equals, "bridge")
   720  	c.Assert(nr.Scope, checker.Equals, "local")
   721  	c.Assert(nr.Internal, checker.Equals, false)
   722  	c.Assert(nr.EnableIPv6, checker.Equals, true)
   723  	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
   724  	c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
   725  	c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16")
   726  	c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24")
   727  	c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254")
   728  	c.Assert(nr.Internal, checker.False)
   729  	dockerCmd(c, "network", "rm", "br0")
   730  	assertNwNotAvailable(c, "test01")
   731  }
   732  
   733  func (s *DockerNetworkSuite) TestDockerNetworkIPAMInvalidCombinations(c *check.C) {
   734  	// network with ip-range out of subnet range
   735  	_, _, err := dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--ip-range=192.170.0.0/16", "test")
   736  	c.Assert(err, check.NotNil)
   737  
   738  	// network with multiple gateways for a single subnet
   739  	_, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--gateway=192.168.0.1", "--gateway=192.168.0.2", "test")
   740  	c.Assert(err, check.NotNil)
   741  
   742  	// Multiple overlapping subnets in the same network must fail
   743  	_, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--subnet=192.168.1.0/16", "test")
   744  	c.Assert(err, check.NotNil)
   745  
   746  	// overlapping subnets across networks must fail
   747  	// create a valid test0 network
   748  	dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test0")
   749  	assertNwIsAvailable(c, "test0")
   750  	// create an overlapping test1 network
   751  	_, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.128.0/17", "test1")
   752  	c.Assert(err, check.NotNil)
   753  	dockerCmd(c, "network", "rm", "test0")
   754  	assertNwNotAvailable(c, "test0")
   755  }
   756  
   757  func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) {
   758  	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "-o", "opt1=drv1", "-o", "opt2=drv2", "testopt")
   759  	assertNwIsAvailable(c, "testopt")
   760  	gopts := remoteDriverNetworkRequest.Options[netlabel.GenericData]
   761  	c.Assert(gopts, checker.NotNil)
   762  	opts, ok := gopts.(map[string]interface{})
   763  	c.Assert(ok, checker.Equals, true)
   764  	c.Assert(opts["opt1"], checker.Equals, "drv1")
   765  	c.Assert(opts["opt2"], checker.Equals, "drv2")
   766  	dockerCmd(c, "network", "rm", "testopt")
   767  	assertNwNotAvailable(c, "testopt")
   768  
   769  }
   770  
   771  func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *check.C) {
   772  	testRequires(c, ExecSupport)
   773  	// On default bridge network built-in service discovery should not happen
   774  	hostsFile := "/etc/hosts"
   775  	bridgeName := "external-bridge"
   776  	bridgeIP := "192.169.255.254/24"
   777  	out, err := createInterface(c, "bridge", bridgeName, bridgeIP)
   778  	c.Assert(err, check.IsNil, check.Commentf(out))
   779  	defer deleteInterface(c, bridgeName)
   780  
   781  	err = s.d.StartWithBusybox("--bridge", bridgeName)
   782  	c.Assert(err, check.IsNil)
   783  	defer s.d.Restart()
   784  
   785  	// run two containers and store first container's etc/hosts content
   786  	out, err = s.d.Cmd("run", "-d", "busybox", "top")
   787  	c.Assert(err, check.IsNil)
   788  	cid1 := strings.TrimSpace(out)
   789  	defer s.d.Cmd("stop", cid1)
   790  
   791  	hosts, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
   792  	c.Assert(err, checker.IsNil)
   793  
   794  	out, err = s.d.Cmd("run", "-d", "--name", "container2", "busybox", "top")
   795  	c.Assert(err, check.IsNil)
   796  	cid2 := strings.TrimSpace(out)
   797  
   798  	// verify first container's etc/hosts file has not changed after spawning the second named container
   799  	hostsPost, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
   800  	c.Assert(err, checker.IsNil)
   801  	c.Assert(string(hosts), checker.Equals, string(hostsPost),
   802  		check.Commentf("Unexpected %s change on second container creation", hostsFile))
   803  
   804  	// stop container 2 and verify first container's etc/hosts has not changed
   805  	_, err = s.d.Cmd("stop", cid2)
   806  	c.Assert(err, check.IsNil)
   807  
   808  	hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
   809  	c.Assert(err, checker.IsNil)
   810  	c.Assert(string(hosts), checker.Equals, string(hostsPost),
   811  		check.Commentf("Unexpected %s change on second container creation", hostsFile))
   812  
   813  	// but discovery is on when connecting to non default bridge network
   814  	network := "anotherbridge"
   815  	out, err = s.d.Cmd("network", "create", network)
   816  	c.Assert(err, check.IsNil, check.Commentf(out))
   817  	defer s.d.Cmd("network", "rm", network)
   818  
   819  	out, err = s.d.Cmd("network", "connect", network, cid1)
   820  	c.Assert(err, check.IsNil, check.Commentf(out))
   821  
   822  	hosts, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
   823  	c.Assert(err, checker.IsNil)
   824  
   825  	hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
   826  	c.Assert(err, checker.IsNil)
   827  	c.Assert(string(hosts), checker.Equals, string(hostsPost),
   828  		check.Commentf("Unexpected %s change on second network connection", hostsFile))
   829  }
   830  
   831  func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *check.C) {
   832  	testRequires(c, ExecSupport, NotArm)
   833  	hostsFile := "/etc/hosts"
   834  	cstmBridgeNw := "custom-bridge-nw"
   835  	cstmBridgeNw1 := "custom-bridge-nw1"
   836  
   837  	dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw)
   838  	assertNwIsAvailable(c, cstmBridgeNw)
   839  
   840  	// run two anonymous containers and store their etc/hosts content
   841  	out, _ := dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top")
   842  	cid1 := strings.TrimSpace(out)
   843  
   844  	hosts1, err := readContainerFileWithExec(cid1, hostsFile)
   845  	c.Assert(err, checker.IsNil)
   846  
   847  	out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top")
   848  	cid2 := strings.TrimSpace(out)
   849  
   850  	hosts2, err := readContainerFileWithExec(cid2, hostsFile)
   851  	c.Assert(err, checker.IsNil)
   852  
   853  	// verify first container etc/hosts file has not changed
   854  	hosts1post, err := readContainerFileWithExec(cid1, hostsFile)
   855  	c.Assert(err, checker.IsNil)
   856  	c.Assert(string(hosts1), checker.Equals, string(hosts1post),
   857  		check.Commentf("Unexpected %s change on anonymous container creation", hostsFile))
   858  
   859  	// Connect the 2nd container to a new network and verify the
   860  	// first container /etc/hosts file still hasn't changed.
   861  	dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw1)
   862  	assertNwIsAvailable(c, cstmBridgeNw1)
   863  
   864  	dockerCmd(c, "network", "connect", cstmBridgeNw1, cid2)
   865  
   866  	hosts2, err = readContainerFileWithExec(cid2, hostsFile)
   867  	c.Assert(err, checker.IsNil)
   868  
   869  	hosts1post, err = readContainerFileWithExec(cid1, hostsFile)
   870  	c.Assert(err, checker.IsNil)
   871  	c.Assert(string(hosts1), checker.Equals, string(hosts1post),
   872  		check.Commentf("Unexpected %s change on container connect", hostsFile))
   873  
   874  	// start a named container
   875  	cName := "AnyName"
   876  	out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top")
   877  	cid3 := strings.TrimSpace(out)
   878  
   879  	// verify that container 1 and 2 can ping the named container
   880  	dockerCmd(c, "exec", cid1, "ping", "-c", "1", cName)
   881  	dockerCmd(c, "exec", cid2, "ping", "-c", "1", cName)
   882  
   883  	// Stop named container and verify first two containers' etc/hosts file hasn't changed
   884  	dockerCmd(c, "stop", cid3)
   885  	hosts1post, err = readContainerFileWithExec(cid1, hostsFile)
   886  	c.Assert(err, checker.IsNil)
   887  	c.Assert(string(hosts1), checker.Equals, string(hosts1post),
   888  		check.Commentf("Unexpected %s change on name container creation", hostsFile))
   889  
   890  	hosts2post, err := readContainerFileWithExec(cid2, hostsFile)
   891  	c.Assert(err, checker.IsNil)
   892  	c.Assert(string(hosts2), checker.Equals, string(hosts2post),
   893  		check.Commentf("Unexpected %s change on name container creation", hostsFile))
   894  
   895  	// verify that container 1 and 2 can't ping the named container now
   896  	_, _, err = dockerCmdWithError("exec", cid1, "ping", "-c", "1", cName)
   897  	c.Assert(err, check.NotNil)
   898  	_, _, err = dockerCmdWithError("exec", cid2, "ping", "-c", "1", cName)
   899  	c.Assert(err, check.NotNil)
   900  }
   901  
   902  func (s *DockerNetworkSuite) TestDockerNetworkLinkOnDefaultNetworkOnly(c *check.C) {
   903  	// Legacy Link feature must work only on default network, and not across networks
   904  	cnt1 := "container1"
   905  	cnt2 := "container2"
   906  	network := "anotherbridge"
   907  
   908  	// Run first container on default network
   909  	dockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top")
   910  
   911  	// Create another network and run the second container on it
   912  	dockerCmd(c, "network", "create", network)
   913  	assertNwIsAvailable(c, network)
   914  	dockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top")
   915  
   916  	// Try launching a container on default network, linking to the first container. Must succeed
   917  	dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top")
   918  
   919  	// Try launching a container on default network, linking to the second container. Must fail
   920  	_, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
   921  	c.Assert(err, checker.NotNil)
   922  
   923  	// Connect second container to default network. Now a container on default network can link to it
   924  	dockerCmd(c, "network", "connect", "bridge", cnt2)
   925  	dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
   926  }
   927  
   928  func (s *DockerNetworkSuite) TestDockerNetworkOverlayPortMapping(c *check.C) {
   929  	// Verify exposed ports are present in ps output when running a container on
   930  	// a network managed by a driver which does not provide the default gateway
   931  	// for the container
   932  	nwn := "ov"
   933  	ctn := "bb"
   934  	port1 := 80
   935  	port2 := 443
   936  	expose1 := fmt.Sprintf("--expose=%d", port1)
   937  	expose2 := fmt.Sprintf("--expose=%d", port2)
   938  
   939  	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn)
   940  	assertNwIsAvailable(c, nwn)
   941  
   942  	dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, expose1, expose2, "busybox", "top")
   943  
   944  	// Check docker ps o/p for last created container reports the unpublished ports
   945  	unpPort1 := fmt.Sprintf("%d/tcp", port1)
   946  	unpPort2 := fmt.Sprintf("%d/tcp", port2)
   947  	out, _ := dockerCmd(c, "ps", "-n=1")
   948  	// Missing unpublished ports in docker ps output
   949  	c.Assert(out, checker.Contains, unpPort1)
   950  	// Missing unpublished ports in docker ps output
   951  	c.Assert(out, checker.Contains, unpPort2)
   952  }
   953  
   954  func (s *DockerNetworkSuite) TestDockerNetworkDriverUngracefulRestart(c *check.C) {
   955  	testRequires(c, DaemonIsLinux, NotUserNamespace)
   956  	dnd := "dnd"
   957  	did := "did"
   958  
   959  	mux := http.NewServeMux()
   960  	server := httptest.NewServer(mux)
   961  	setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did)
   962  
   963  	s.d.StartWithBusybox()
   964  	_, err := s.d.Cmd("network", "create", "-d", dnd, "--subnet", "1.1.1.0/24", "net1")
   965  	c.Assert(err, checker.IsNil)
   966  
   967  	_, err = s.d.Cmd("run", "-itd", "--net", "net1", "--name", "foo", "--ip", "1.1.1.10", "busybox", "sh")
   968  	c.Assert(err, checker.IsNil)
   969  
   970  	// Kill daemon and restart
   971  	if err = s.d.cmd.Process.Kill(); err != nil {
   972  		c.Fatal(err)
   973  	}
   974  
   975  	server.Close()
   976  
   977  	startTime := time.Now().Unix()
   978  	if err = s.d.Restart(); err != nil {
   979  		c.Fatal(err)
   980  	}
   981  	lapse := time.Now().Unix() - startTime
   982  	if lapse > 60 {
   983  		// In normal scenarios, daemon restart takes ~1 second.
   984  		// Plugin retry mechanism can delay the daemon start. systemd may not like it.
   985  		// Avoid accessing plugins during daemon bootup
   986  		c.Logf("daemon restart took too long : %d seconds", lapse)
   987  	}
   988  
   989  	// Restart the custom dummy plugin
   990  	mux = http.NewServeMux()
   991  	server = httptest.NewServer(mux)
   992  	setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did)
   993  
   994  	// trying to reuse the same ip must succeed
   995  	_, err = s.d.Cmd("run", "-itd", "--net", "net1", "--name", "bar", "--ip", "1.1.1.10", "busybox", "sh")
   996  	c.Assert(err, checker.IsNil)
   997  }
   998  
   999  func (s *DockerNetworkSuite) TestDockerNetworkMacInspect(c *check.C) {
  1000  	// Verify endpoint MAC address is correctly populated in container's network settings
  1001  	nwn := "ov"
  1002  	ctn := "bb"
  1003  
  1004  	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn)
  1005  	assertNwIsAvailable(c, nwn)
  1006  
  1007  	dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, "busybox", "top")
  1008  
  1009  	mac := inspectField(c, ctn, "NetworkSettings.Networks."+nwn+".MacAddress")
  1010  	c.Assert(mac, checker.Equals, "a0:b1:c2:d3:e4:f5")
  1011  }
  1012  
  1013  func (s *DockerSuite) TestInspectAPIMultipleNetworks(c *check.C) {
  1014  	dockerCmd(c, "network", "create", "mybridge1")
  1015  	dockerCmd(c, "network", "create", "mybridge2")
  1016  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  1017  	id := strings.TrimSpace(out)
  1018  	c.Assert(waitRun(id), check.IsNil)
  1019  
  1020  	dockerCmd(c, "network", "connect", "mybridge1", id)
  1021  	dockerCmd(c, "network", "connect", "mybridge2", id)
  1022  
  1023  	body := getInspectBody(c, "v1.20", id)
  1024  	var inspect120 v1p20.ContainerJSON
  1025  	err := json.Unmarshal(body, &inspect120)
  1026  	c.Assert(err, checker.IsNil)
  1027  
  1028  	versionedIP := inspect120.NetworkSettings.IPAddress
  1029  
  1030  	body = getInspectBody(c, "v1.21", id)
  1031  	var inspect121 types.ContainerJSON
  1032  	err = json.Unmarshal(body, &inspect121)
  1033  	c.Assert(err, checker.IsNil)
  1034  	c.Assert(inspect121.NetworkSettings.Networks, checker.HasLen, 3)
  1035  
  1036  	bridge := inspect121.NetworkSettings.Networks["bridge"]
  1037  	c.Assert(bridge.IPAddress, checker.Equals, versionedIP)
  1038  	c.Assert(bridge.IPAddress, checker.Equals, inspect121.NetworkSettings.IPAddress)
  1039  }
  1040  
  1041  func connectContainerToNetworks(c *check.C, d *Daemon, cName string, nws []string) {
  1042  	// Run a container on the default network
  1043  	out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top")
  1044  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1045  
  1046  	// Attach the container to other networks
  1047  	for _, nw := range nws {
  1048  		out, err = d.Cmd("network", "create", nw)
  1049  		c.Assert(err, checker.IsNil, check.Commentf(out))
  1050  		out, err = d.Cmd("network", "connect", nw, cName)
  1051  		c.Assert(err, checker.IsNil, check.Commentf(out))
  1052  	}
  1053  }
  1054  
  1055  func verifyContainerIsConnectedToNetworks(c *check.C, d *Daemon, cName string, nws []string) {
  1056  	// Verify container is connected to all the networks
  1057  	for _, nw := range nws {
  1058  		out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName)
  1059  		c.Assert(err, checker.IsNil, check.Commentf(out))
  1060  		c.Assert(out, checker.Not(checker.Equals), "<no value>\n")
  1061  	}
  1062  }
  1063  
  1064  func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *check.C) {
  1065  	cName := "bb"
  1066  	nwList := []string{"nw1", "nw2", "nw3"}
  1067  
  1068  	s.d.StartWithBusybox()
  1069  
  1070  	connectContainerToNetworks(c, s.d, cName, nwList)
  1071  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1072  
  1073  	// Reload daemon
  1074  	s.d.Restart()
  1075  
  1076  	_, err := s.d.Cmd("start", cName)
  1077  	c.Assert(err, checker.IsNil)
  1078  
  1079  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1080  }
  1081  
  1082  func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRestart(c *check.C) {
  1083  	cName := "cc"
  1084  	nwList := []string{"nw1", "nw2", "nw3"}
  1085  
  1086  	s.d.StartWithBusybox()
  1087  
  1088  	connectContainerToNetworks(c, s.d, cName, nwList)
  1089  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1090  
  1091  	// Kill daemon and restart
  1092  	if err := s.d.cmd.Process.Kill(); err != nil {
  1093  		c.Fatal(err)
  1094  	}
  1095  	s.d.Restart()
  1096  
  1097  	// Restart container
  1098  	_, err := s.d.Cmd("start", cName)
  1099  	c.Assert(err, checker.IsNil)
  1100  
  1101  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1102  }
  1103  
  1104  func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *check.C) {
  1105  	out, _ := dockerCmd(c, "network", "create", "one")
  1106  	containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top")
  1107  	c.Assert(err, checker.IsNil, check.Commentf(containerOut))
  1108  }
  1109  
  1110  func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *check.C) {
  1111  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1112  	s.d.StartWithBusybox()
  1113  
  1114  	// Run a few containers on host network
  1115  	for i := 0; i < 10; i++ {
  1116  		cName := fmt.Sprintf("hostc-%d", i)
  1117  		out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top")
  1118  		c.Assert(err, checker.IsNil, check.Commentf(out))
  1119  
  1120  		// verfiy container has finished starting before killing daemon
  1121  		err = s.d.waitRun(cName)
  1122  		c.Assert(err, checker.IsNil)
  1123  	}
  1124  
  1125  	// Kill daemon ungracefully and restart
  1126  	if err := s.d.cmd.Process.Kill(); err != nil {
  1127  		c.Fatal(err)
  1128  	}
  1129  	if err := s.d.Restart(); err != nil {
  1130  		c.Fatal(err)
  1131  	}
  1132  
  1133  	// make sure all the containers are up and running
  1134  	for i := 0; i < 10; i++ {
  1135  		err := s.d.waitRun(fmt.Sprintf("hostc-%d", i))
  1136  		c.Assert(err, checker.IsNil)
  1137  	}
  1138  }
  1139  
  1140  func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *check.C) {
  1141  	dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
  1142  	c.Assert(waitRun("container1"), check.IsNil)
  1143  	dockerCmd(c, "network", "disconnect", "bridge", "container1")
  1144  	out, _, err := dockerCmdWithError("network", "connect", "host", "container1")
  1145  	c.Assert(err, checker.NotNil, check.Commentf(out))
  1146  	c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error())
  1147  }
  1148  
  1149  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *check.C) {
  1150  	dockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top")
  1151  	c.Assert(waitRun("container1"), check.IsNil)
  1152  	out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1")
  1153  	c.Assert(err, checker.NotNil, check.Commentf("Should err out disconnect from host"))
  1154  	c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error())
  1155  }
  1156  
  1157  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *check.C) {
  1158  	testRequires(c, NotArm)
  1159  	dockerCmd(c, "network", "create", "test1")
  1160  	dockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top")
  1161  	c.Assert(waitRun("c1"), check.IsNil)
  1162  	dockerCmd(c, "network", "connect", "test1", "c1")
  1163  }
  1164  
  1165  func verifyPortMap(c *check.C, container, port, originalMapping string, mustBeEqual bool) {
  1166  	chk := checker.Equals
  1167  	if !mustBeEqual {
  1168  		chk = checker.Not(checker.Equals)
  1169  	}
  1170  	currentMapping, _ := dockerCmd(c, "port", container, port)
  1171  	c.Assert(currentMapping, chk, originalMapping)
  1172  }
  1173  
  1174  func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectWithPortMapping(c *check.C) {
  1175  	// Connect and disconnect a container with explicit and non-explicit
  1176  	// host port mapping to/from networks which do cause and do not cause
  1177  	// the container default gateway to change, and verify docker port cmd
  1178  	// returns congruent information
  1179  	testRequires(c, NotArm)
  1180  	cnt := "c1"
  1181  	dockerCmd(c, "network", "create", "aaa")
  1182  	dockerCmd(c, "network", "create", "ccc")
  1183  
  1184  	dockerCmd(c, "run", "-d", "--name", cnt, "-p", "9000:90", "-p", "70", "busybox", "top")
  1185  	c.Assert(waitRun(cnt), check.IsNil)
  1186  	curPortMap, _ := dockerCmd(c, "port", cnt, "70")
  1187  	curExplPortMap, _ := dockerCmd(c, "port", cnt, "90")
  1188  
  1189  	// Connect to a network which causes the container's default gw switch
  1190  	dockerCmd(c, "network", "connect", "aaa", cnt)
  1191  	verifyPortMap(c, cnt, "70", curPortMap, false)
  1192  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1193  
  1194  	// Read current mapping
  1195  	curPortMap, _ = dockerCmd(c, "port", cnt, "70")
  1196  
  1197  	// Disconnect from a network which causes the container's default gw switch
  1198  	dockerCmd(c, "network", "disconnect", "aaa", cnt)
  1199  	verifyPortMap(c, cnt, "70", curPortMap, false)
  1200  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1201  
  1202  	// Read current mapping
  1203  	curPortMap, _ = dockerCmd(c, "port", cnt, "70")
  1204  
  1205  	// Connect to a network which does not cause the container's default gw switch
  1206  	dockerCmd(c, "network", "connect", "ccc", cnt)
  1207  	verifyPortMap(c, cnt, "70", curPortMap, true)
  1208  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1209  }
  1210  
  1211  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *check.C) {
  1212  	macAddress := "02:42:ac:11:00:02"
  1213  	dockerCmd(c, "network", "create", "mynetwork")
  1214  	dockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top")
  1215  	c.Assert(waitRun("test"), check.IsNil)
  1216  	mac1 := inspectField(c, "test", "NetworkSettings.Networks.bridge.MacAddress")
  1217  	c.Assert(strings.TrimSpace(mac1), checker.Equals, macAddress)
  1218  	dockerCmd(c, "network", "connect", "mynetwork", "test")
  1219  	mac2 := inspectField(c, "test", "NetworkSettings.Networks.mynetwork.MacAddress")
  1220  	c.Assert(strings.TrimSpace(mac2), checker.Not(checker.Equals), strings.TrimSpace(mac1))
  1221  }
  1222  
  1223  func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *check.C) {
  1224  	dockerCmd(c, "create", "--name", "test", "busybox")
  1225  	networks := inspectField(c, "test", "NetworkSettings.Networks")
  1226  	c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should return 'bridge' network"))
  1227  }
  1228  
  1229  func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMultipleNetworks(c *check.C) {
  1230  	dockerCmd(c, "network", "create", "test")
  1231  	dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top")
  1232  	c.Assert(waitRun("foo"), checker.IsNil)
  1233  	dockerCmd(c, "network", "connect", "test", "foo")
  1234  	dockerCmd(c, "restart", "foo")
  1235  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1236  	c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should contain 'bridge' network"))
  1237  	c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
  1238  }
  1239  
  1240  func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *check.C) {
  1241  	dockerCmd(c, "network", "create", "test")
  1242  	dockerCmd(c, "create", "--name=foo", "busybox", "top")
  1243  	dockerCmd(c, "network", "connect", "test", "foo")
  1244  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1245  	c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
  1246  
  1247  	// Restart docker daemon to test the config has persisted to disk
  1248  	s.d.Restart()
  1249  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1250  	c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
  1251  
  1252  	// start the container and test if we can ping it from another container in the same network
  1253  	dockerCmd(c, "start", "foo")
  1254  	c.Assert(waitRun("foo"), checker.IsNil)
  1255  	ip := inspectField(c, "foo", "NetworkSettings.Networks.test.IPAddress")
  1256  	ip = strings.TrimSpace(ip)
  1257  	dockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip))
  1258  
  1259  	dockerCmd(c, "stop", "foo")
  1260  
  1261  	// Test disconnect
  1262  	dockerCmd(c, "network", "disconnect", "test", "foo")
  1263  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1264  	c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
  1265  
  1266  	// Restart docker daemon to test the config has persisted to disk
  1267  	s.d.Restart()
  1268  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1269  	c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
  1270  
  1271  }
  1272  
  1273  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *check.C) {
  1274  	dockerCmd(c, "network", "create", "test")
  1275  	dockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top")
  1276  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1277  	c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
  1278  
  1279  	// Stop container and remove network
  1280  	dockerCmd(c, "stop", "foo")
  1281  	dockerCmd(c, "network", "rm", "test")
  1282  
  1283  	// Test disconnecting stopped container from nonexisting network
  1284  	dockerCmd(c, "network", "disconnect", "-f", "test", "foo")
  1285  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1286  	c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
  1287  }
  1288  
  1289  func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) {
  1290  	// create two networks
  1291  	dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")
  1292  	assertNwIsAvailable(c, "n0")
  1293  
  1294  	dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--ip-range=172.30.5.0/24", "--subnet=2001:db8:abcd::/64", "--ip-range=2001:db8:abcd::/80", "n1")
  1295  	assertNwIsAvailable(c, "n1")
  1296  
  1297  	// run a container on first network specifying the ip addresses
  1298  	dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1299  	c.Assert(waitRun("c0"), check.IsNil)
  1300  	verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1301  	verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1302  
  1303  	// connect the container to the second network specifying an ip addresses
  1304  	dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0")
  1305  	verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1306  	verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1307  
  1308  	// Stop and restart the container
  1309  	dockerCmd(c, "stop", "c0")
  1310  	dockerCmd(c, "start", "c0")
  1311  
  1312  	// verify requested addresses are applied and configs are still there
  1313  	verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1314  	verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1315  	verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1316  	verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1317  
  1318  	// Still it should fail to connect to the default network with a specified IP (whatever ip)
  1319  	out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0")
  1320  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1321  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error())
  1322  
  1323  }
  1324  
  1325  func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIPStoppedContainer(c *check.C) {
  1326  	// create a container
  1327  	dockerCmd(c, "create", "--name", "c0", "busybox", "top")
  1328  
  1329  	// create a network
  1330  	dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0")
  1331  	assertNwIsAvailable(c, "n0")
  1332  
  1333  	// connect the container to the network specifying an ip addresses
  1334  	dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n0", "c0")
  1335  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1336  
  1337  	// start the container, verify config has not changed and ip addresses are assigned
  1338  	dockerCmd(c, "start", "c0")
  1339  	c.Assert(waitRun("c0"), check.IsNil)
  1340  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1341  	verifyIPAddresses(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1342  
  1343  	// stop the container and check ip config has not changed
  1344  	dockerCmd(c, "stop", "c0")
  1345  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1346  }
  1347  
  1348  func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedRequiredIP(c *check.C) {
  1349  	// requested IP is not supported on predefined networks
  1350  	for _, mode := range []string{"none", "host", "bridge", "default"} {
  1351  		checkUnsupportedNetworkAndIP(c, mode)
  1352  	}
  1353  
  1354  	// requested IP is not supported on networks with no user defined subnets
  1355  	dockerCmd(c, "network", "create", "n0")
  1356  	assertNwIsAvailable(c, "n0")
  1357  
  1358  	out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top")
  1359  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1360  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error())
  1361  
  1362  	out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--net", "n0", "busybox", "top")
  1363  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1364  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error())
  1365  
  1366  	dockerCmd(c, "network", "rm", "n0")
  1367  	assertNwNotAvailable(c, "n0")
  1368  }
  1369  
  1370  func checkUnsupportedNetworkAndIP(c *check.C, nwMode string) {
  1371  	out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1372  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1373  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error())
  1374  }
  1375  
  1376  func verifyIPAddressConfig(c *check.C, cName, nwname, ipv4, ipv6 string) {
  1377  	if ipv4 != "" {
  1378  		out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv4Address", nwname))
  1379  		c.Assert(strings.TrimSpace(out), check.Equals, ipv4)
  1380  	}
  1381  
  1382  	if ipv6 != "" {
  1383  		out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv6Address", nwname))
  1384  		c.Assert(strings.TrimSpace(out), check.Equals, ipv6)
  1385  	}
  1386  }
  1387  
  1388  func verifyIPAddresses(c *check.C, cName, nwname, ipv4, ipv6 string) {
  1389  	out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAddress", nwname))
  1390  	c.Assert(strings.TrimSpace(out), check.Equals, ipv4)
  1391  
  1392  	out = inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.GlobalIPv6Address", nwname))
  1393  	c.Assert(strings.TrimSpace(out), check.Equals, ipv6)
  1394  }
  1395  
  1396  func (s *DockerNetworkSuite) TestDockerNetworkConnectLinkLocalIP(c *check.C) {
  1397  	// create one test network
  1398  	dockerCmd(c, "network", "create", "n0")
  1399  	assertNwIsAvailable(c, "n0")
  1400  
  1401  	// run a container with incorrect link-local address
  1402  	_, _, err := dockerCmdWithError("run", "--link-local-ip", "169.253.5.5", "busybox", "top")
  1403  	c.Assert(err, check.NotNil)
  1404  	_, _, err = dockerCmdWithError("run", "--link-local-ip", "2001:db8::89", "busybox", "top")
  1405  	c.Assert(err, check.NotNil)
  1406  
  1407  	// run two containers with link-local ip on the test network
  1408  	dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--link-local-ip", "169.254.7.7", "--link-local-ip", "fe80::254:77", "busybox", "top")
  1409  	c.Assert(waitRun("c0"), check.IsNil)
  1410  	dockerCmd(c, "run", "-d", "--name", "c1", "--net=n0", "--link-local-ip", "169.254.8.8", "--link-local-ip", "fe80::254:88", "busybox", "top")
  1411  	c.Assert(waitRun("c1"), check.IsNil)
  1412  
  1413  	// run a container on the default network and connect it to the test network specifying a link-local address
  1414  	dockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top")
  1415  	c.Assert(waitRun("c2"), check.IsNil)
  1416  	dockerCmd(c, "network", "connect", "--link-local-ip", "169.254.9.9", "n0", "c2")
  1417  
  1418  	// verify the three containers can ping each other via the link-local addresses
  1419  	_, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
  1420  	c.Assert(err, check.IsNil)
  1421  	_, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
  1422  	c.Assert(err, check.IsNil)
  1423  	_, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
  1424  	c.Assert(err, check.IsNil)
  1425  
  1426  	// Stop and restart the three containers
  1427  	dockerCmd(c, "stop", "c0")
  1428  	dockerCmd(c, "stop", "c1")
  1429  	dockerCmd(c, "stop", "c2")
  1430  	dockerCmd(c, "start", "c0")
  1431  	dockerCmd(c, "start", "c1")
  1432  	dockerCmd(c, "start", "c2")
  1433  
  1434  	// verify the ping again
  1435  	_, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
  1436  	c.Assert(err, check.IsNil)
  1437  	_, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
  1438  	c.Assert(err, check.IsNil)
  1439  	_, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
  1440  	c.Assert(err, check.IsNil)
  1441  }
  1442  
  1443  func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectLink(c *check.C) {
  1444  	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
  1445  	dockerCmd(c, "network", "create", "-d", "bridge", "foo1")
  1446  	dockerCmd(c, "network", "create", "-d", "bridge", "foo2")
  1447  
  1448  	dockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top")
  1449  	c.Assert(waitRun("first"), check.IsNil)
  1450  
  1451  	// run a container in a user-defined network with a link for an existing container
  1452  	// and a link for a container that doesn't exist
  1453  	dockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1",
  1454  		"--link=third:bar", "busybox", "top")
  1455  	c.Assert(waitRun("second"), check.IsNil)
  1456  
  1457  	// ping to first and its alias FirstInFoo1 must succeed
  1458  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1459  	c.Assert(err, check.IsNil)
  1460  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
  1461  	c.Assert(err, check.IsNil)
  1462  
  1463  	// connect first container to foo2 network
  1464  	dockerCmd(c, "network", "connect", "foo2", "first")
  1465  	// connect second container to foo2 network with a different alias for first container
  1466  	dockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second")
  1467  
  1468  	// ping the new alias in network foo2
  1469  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
  1470  	c.Assert(err, check.IsNil)
  1471  
  1472  	// disconnect first container from foo1 network
  1473  	dockerCmd(c, "network", "disconnect", "foo1", "first")
  1474  
  1475  	// link in foo1 network must fail
  1476  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
  1477  	c.Assert(err, check.NotNil)
  1478  
  1479  	// link in foo2 network must succeed
  1480  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
  1481  	c.Assert(err, check.IsNil)
  1482  }
  1483  
  1484  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *check.C) {
  1485  	netWorkName1 := "test1"
  1486  	netWorkName2 := "test2"
  1487  	containerName := "foo"
  1488  
  1489  	dockerCmd(c, "network", "create", netWorkName1)
  1490  	dockerCmd(c, "network", "create", netWorkName2)
  1491  	dockerCmd(c, "create", "--name", containerName, "busybox", "top")
  1492  	dockerCmd(c, "network", "connect", netWorkName1, containerName)
  1493  	dockerCmd(c, "network", "connect", netWorkName2, containerName)
  1494  	dockerCmd(c, "network", "disconnect", "bridge", containerName)
  1495  
  1496  	dockerCmd(c, "start", containerName)
  1497  	c.Assert(waitRun(containerName), checker.IsNil)
  1498  	networks := inspectField(c, containerName, "NetworkSettings.Networks")
  1499  	c.Assert(networks, checker.Contains, netWorkName1, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName1)))
  1500  	c.Assert(networks, checker.Contains, netWorkName2, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName2)))
  1501  	c.Assert(networks, checker.Not(checker.Contains), "bridge", check.Commentf("Should not contain 'bridge' network"))
  1502  }
  1503  
  1504  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithAliasOnDefaultNetworks(c *check.C) {
  1505  	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
  1506  
  1507  	defaults := []string{"bridge", "host", "none"}
  1508  	out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top")
  1509  	containerID := strings.TrimSpace(out)
  1510  	for _, net := range defaults {
  1511  		res, _, err := dockerCmdWithError("network", "connect", "--alias", "alias"+net, net, containerID)
  1512  		c.Assert(err, checker.NotNil)
  1513  		c.Assert(res, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
  1514  	}
  1515  }
  1516  
  1517  func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *check.C) {
  1518  	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
  1519  	dockerCmd(c, "network", "create", "-d", "bridge", "net1")
  1520  	dockerCmd(c, "network", "create", "-d", "bridge", "net2")
  1521  
  1522  	cid, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox", "top")
  1523  	c.Assert(waitRun("first"), check.IsNil)
  1524  
  1525  	dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top")
  1526  	c.Assert(waitRun("second"), check.IsNil)
  1527  
  1528  	// ping first container and its alias
  1529  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1530  	c.Assert(err, check.IsNil)
  1531  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
  1532  	c.Assert(err, check.IsNil)
  1533  
  1534  	// ping first container's short-id alias
  1535  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
  1536  	c.Assert(err, check.IsNil)
  1537  
  1538  	// connect first container to net2 network
  1539  	dockerCmd(c, "network", "connect", "--alias=bar", "net2", "first")
  1540  	// connect second container to foo2 network with a different alias for first container
  1541  	dockerCmd(c, "network", "connect", "net2", "second")
  1542  
  1543  	// ping the new alias in network foo2
  1544  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
  1545  	c.Assert(err, check.IsNil)
  1546  
  1547  	// disconnect first container from net1 network
  1548  	dockerCmd(c, "network", "disconnect", "net1", "first")
  1549  
  1550  	// ping to net1 scoped alias "foo" must fail
  1551  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
  1552  	c.Assert(err, check.NotNil)
  1553  
  1554  	// ping to net2 scoped alias "bar" must still succeed
  1555  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
  1556  	c.Assert(err, check.IsNil)
  1557  	// ping to net2 scoped alias short-id must still succeed
  1558  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
  1559  	c.Assert(err, check.IsNil)
  1560  
  1561  	// verify the alias option is rejected when running on predefined network
  1562  	out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox", "top")
  1563  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1564  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
  1565  
  1566  	// verify the alias option is rejected when connecting to predefined network
  1567  	out, _, err = dockerCmdWithError("network", "connect", "--alias=any", "bridge", "first")
  1568  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1569  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
  1570  }
  1571  
  1572  func (s *DockerSuite) TestUserDefinedNetworkConnectivity(c *check.C) {
  1573  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1574  	dockerCmd(c, "network", "create", "-d", "bridge", "br.net1")
  1575  
  1576  	dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox", "top")
  1577  	c.Assert(waitRun("c1.net1"), check.IsNil)
  1578  
  1579  	dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox", "top")
  1580  	c.Assert(waitRun("c2.net1"), check.IsNil)
  1581  
  1582  	// ping first container by its unqualified name
  1583  	_, _, err := dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1")
  1584  	c.Assert(err, check.IsNil)
  1585  
  1586  	// ping first container by its qualified name
  1587  	_, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1")
  1588  	c.Assert(err, check.IsNil)
  1589  
  1590  	// ping with first qualified name masked by an additional domain. should fail
  1591  	_, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1.google.com")
  1592  	c.Assert(err, check.NotNil)
  1593  }
  1594  
  1595  func (s *DockerSuite) TestEmbeddedDNSInvalidInput(c *check.C) {
  1596  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1597  	dockerCmd(c, "network", "create", "-d", "bridge", "nw1")
  1598  
  1599  	// Sending garbage to embedded DNS shouldn't crash the daemon
  1600  	dockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:jessie", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53")
  1601  }
  1602  
  1603  func (s *DockerSuite) TestDockerNetworkConnectFailsNoInspectChange(c *check.C) {
  1604  	dockerCmd(c, "run", "-d", "--name=bb", "busybox", "top")
  1605  	c.Assert(waitRun("bb"), check.IsNil)
  1606  
  1607  	ns0 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
  1608  
  1609  	// A failing redundant network connect should not alter current container's endpoint settings
  1610  	_, _, err := dockerCmdWithError("network", "connect", "bridge", "bb")
  1611  	c.Assert(err, check.NotNil)
  1612  
  1613  	ns1 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
  1614  	c.Assert(ns1, check.Equals, ns0)
  1615  }
  1616  
  1617  func (s *DockerSuite) TestDockerNetworkInternalMode(c *check.C) {
  1618  	dockerCmd(c, "network", "create", "--driver=bridge", "--internal", "internal")
  1619  	assertNwIsAvailable(c, "internal")
  1620  	nr := getNetworkResource(c, "internal")
  1621  	c.Assert(nr.Internal, checker.True)
  1622  
  1623  	dockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox", "top")
  1624  	c.Assert(waitRun("first"), check.IsNil)
  1625  	dockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox", "top")
  1626  	c.Assert(waitRun("second"), check.IsNil)
  1627  	out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "www.google.com")
  1628  	c.Assert(err, check.NotNil)
  1629  	c.Assert(out, checker.Contains, "ping: bad address")
  1630  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1631  	c.Assert(err, check.IsNil)
  1632  }
  1633  
  1634  // Test for #21401
  1635  func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *check.C) {
  1636  	dockerCmd(c, "network", "create", "test@#$")
  1637  	assertNwIsAvailable(c, "test@#$")
  1638  	dockerCmd(c, "network", "rm", "test@#$")
  1639  	assertNwNotAvailable(c, "test@#$")
  1640  
  1641  	dockerCmd(c, "network", "create", "kiwl$%^")
  1642  	assertNwIsAvailable(c, "kiwl$%^")
  1643  	dockerCmd(c, "network", "rm", "kiwl$%^")
  1644  	assertNwNotAvailable(c, "kiwl$%^")
  1645  }
  1646  
  1647  func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *check.C) {
  1648  	testRequires(t, DaemonIsLinux)
  1649  	if err := s.d.StartWithBusybox("--live-restore"); err != nil {
  1650  		t.Fatal(err)
  1651  	}
  1652  	defer s.d.Stop()
  1653  	oldCon := "old"
  1654  
  1655  	_, err := s.d.Cmd("run", "-d", "--name", oldCon, "-p", "80:80", "busybox", "top")
  1656  	if err != nil {
  1657  		t.Fatal(err)
  1658  	}
  1659  	oldContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", oldCon)
  1660  	if err != nil {
  1661  		t.Fatal(err)
  1662  	}
  1663  	// Kill the daemon
  1664  	if err := s.d.Kill(); err != nil {
  1665  		t.Fatal(err)
  1666  	}
  1667  
  1668  	// restart the daemon
  1669  	if err := s.d.Start("--live-restore"); err != nil {
  1670  		t.Fatal(err)
  1671  	}
  1672  
  1673  	// start a new container, the new container's ip should not be the same with
  1674  	// old running container.
  1675  	newCon := "new"
  1676  	_, err = s.d.Cmd("run", "-d", "--name", newCon, "busybox", "top")
  1677  	if err != nil {
  1678  		t.Fatal(err)
  1679  	}
  1680  	newContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", newCon)
  1681  	if err != nil {
  1682  		t.Fatal(err)
  1683  	}
  1684  	if strings.Compare(strings.TrimSpace(oldContainerIP), strings.TrimSpace(newContainerIP)) == 0 {
  1685  		t.Fatalf("new container ip should not equal to old running container  ip")
  1686  	}
  1687  
  1688  	// start a new container, the new container should ping old running container
  1689  	_, err = s.d.Cmd("run", "-t", "busybox", "ping", "-c", "1", oldContainerIP)
  1690  	if err != nil {
  1691  		t.Fatal(err)
  1692  	}
  1693  
  1694  	// start a new container, trying to publish port 80:80 should fail
  1695  	out, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
  1696  	if err == nil || !strings.Contains(out, "Bind for 0.0.0.0:80 failed: port is already allocated") {
  1697  		t.Fatalf("80 port is allocated to old running container, it should failed on allocating to new container")
  1698  	}
  1699  
  1700  	// kill old running container and try to allocate again
  1701  	_, err = s.d.Cmd("kill", oldCon)
  1702  	if err != nil {
  1703  		t.Fatal(err)
  1704  	}
  1705  	id, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
  1706  	if err != nil {
  1707  		t.Fatal(err)
  1708  	}
  1709  
  1710  	// Cleanup because these containers will not be shut down by daemon
  1711  	out, err = s.d.Cmd("stop", newCon)
  1712  	if err != nil {
  1713  		t.Fatalf("err: %v %v", err, string(out))
  1714  	}
  1715  	_, err = s.d.Cmd("stop", strings.TrimSpace(id))
  1716  	if err != nil {
  1717  		t.Fatal(err)
  1718  	}
  1719  }
  1720  
  1721  func (s *DockerNetworkSuite) TestDockerNetworkFlagAlias(c *check.C) {
  1722  	dockerCmd(c, "network", "create", "user")
  1723  	output, status := dockerCmd(c, "run", "--rm", "--network=user", "--network-alias=foo", "busybox", "true")
  1724  	c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output))
  1725  
  1726  	output, status, _ = dockerCmdWithError("run", "--rm", "--net=user", "--network=user", "busybox", "true")
  1727  	c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output))
  1728  
  1729  	output, status, _ = dockerCmdWithError("run", "--rm", "--network=user", "--net-alias=foo", "--network-alias=bar", "busybox", "true")
  1730  	c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output))
  1731  }
  1732  
  1733  func (s *DockerNetworkSuite) TestDockerNetworkValidateIP(c *check.C) {
  1734  	_, _, err := dockerCmdWithError("network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "mynet")
  1735  	c.Assert(err, check.IsNil)
  1736  	assertNwIsAvailable(c, "mynet")
  1737  
  1738  	_, _, err = dockerCmdWithError("run", "-d", "--name", "mynet0", "--net=mynet", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1739  	c.Assert(err, check.IsNil)
  1740  	c.Assert(waitRun("mynet0"), check.IsNil)
  1741  	verifyIPAddressConfig(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
  1742  	verifyIPAddresses(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
  1743  
  1744  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "mynet_ip", "--ip6", "2001:db8:1234::9999", "busybox", "top")
  1745  	c.Assert(err.Error(), checker.Contains, "invalid IPv4 address")
  1746  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "172.28.99.99", "--ip6", "mynet_ip6", "busybox", "top")
  1747  	c.Assert(err.Error(), checker.Contains, "invalid IPv6 address")
  1748  	// This is a case of IPv4 address to `--ip6`
  1749  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "172.28.99.99", "busybox", "top")
  1750  	c.Assert(err.Error(), checker.Contains, "invalid IPv6 address")
  1751  	// This is a special case of an IPv4-mapped IPv6 address
  1752  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "::ffff:172.28.99.99", "busybox", "top")
  1753  	c.Assert(err.Error(), checker.Contains, "invalid IPv6 address")
  1754  }
  1755  
  1756  // Test case for 26220
  1757  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *check.C) {
  1758  	out, _ := dockerCmd(c, "network", "inspect", "--format", "{{.Id}}", "bridge")
  1759  
  1760  	network := strings.TrimSpace(out)
  1761  
  1762  	name := "test"
  1763  	dockerCmd(c, "create", "--name", name, "busybox", "top")
  1764  
  1765  	_, _, err := dockerCmdWithError("network", "disconnect", network, name)
  1766  	c.Assert(err, check.IsNil)
  1767  }