github.com/samwhited/moby@v1.13.1/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=fd80:24e2:f998:72d6::/64", "--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, 2)
   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 *DockerNetworkSuite) TestDockerPluginV2NetworkDriver(c *check.C) {
   772  	testRequires(c, DaemonIsLinux, IsAmd64, Network)
   773  
   774  	var (
   775  		npName        = "tiborvass/test-docker-netplugin"
   776  		npTag         = "latest"
   777  		npNameWithTag = npName + ":" + npTag
   778  	)
   779  	_, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", npNameWithTag)
   780  	c.Assert(err, checker.IsNil)
   781  
   782  	out, _, err := dockerCmdWithError("plugin", "ls")
   783  	c.Assert(err, checker.IsNil)
   784  	c.Assert(out, checker.Contains, npName)
   785  	c.Assert(out, checker.Contains, npTag)
   786  	c.Assert(out, checker.Contains, "true")
   787  
   788  	dockerCmd(c, "network", "create", "-d", npNameWithTag, "v2net")
   789  	assertNwIsAvailable(c, "v2net")
   790  	dockerCmd(c, "network", "rm", "v2net")
   791  	assertNwNotAvailable(c, "v2net")
   792  
   793  }
   794  
   795  func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *check.C) {
   796  	testRequires(c, ExecSupport)
   797  	// On default bridge network built-in service discovery should not happen
   798  	hostsFile := "/etc/hosts"
   799  	bridgeName := "external-bridge"
   800  	bridgeIP := "192.169.255.254/24"
   801  	out, err := createInterface(c, "bridge", bridgeName, bridgeIP)
   802  	c.Assert(err, check.IsNil, check.Commentf(out))
   803  	defer deleteInterface(c, bridgeName)
   804  
   805  	err = s.d.StartWithBusybox("--bridge", bridgeName)
   806  	c.Assert(err, check.IsNil)
   807  	defer s.d.Restart()
   808  
   809  	// run two containers and store first container's etc/hosts content
   810  	out, err = s.d.Cmd("run", "-d", "busybox", "top")
   811  	c.Assert(err, check.IsNil)
   812  	cid1 := strings.TrimSpace(out)
   813  	defer s.d.Cmd("stop", cid1)
   814  
   815  	hosts, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
   816  	c.Assert(err, checker.IsNil)
   817  
   818  	out, err = s.d.Cmd("run", "-d", "--name", "container2", "busybox", "top")
   819  	c.Assert(err, check.IsNil)
   820  	cid2 := strings.TrimSpace(out)
   821  
   822  	// verify first container's etc/hosts file has not changed after spawning the second named container
   823  	hostsPost, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
   824  	c.Assert(err, checker.IsNil)
   825  	c.Assert(string(hosts), checker.Equals, string(hostsPost),
   826  		check.Commentf("Unexpected %s change on second container creation", hostsFile))
   827  
   828  	// stop container 2 and verify first container's etc/hosts has not changed
   829  	_, err = s.d.Cmd("stop", cid2)
   830  	c.Assert(err, check.IsNil)
   831  
   832  	hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
   833  	c.Assert(err, checker.IsNil)
   834  	c.Assert(string(hosts), checker.Equals, string(hostsPost),
   835  		check.Commentf("Unexpected %s change on second container creation", hostsFile))
   836  
   837  	// but discovery is on when connecting to non default bridge network
   838  	network := "anotherbridge"
   839  	out, err = s.d.Cmd("network", "create", network)
   840  	c.Assert(err, check.IsNil, check.Commentf(out))
   841  	defer s.d.Cmd("network", "rm", network)
   842  
   843  	out, err = s.d.Cmd("network", "connect", network, cid1)
   844  	c.Assert(err, check.IsNil, check.Commentf(out))
   845  
   846  	hosts, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
   847  	c.Assert(err, checker.IsNil)
   848  
   849  	hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
   850  	c.Assert(err, checker.IsNil)
   851  	c.Assert(string(hosts), checker.Equals, string(hostsPost),
   852  		check.Commentf("Unexpected %s change on second network connection", hostsFile))
   853  }
   854  
   855  func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *check.C) {
   856  	testRequires(c, ExecSupport, NotArm)
   857  	hostsFile := "/etc/hosts"
   858  	cstmBridgeNw := "custom-bridge-nw"
   859  	cstmBridgeNw1 := "custom-bridge-nw1"
   860  
   861  	dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw)
   862  	assertNwIsAvailable(c, cstmBridgeNw)
   863  
   864  	// run two anonymous containers and store their etc/hosts content
   865  	out, _ := dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top")
   866  	cid1 := strings.TrimSpace(out)
   867  
   868  	hosts1, err := readContainerFileWithExec(cid1, hostsFile)
   869  	c.Assert(err, checker.IsNil)
   870  
   871  	out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top")
   872  	cid2 := strings.TrimSpace(out)
   873  
   874  	hosts2, err := readContainerFileWithExec(cid2, hostsFile)
   875  	c.Assert(err, checker.IsNil)
   876  
   877  	// verify first container etc/hosts file has not changed
   878  	hosts1post, err := readContainerFileWithExec(cid1, hostsFile)
   879  	c.Assert(err, checker.IsNil)
   880  	c.Assert(string(hosts1), checker.Equals, string(hosts1post),
   881  		check.Commentf("Unexpected %s change on anonymous container creation", hostsFile))
   882  
   883  	// Connect the 2nd container to a new network and verify the
   884  	// first container /etc/hosts file still hasn't changed.
   885  	dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw1)
   886  	assertNwIsAvailable(c, cstmBridgeNw1)
   887  
   888  	dockerCmd(c, "network", "connect", cstmBridgeNw1, cid2)
   889  
   890  	hosts2, err = readContainerFileWithExec(cid2, hostsFile)
   891  	c.Assert(err, checker.IsNil)
   892  
   893  	hosts1post, err = readContainerFileWithExec(cid1, hostsFile)
   894  	c.Assert(err, checker.IsNil)
   895  	c.Assert(string(hosts1), checker.Equals, string(hosts1post),
   896  		check.Commentf("Unexpected %s change on container connect", hostsFile))
   897  
   898  	// start a named container
   899  	cName := "AnyName"
   900  	out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top")
   901  	cid3 := strings.TrimSpace(out)
   902  
   903  	// verify that container 1 and 2 can ping the named container
   904  	dockerCmd(c, "exec", cid1, "ping", "-c", "1", cName)
   905  	dockerCmd(c, "exec", cid2, "ping", "-c", "1", cName)
   906  
   907  	// Stop named container and verify first two containers' etc/hosts file hasn't changed
   908  	dockerCmd(c, "stop", cid3)
   909  	hosts1post, err = readContainerFileWithExec(cid1, hostsFile)
   910  	c.Assert(err, checker.IsNil)
   911  	c.Assert(string(hosts1), checker.Equals, string(hosts1post),
   912  		check.Commentf("Unexpected %s change on name container creation", hostsFile))
   913  
   914  	hosts2post, err := readContainerFileWithExec(cid2, hostsFile)
   915  	c.Assert(err, checker.IsNil)
   916  	c.Assert(string(hosts2), checker.Equals, string(hosts2post),
   917  		check.Commentf("Unexpected %s change on name container creation", hostsFile))
   918  
   919  	// verify that container 1 and 2 can't ping the named container now
   920  	_, _, err = dockerCmdWithError("exec", cid1, "ping", "-c", "1", cName)
   921  	c.Assert(err, check.NotNil)
   922  	_, _, err = dockerCmdWithError("exec", cid2, "ping", "-c", "1", cName)
   923  	c.Assert(err, check.NotNil)
   924  }
   925  
   926  func (s *DockerNetworkSuite) TestDockerNetworkLinkOnDefaultNetworkOnly(c *check.C) {
   927  	// Legacy Link feature must work only on default network, and not across networks
   928  	cnt1 := "container1"
   929  	cnt2 := "container2"
   930  	network := "anotherbridge"
   931  
   932  	// Run first container on default network
   933  	dockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top")
   934  
   935  	// Create another network and run the second container on it
   936  	dockerCmd(c, "network", "create", network)
   937  	assertNwIsAvailable(c, network)
   938  	dockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top")
   939  
   940  	// Try launching a container on default network, linking to the first container. Must succeed
   941  	dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top")
   942  
   943  	// Try launching a container on default network, linking to the second container. Must fail
   944  	_, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
   945  	c.Assert(err, checker.NotNil)
   946  
   947  	// Connect second container to default network. Now a container on default network can link to it
   948  	dockerCmd(c, "network", "connect", "bridge", cnt2)
   949  	dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
   950  }
   951  
   952  func (s *DockerNetworkSuite) TestDockerNetworkOverlayPortMapping(c *check.C) {
   953  	// Verify exposed ports are present in ps output when running a container on
   954  	// a network managed by a driver which does not provide the default gateway
   955  	// for the container
   956  	nwn := "ov"
   957  	ctn := "bb"
   958  	port1 := 80
   959  	port2 := 443
   960  	expose1 := fmt.Sprintf("--expose=%d", port1)
   961  	expose2 := fmt.Sprintf("--expose=%d", port2)
   962  
   963  	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn)
   964  	assertNwIsAvailable(c, nwn)
   965  
   966  	dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, expose1, expose2, "busybox", "top")
   967  
   968  	// Check docker ps o/p for last created container reports the unpublished ports
   969  	unpPort1 := fmt.Sprintf("%d/tcp", port1)
   970  	unpPort2 := fmt.Sprintf("%d/tcp", port2)
   971  	out, _ := dockerCmd(c, "ps", "-n=1")
   972  	// Missing unpublished ports in docker ps output
   973  	c.Assert(out, checker.Contains, unpPort1)
   974  	// Missing unpublished ports in docker ps output
   975  	c.Assert(out, checker.Contains, unpPort2)
   976  }
   977  
   978  func (s *DockerNetworkSuite) TestDockerNetworkDriverUngracefulRestart(c *check.C) {
   979  	testRequires(c, DaemonIsLinux, NotUserNamespace)
   980  	dnd := "dnd"
   981  	did := "did"
   982  
   983  	mux := http.NewServeMux()
   984  	server := httptest.NewServer(mux)
   985  	setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did)
   986  
   987  	s.d.StartWithBusybox()
   988  	_, err := s.d.Cmd("network", "create", "-d", dnd, "--subnet", "1.1.1.0/24", "net1")
   989  	c.Assert(err, checker.IsNil)
   990  
   991  	_, err = s.d.Cmd("run", "-itd", "--net", "net1", "--name", "foo", "--ip", "1.1.1.10", "busybox", "sh")
   992  	c.Assert(err, checker.IsNil)
   993  
   994  	// Kill daemon and restart
   995  	if err = s.d.cmd.Process.Kill(); err != nil {
   996  		c.Fatal(err)
   997  	}
   998  
   999  	server.Close()
  1000  
  1001  	startTime := time.Now().Unix()
  1002  	if err = s.d.Restart(); err != nil {
  1003  		c.Fatal(err)
  1004  	}
  1005  	lapse := time.Now().Unix() - startTime
  1006  	if lapse > 60 {
  1007  		// In normal scenarios, daemon restart takes ~1 second.
  1008  		// Plugin retry mechanism can delay the daemon start. systemd may not like it.
  1009  		// Avoid accessing plugins during daemon bootup
  1010  		c.Logf("daemon restart took too long : %d seconds", lapse)
  1011  	}
  1012  
  1013  	// Restart the custom dummy plugin
  1014  	mux = http.NewServeMux()
  1015  	server = httptest.NewServer(mux)
  1016  	setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did)
  1017  
  1018  	// trying to reuse the same ip must succeed
  1019  	_, err = s.d.Cmd("run", "-itd", "--net", "net1", "--name", "bar", "--ip", "1.1.1.10", "busybox", "sh")
  1020  	c.Assert(err, checker.IsNil)
  1021  }
  1022  
  1023  func (s *DockerNetworkSuite) TestDockerNetworkMacInspect(c *check.C) {
  1024  	// Verify endpoint MAC address is correctly populated in container's network settings
  1025  	nwn := "ov"
  1026  	ctn := "bb"
  1027  
  1028  	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn)
  1029  	assertNwIsAvailable(c, nwn)
  1030  
  1031  	dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, "busybox", "top")
  1032  
  1033  	mac := inspectField(c, ctn, "NetworkSettings.Networks."+nwn+".MacAddress")
  1034  	c.Assert(mac, checker.Equals, "a0:b1:c2:d3:e4:f5")
  1035  }
  1036  
  1037  func (s *DockerSuite) TestInspectAPIMultipleNetworks(c *check.C) {
  1038  	dockerCmd(c, "network", "create", "mybridge1")
  1039  	dockerCmd(c, "network", "create", "mybridge2")
  1040  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  1041  	id := strings.TrimSpace(out)
  1042  	c.Assert(waitRun(id), check.IsNil)
  1043  
  1044  	dockerCmd(c, "network", "connect", "mybridge1", id)
  1045  	dockerCmd(c, "network", "connect", "mybridge2", id)
  1046  
  1047  	body := getInspectBody(c, "v1.20", id)
  1048  	var inspect120 v1p20.ContainerJSON
  1049  	err := json.Unmarshal(body, &inspect120)
  1050  	c.Assert(err, checker.IsNil)
  1051  
  1052  	versionedIP := inspect120.NetworkSettings.IPAddress
  1053  
  1054  	body = getInspectBody(c, "v1.21", id)
  1055  	var inspect121 types.ContainerJSON
  1056  	err = json.Unmarshal(body, &inspect121)
  1057  	c.Assert(err, checker.IsNil)
  1058  	c.Assert(inspect121.NetworkSettings.Networks, checker.HasLen, 3)
  1059  
  1060  	bridge := inspect121.NetworkSettings.Networks["bridge"]
  1061  	c.Assert(bridge.IPAddress, checker.Equals, versionedIP)
  1062  	c.Assert(bridge.IPAddress, checker.Equals, inspect121.NetworkSettings.IPAddress)
  1063  }
  1064  
  1065  func connectContainerToNetworks(c *check.C, d *Daemon, cName string, nws []string) {
  1066  	// Run a container on the default network
  1067  	out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top")
  1068  	c.Assert(err, checker.IsNil, check.Commentf(out))
  1069  
  1070  	// Attach the container to other networks
  1071  	for _, nw := range nws {
  1072  		out, err = d.Cmd("network", "create", nw)
  1073  		c.Assert(err, checker.IsNil, check.Commentf(out))
  1074  		out, err = d.Cmd("network", "connect", nw, cName)
  1075  		c.Assert(err, checker.IsNil, check.Commentf(out))
  1076  	}
  1077  }
  1078  
  1079  func verifyContainerIsConnectedToNetworks(c *check.C, d *Daemon, cName string, nws []string) {
  1080  	// Verify container is connected to all the networks
  1081  	for _, nw := range nws {
  1082  		out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName)
  1083  		c.Assert(err, checker.IsNil, check.Commentf(out))
  1084  		c.Assert(out, checker.Not(checker.Equals), "<no value>\n")
  1085  	}
  1086  }
  1087  
  1088  func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *check.C) {
  1089  	cName := "bb"
  1090  	nwList := []string{"nw1", "nw2", "nw3"}
  1091  
  1092  	s.d.StartWithBusybox()
  1093  
  1094  	connectContainerToNetworks(c, s.d, cName, nwList)
  1095  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1096  
  1097  	// Reload daemon
  1098  	s.d.Restart()
  1099  
  1100  	_, err := s.d.Cmd("start", cName)
  1101  	c.Assert(err, checker.IsNil)
  1102  
  1103  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1104  }
  1105  
  1106  func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRestart(c *check.C) {
  1107  	cName := "cc"
  1108  	nwList := []string{"nw1", "nw2", "nw3"}
  1109  
  1110  	s.d.StartWithBusybox()
  1111  
  1112  	connectContainerToNetworks(c, s.d, cName, nwList)
  1113  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1114  
  1115  	// Kill daemon and restart
  1116  	if err := s.d.cmd.Process.Kill(); err != nil {
  1117  		c.Fatal(err)
  1118  	}
  1119  	s.d.Restart()
  1120  
  1121  	// Restart container
  1122  	_, err := s.d.Cmd("start", cName)
  1123  	c.Assert(err, checker.IsNil)
  1124  
  1125  	verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  1126  }
  1127  
  1128  func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *check.C) {
  1129  	out, _ := dockerCmd(c, "network", "create", "one")
  1130  	containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top")
  1131  	c.Assert(err, checker.IsNil, check.Commentf(containerOut))
  1132  }
  1133  
  1134  func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *check.C) {
  1135  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1136  	s.d.StartWithBusybox()
  1137  
  1138  	// Run a few containers on host network
  1139  	for i := 0; i < 10; i++ {
  1140  		cName := fmt.Sprintf("hostc-%d", i)
  1141  		out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top")
  1142  		c.Assert(err, checker.IsNil, check.Commentf(out))
  1143  
  1144  		// verfiy container has finished starting before killing daemon
  1145  		err = s.d.waitRun(cName)
  1146  		c.Assert(err, checker.IsNil)
  1147  	}
  1148  
  1149  	// Kill daemon ungracefully and restart
  1150  	if err := s.d.cmd.Process.Kill(); err != nil {
  1151  		c.Fatal(err)
  1152  	}
  1153  	if err := s.d.Restart(); err != nil {
  1154  		c.Fatal(err)
  1155  	}
  1156  
  1157  	// make sure all the containers are up and running
  1158  	for i := 0; i < 10; i++ {
  1159  		err := s.d.waitRun(fmt.Sprintf("hostc-%d", i))
  1160  		c.Assert(err, checker.IsNil)
  1161  	}
  1162  }
  1163  
  1164  func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *check.C) {
  1165  	dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
  1166  	c.Assert(waitRun("container1"), check.IsNil)
  1167  	dockerCmd(c, "network", "disconnect", "bridge", "container1")
  1168  	out, _, err := dockerCmdWithError("network", "connect", "host", "container1")
  1169  	c.Assert(err, checker.NotNil, check.Commentf(out))
  1170  	c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error())
  1171  }
  1172  
  1173  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *check.C) {
  1174  	dockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top")
  1175  	c.Assert(waitRun("container1"), check.IsNil)
  1176  	out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1")
  1177  	c.Assert(err, checker.NotNil, check.Commentf("Should err out disconnect from host"))
  1178  	c.Assert(out, checker.Contains, runconfig.ErrConflictHostNetwork.Error())
  1179  }
  1180  
  1181  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *check.C) {
  1182  	testRequires(c, NotArm)
  1183  	dockerCmd(c, "network", "create", "test1")
  1184  	dockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top")
  1185  	c.Assert(waitRun("c1"), check.IsNil)
  1186  	dockerCmd(c, "network", "connect", "test1", "c1")
  1187  }
  1188  
  1189  func verifyPortMap(c *check.C, container, port, originalMapping string, mustBeEqual bool) {
  1190  	chk := checker.Equals
  1191  	if !mustBeEqual {
  1192  		chk = checker.Not(checker.Equals)
  1193  	}
  1194  	currentMapping, _ := dockerCmd(c, "port", container, port)
  1195  	c.Assert(currentMapping, chk, originalMapping)
  1196  }
  1197  
  1198  func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectWithPortMapping(c *check.C) {
  1199  	// Connect and disconnect a container with explicit and non-explicit
  1200  	// host port mapping to/from networks which do cause and do not cause
  1201  	// the container default gateway to change, and verify docker port cmd
  1202  	// returns congruent information
  1203  	testRequires(c, NotArm)
  1204  	cnt := "c1"
  1205  	dockerCmd(c, "network", "create", "aaa")
  1206  	dockerCmd(c, "network", "create", "ccc")
  1207  
  1208  	dockerCmd(c, "run", "-d", "--name", cnt, "-p", "9000:90", "-p", "70", "busybox", "top")
  1209  	c.Assert(waitRun(cnt), check.IsNil)
  1210  	curPortMap, _ := dockerCmd(c, "port", cnt, "70")
  1211  	curExplPortMap, _ := dockerCmd(c, "port", cnt, "90")
  1212  
  1213  	// Connect to a network which causes the container's default gw switch
  1214  	dockerCmd(c, "network", "connect", "aaa", cnt)
  1215  	verifyPortMap(c, cnt, "70", curPortMap, false)
  1216  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1217  
  1218  	// Read current mapping
  1219  	curPortMap, _ = dockerCmd(c, "port", cnt, "70")
  1220  
  1221  	// Disconnect from a network which causes the container's default gw switch
  1222  	dockerCmd(c, "network", "disconnect", "aaa", cnt)
  1223  	verifyPortMap(c, cnt, "70", curPortMap, false)
  1224  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1225  
  1226  	// Read current mapping
  1227  	curPortMap, _ = dockerCmd(c, "port", cnt, "70")
  1228  
  1229  	// Connect to a network which does not cause the container's default gw switch
  1230  	dockerCmd(c, "network", "connect", "ccc", cnt)
  1231  	verifyPortMap(c, cnt, "70", curPortMap, true)
  1232  	verifyPortMap(c, cnt, "90", curExplPortMap, true)
  1233  }
  1234  
  1235  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *check.C) {
  1236  	macAddress := "02:42:ac:11:00:02"
  1237  	dockerCmd(c, "network", "create", "mynetwork")
  1238  	dockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top")
  1239  	c.Assert(waitRun("test"), check.IsNil)
  1240  	mac1 := inspectField(c, "test", "NetworkSettings.Networks.bridge.MacAddress")
  1241  	c.Assert(strings.TrimSpace(mac1), checker.Equals, macAddress)
  1242  	dockerCmd(c, "network", "connect", "mynetwork", "test")
  1243  	mac2 := inspectField(c, "test", "NetworkSettings.Networks.mynetwork.MacAddress")
  1244  	c.Assert(strings.TrimSpace(mac2), checker.Not(checker.Equals), strings.TrimSpace(mac1))
  1245  }
  1246  
  1247  func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *check.C) {
  1248  	dockerCmd(c, "create", "--name", "test", "busybox")
  1249  	networks := inspectField(c, "test", "NetworkSettings.Networks")
  1250  	c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should return 'bridge' network"))
  1251  }
  1252  
  1253  func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMultipleNetworks(c *check.C) {
  1254  	dockerCmd(c, "network", "create", "test")
  1255  	dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top")
  1256  	c.Assert(waitRun("foo"), checker.IsNil)
  1257  	dockerCmd(c, "network", "connect", "test", "foo")
  1258  	dockerCmd(c, "restart", "foo")
  1259  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1260  	c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should contain 'bridge' network"))
  1261  	c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
  1262  }
  1263  
  1264  func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *check.C) {
  1265  	dockerCmd(c, "network", "create", "test")
  1266  	dockerCmd(c, "create", "--name=foo", "busybox", "top")
  1267  	dockerCmd(c, "network", "connect", "test", "foo")
  1268  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1269  	c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
  1270  
  1271  	// Restart docker daemon to test the config has persisted to disk
  1272  	s.d.Restart()
  1273  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1274  	c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
  1275  
  1276  	// start the container and test if we can ping it from another container in the same network
  1277  	dockerCmd(c, "start", "foo")
  1278  	c.Assert(waitRun("foo"), checker.IsNil)
  1279  	ip := inspectField(c, "foo", "NetworkSettings.Networks.test.IPAddress")
  1280  	ip = strings.TrimSpace(ip)
  1281  	dockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip))
  1282  
  1283  	dockerCmd(c, "stop", "foo")
  1284  
  1285  	// Test disconnect
  1286  	dockerCmd(c, "network", "disconnect", "test", "foo")
  1287  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1288  	c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
  1289  
  1290  	// Restart docker daemon to test the config has persisted to disk
  1291  	s.d.Restart()
  1292  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1293  	c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
  1294  
  1295  }
  1296  
  1297  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *check.C) {
  1298  	dockerCmd(c, "network", "create", "test")
  1299  	dockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top")
  1300  	networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1301  	c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
  1302  
  1303  	// Stop container and remove network
  1304  	dockerCmd(c, "stop", "foo")
  1305  	dockerCmd(c, "network", "rm", "test")
  1306  
  1307  	// Test disconnecting stopped container from nonexisting network
  1308  	dockerCmd(c, "network", "disconnect", "-f", "test", "foo")
  1309  	networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1310  	c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
  1311  }
  1312  
  1313  func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) {
  1314  	// create two networks
  1315  	dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")
  1316  	assertNwIsAvailable(c, "n0")
  1317  
  1318  	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")
  1319  	assertNwIsAvailable(c, "n1")
  1320  
  1321  	// run a container on first network specifying the ip addresses
  1322  	dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1323  	c.Assert(waitRun("c0"), check.IsNil)
  1324  	verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1325  	verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1326  
  1327  	// connect the container to the second network specifying an ip addresses
  1328  	dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0")
  1329  	verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1330  	verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1331  
  1332  	// Stop and restart the container
  1333  	dockerCmd(c, "stop", "c0")
  1334  	dockerCmd(c, "start", "c0")
  1335  
  1336  	// verify requested addresses are applied and configs are still there
  1337  	verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1338  	verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1339  	verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1340  	verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1341  
  1342  	// Still it should fail to connect to the default network with a specified IP (whatever ip)
  1343  	out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0")
  1344  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1345  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error())
  1346  
  1347  }
  1348  
  1349  func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIPStoppedContainer(c *check.C) {
  1350  	// create a container
  1351  	dockerCmd(c, "create", "--name", "c0", "busybox", "top")
  1352  
  1353  	// create a network
  1354  	dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0")
  1355  	assertNwIsAvailable(c, "n0")
  1356  
  1357  	// connect the container to the network specifying an ip addresses
  1358  	dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n0", "c0")
  1359  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1360  
  1361  	// start the container, verify config has not changed and ip addresses are assigned
  1362  	dockerCmd(c, "start", "c0")
  1363  	c.Assert(waitRun("c0"), check.IsNil)
  1364  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1365  	verifyIPAddresses(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1366  
  1367  	// stop the container and check ip config has not changed
  1368  	dockerCmd(c, "stop", "c0")
  1369  	verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1370  }
  1371  
  1372  func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedRequiredIP(c *check.C) {
  1373  	// requested IP is not supported on predefined networks
  1374  	for _, mode := range []string{"none", "host", "bridge", "default"} {
  1375  		checkUnsupportedNetworkAndIP(c, mode)
  1376  	}
  1377  
  1378  	// requested IP is not supported on networks with no user defined subnets
  1379  	dockerCmd(c, "network", "create", "n0")
  1380  	assertNwIsAvailable(c, "n0")
  1381  
  1382  	out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top")
  1383  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1384  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error())
  1385  
  1386  	out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--net", "n0", "busybox", "top")
  1387  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1388  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error())
  1389  
  1390  	dockerCmd(c, "network", "rm", "n0")
  1391  	assertNwNotAvailable(c, "n0")
  1392  }
  1393  
  1394  func checkUnsupportedNetworkAndIP(c *check.C, nwMode string) {
  1395  	out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1396  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1397  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndIP.Error())
  1398  }
  1399  
  1400  func verifyIPAddressConfig(c *check.C, cName, nwname, ipv4, ipv6 string) {
  1401  	if ipv4 != "" {
  1402  		out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv4Address", nwname))
  1403  		c.Assert(strings.TrimSpace(out), check.Equals, ipv4)
  1404  	}
  1405  
  1406  	if ipv6 != "" {
  1407  		out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv6Address", nwname))
  1408  		c.Assert(strings.TrimSpace(out), check.Equals, ipv6)
  1409  	}
  1410  }
  1411  
  1412  func verifyIPAddresses(c *check.C, cName, nwname, ipv4, ipv6 string) {
  1413  	out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAddress", nwname))
  1414  	c.Assert(strings.TrimSpace(out), check.Equals, ipv4)
  1415  
  1416  	out = inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.GlobalIPv6Address", nwname))
  1417  	c.Assert(strings.TrimSpace(out), check.Equals, ipv6)
  1418  }
  1419  
  1420  func (s *DockerNetworkSuite) TestDockerNetworkConnectLinkLocalIP(c *check.C) {
  1421  	// create one test network
  1422  	dockerCmd(c, "network", "create", "n0")
  1423  	assertNwIsAvailable(c, "n0")
  1424  
  1425  	// run a container with incorrect link-local address
  1426  	_, _, err := dockerCmdWithError("run", "--link-local-ip", "169.253.5.5", "busybox", "top")
  1427  	c.Assert(err, check.NotNil)
  1428  	_, _, err = dockerCmdWithError("run", "--link-local-ip", "2001:db8::89", "busybox", "top")
  1429  	c.Assert(err, check.NotNil)
  1430  
  1431  	// run two containers with link-local ip on the test network
  1432  	dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--link-local-ip", "169.254.7.7", "--link-local-ip", "fe80::254:77", "busybox", "top")
  1433  	c.Assert(waitRun("c0"), check.IsNil)
  1434  	dockerCmd(c, "run", "-d", "--name", "c1", "--net=n0", "--link-local-ip", "169.254.8.8", "--link-local-ip", "fe80::254:88", "busybox", "top")
  1435  	c.Assert(waitRun("c1"), check.IsNil)
  1436  
  1437  	// run a container on the default network and connect it to the test network specifying a link-local address
  1438  	dockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top")
  1439  	c.Assert(waitRun("c2"), check.IsNil)
  1440  	dockerCmd(c, "network", "connect", "--link-local-ip", "169.254.9.9", "n0", "c2")
  1441  
  1442  	// verify the three containers can ping each other via the link-local addresses
  1443  	_, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
  1444  	c.Assert(err, check.IsNil)
  1445  	_, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
  1446  	c.Assert(err, check.IsNil)
  1447  	_, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
  1448  	c.Assert(err, check.IsNil)
  1449  
  1450  	// Stop and restart the three containers
  1451  	dockerCmd(c, "stop", "c0")
  1452  	dockerCmd(c, "stop", "c1")
  1453  	dockerCmd(c, "stop", "c2")
  1454  	dockerCmd(c, "start", "c0")
  1455  	dockerCmd(c, "start", "c1")
  1456  	dockerCmd(c, "start", "c2")
  1457  
  1458  	// verify the ping again
  1459  	_, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
  1460  	c.Assert(err, check.IsNil)
  1461  	_, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
  1462  	c.Assert(err, check.IsNil)
  1463  	_, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
  1464  	c.Assert(err, check.IsNil)
  1465  }
  1466  
  1467  func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectLink(c *check.C) {
  1468  	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
  1469  	dockerCmd(c, "network", "create", "-d", "bridge", "foo1")
  1470  	dockerCmd(c, "network", "create", "-d", "bridge", "foo2")
  1471  
  1472  	dockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top")
  1473  	c.Assert(waitRun("first"), check.IsNil)
  1474  
  1475  	// run a container in a user-defined network with a link for an existing container
  1476  	// and a link for a container that doesn't exist
  1477  	dockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1",
  1478  		"--link=third:bar", "busybox", "top")
  1479  	c.Assert(waitRun("second"), check.IsNil)
  1480  
  1481  	// ping to first and its alias FirstInFoo1 must succeed
  1482  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1483  	c.Assert(err, check.IsNil)
  1484  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
  1485  	c.Assert(err, check.IsNil)
  1486  
  1487  	// connect first container to foo2 network
  1488  	dockerCmd(c, "network", "connect", "foo2", "first")
  1489  	// connect second container to foo2 network with a different alias for first container
  1490  	dockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second")
  1491  
  1492  	// ping the new alias in network foo2
  1493  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
  1494  	c.Assert(err, check.IsNil)
  1495  
  1496  	// disconnect first container from foo1 network
  1497  	dockerCmd(c, "network", "disconnect", "foo1", "first")
  1498  
  1499  	// link in foo1 network must fail
  1500  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
  1501  	c.Assert(err, check.NotNil)
  1502  
  1503  	// link in foo2 network must succeed
  1504  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
  1505  	c.Assert(err, check.IsNil)
  1506  }
  1507  
  1508  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *check.C) {
  1509  	netWorkName1 := "test1"
  1510  	netWorkName2 := "test2"
  1511  	containerName := "foo"
  1512  
  1513  	dockerCmd(c, "network", "create", netWorkName1)
  1514  	dockerCmd(c, "network", "create", netWorkName2)
  1515  	dockerCmd(c, "create", "--name", containerName, "busybox", "top")
  1516  	dockerCmd(c, "network", "connect", netWorkName1, containerName)
  1517  	dockerCmd(c, "network", "connect", netWorkName2, containerName)
  1518  	dockerCmd(c, "network", "disconnect", "bridge", containerName)
  1519  
  1520  	dockerCmd(c, "start", containerName)
  1521  	c.Assert(waitRun(containerName), checker.IsNil)
  1522  	networks := inspectField(c, containerName, "NetworkSettings.Networks")
  1523  	c.Assert(networks, checker.Contains, netWorkName1, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName1)))
  1524  	c.Assert(networks, checker.Contains, netWorkName2, check.Commentf(fmt.Sprintf("Should contain '%s' network", netWorkName2)))
  1525  	c.Assert(networks, checker.Not(checker.Contains), "bridge", check.Commentf("Should not contain 'bridge' network"))
  1526  }
  1527  
  1528  func (s *DockerNetworkSuite) TestDockerNetworkConnectWithAliasOnDefaultNetworks(c *check.C) {
  1529  	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
  1530  
  1531  	defaults := []string{"bridge", "host", "none"}
  1532  	out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top")
  1533  	containerID := strings.TrimSpace(out)
  1534  	for _, net := range defaults {
  1535  		res, _, err := dockerCmdWithError("network", "connect", "--alias", "alias"+net, net, containerID)
  1536  		c.Assert(err, checker.NotNil)
  1537  		c.Assert(res, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
  1538  	}
  1539  }
  1540  
  1541  func (s *DockerSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *check.C) {
  1542  	testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
  1543  	dockerCmd(c, "network", "create", "-d", "bridge", "net1")
  1544  	dockerCmd(c, "network", "create", "-d", "bridge", "net2")
  1545  
  1546  	cid, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox", "top")
  1547  	c.Assert(waitRun("first"), check.IsNil)
  1548  
  1549  	dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox", "top")
  1550  	c.Assert(waitRun("second"), check.IsNil)
  1551  
  1552  	// ping first container and its alias
  1553  	_, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1554  	c.Assert(err, check.IsNil)
  1555  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
  1556  	c.Assert(err, check.IsNil)
  1557  
  1558  	// ping first container's short-id alias
  1559  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
  1560  	c.Assert(err, check.IsNil)
  1561  
  1562  	// connect first container to net2 network
  1563  	dockerCmd(c, "network", "connect", "--alias=bar", "net2", "first")
  1564  	// connect second container to foo2 network with a different alias for first container
  1565  	dockerCmd(c, "network", "connect", "net2", "second")
  1566  
  1567  	// ping the new alias in network foo2
  1568  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
  1569  	c.Assert(err, check.IsNil)
  1570  
  1571  	// disconnect first container from net1 network
  1572  	dockerCmd(c, "network", "disconnect", "net1", "first")
  1573  
  1574  	// ping to net1 scoped alias "foo" must fail
  1575  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
  1576  	c.Assert(err, check.NotNil)
  1577  
  1578  	// ping to net2 scoped alias "bar" must still succeed
  1579  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
  1580  	c.Assert(err, check.IsNil)
  1581  	// ping to net2 scoped alias short-id must still succeed
  1582  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
  1583  	c.Assert(err, check.IsNil)
  1584  
  1585  	// verify the alias option is rejected when running on predefined network
  1586  	out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox", "top")
  1587  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1588  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
  1589  
  1590  	// verify the alias option is rejected when connecting to predefined network
  1591  	out, _, err = dockerCmdWithError("network", "connect", "--alias=any", "bridge", "first")
  1592  	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
  1593  	c.Assert(out, checker.Contains, runconfig.ErrUnsupportedNetworkAndAlias.Error())
  1594  }
  1595  
  1596  func (s *DockerSuite) TestUserDefinedNetworkConnectivity(c *check.C) {
  1597  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1598  	dockerCmd(c, "network", "create", "-d", "bridge", "br.net1")
  1599  
  1600  	dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox", "top")
  1601  	c.Assert(waitRun("c1.net1"), check.IsNil)
  1602  
  1603  	dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox", "top")
  1604  	c.Assert(waitRun("c2.net1"), check.IsNil)
  1605  
  1606  	// ping first container by its unqualified name
  1607  	_, _, err := dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1")
  1608  	c.Assert(err, check.IsNil)
  1609  
  1610  	// ping first container by its qualified name
  1611  	_, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1")
  1612  	c.Assert(err, check.IsNil)
  1613  
  1614  	// ping with first qualified name masked by an additional domain. should fail
  1615  	_, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1.google.com")
  1616  	c.Assert(err, check.NotNil)
  1617  }
  1618  
  1619  func (s *DockerSuite) TestEmbeddedDNSInvalidInput(c *check.C) {
  1620  	testRequires(c, DaemonIsLinux, NotUserNamespace)
  1621  	dockerCmd(c, "network", "create", "-d", "bridge", "nw1")
  1622  
  1623  	// Sending garbage to embedded DNS shouldn't crash the daemon
  1624  	dockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:jessie", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53")
  1625  }
  1626  
  1627  func (s *DockerSuite) TestDockerNetworkConnectFailsNoInspectChange(c *check.C) {
  1628  	dockerCmd(c, "run", "-d", "--name=bb", "busybox", "top")
  1629  	c.Assert(waitRun("bb"), check.IsNil)
  1630  
  1631  	ns0 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
  1632  
  1633  	// A failing redundant network connect should not alter current container's endpoint settings
  1634  	_, _, err := dockerCmdWithError("network", "connect", "bridge", "bb")
  1635  	c.Assert(err, check.NotNil)
  1636  
  1637  	ns1 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
  1638  	c.Assert(ns1, check.Equals, ns0)
  1639  }
  1640  
  1641  func (s *DockerSuite) TestDockerNetworkInternalMode(c *check.C) {
  1642  	dockerCmd(c, "network", "create", "--driver=bridge", "--internal", "internal")
  1643  	assertNwIsAvailable(c, "internal")
  1644  	nr := getNetworkResource(c, "internal")
  1645  	c.Assert(nr.Internal, checker.True)
  1646  
  1647  	dockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox", "top")
  1648  	c.Assert(waitRun("first"), check.IsNil)
  1649  	dockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox", "top")
  1650  	c.Assert(waitRun("second"), check.IsNil)
  1651  	out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "www.google.com")
  1652  	c.Assert(err, check.NotNil)
  1653  	c.Assert(out, checker.Contains, "ping: bad address")
  1654  	_, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1655  	c.Assert(err, check.IsNil)
  1656  }
  1657  
  1658  // Test for #21401
  1659  func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *check.C) {
  1660  	dockerCmd(c, "network", "create", "test@#$")
  1661  	assertNwIsAvailable(c, "test@#$")
  1662  	dockerCmd(c, "network", "rm", "test@#$")
  1663  	assertNwNotAvailable(c, "test@#$")
  1664  
  1665  	dockerCmd(c, "network", "create", "kiwl$%^")
  1666  	assertNwIsAvailable(c, "kiwl$%^")
  1667  	dockerCmd(c, "network", "rm", "kiwl$%^")
  1668  	assertNwNotAvailable(c, "kiwl$%^")
  1669  }
  1670  
  1671  func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *check.C) {
  1672  	testRequires(t, DaemonIsLinux)
  1673  	if err := s.d.StartWithBusybox("--live-restore"); err != nil {
  1674  		t.Fatal(err)
  1675  	}
  1676  	defer s.d.Stop()
  1677  	oldCon := "old"
  1678  
  1679  	_, err := s.d.Cmd("run", "-d", "--name", oldCon, "-p", "80:80", "busybox", "top")
  1680  	if err != nil {
  1681  		t.Fatal(err)
  1682  	}
  1683  	oldContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", oldCon)
  1684  	if err != nil {
  1685  		t.Fatal(err)
  1686  	}
  1687  	// Kill the daemon
  1688  	if err := s.d.Kill(); err != nil {
  1689  		t.Fatal(err)
  1690  	}
  1691  
  1692  	// restart the daemon
  1693  	if err := s.d.Start("--live-restore"); err != nil {
  1694  		t.Fatal(err)
  1695  	}
  1696  
  1697  	// start a new container, the new container's ip should not be the same with
  1698  	// old running container.
  1699  	newCon := "new"
  1700  	_, err = s.d.Cmd("run", "-d", "--name", newCon, "busybox", "top")
  1701  	if err != nil {
  1702  		t.Fatal(err)
  1703  	}
  1704  	newContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", newCon)
  1705  	if err != nil {
  1706  		t.Fatal(err)
  1707  	}
  1708  	if strings.Compare(strings.TrimSpace(oldContainerIP), strings.TrimSpace(newContainerIP)) == 0 {
  1709  		t.Fatalf("new container ip should not equal to old running container  ip")
  1710  	}
  1711  
  1712  	// start a new container, the new container should ping old running container
  1713  	_, err = s.d.Cmd("run", "-t", "busybox", "ping", "-c", "1", oldContainerIP)
  1714  	if err != nil {
  1715  		t.Fatal(err)
  1716  	}
  1717  
  1718  	// start a new container, trying to publish port 80:80 should fail
  1719  	out, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
  1720  	if err == nil || !strings.Contains(out, "Bind for 0.0.0.0:80 failed: port is already allocated") {
  1721  		t.Fatalf("80 port is allocated to old running container, it should failed on allocating to new container")
  1722  	}
  1723  
  1724  	// kill old running container and try to allocate again
  1725  	_, err = s.d.Cmd("kill", oldCon)
  1726  	if err != nil {
  1727  		t.Fatal(err)
  1728  	}
  1729  	id, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
  1730  	if err != nil {
  1731  		t.Fatal(err)
  1732  	}
  1733  
  1734  	// Cleanup because these containers will not be shut down by daemon
  1735  	out, err = s.d.Cmd("stop", newCon)
  1736  	if err != nil {
  1737  		t.Fatalf("err: %v %v", err, string(out))
  1738  	}
  1739  	_, err = s.d.Cmd("stop", strings.TrimSpace(id))
  1740  	if err != nil {
  1741  		t.Fatal(err)
  1742  	}
  1743  }
  1744  
  1745  func (s *DockerNetworkSuite) TestDockerNetworkFlagAlias(c *check.C) {
  1746  	dockerCmd(c, "network", "create", "user")
  1747  	output, status := dockerCmd(c, "run", "--rm", "--network=user", "--network-alias=foo", "busybox", "true")
  1748  	c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output))
  1749  
  1750  	output, status, _ = dockerCmdWithError("run", "--rm", "--net=user", "--network=user", "busybox", "true")
  1751  	c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output))
  1752  
  1753  	output, status, _ = dockerCmdWithError("run", "--rm", "--network=user", "--net-alias=foo", "--network-alias=bar", "busybox", "true")
  1754  	c.Assert(status, checker.Equals, 0, check.Commentf("unexpected status code %d (%s)", status, output))
  1755  }
  1756  
  1757  func (s *DockerNetworkSuite) TestDockerNetworkValidateIP(c *check.C) {
  1758  	_, _, err := dockerCmdWithError("network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "mynet")
  1759  	c.Assert(err, check.IsNil)
  1760  	assertNwIsAvailable(c, "mynet")
  1761  
  1762  	_, _, err = dockerCmdWithError("run", "-d", "--name", "mynet0", "--net=mynet", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1763  	c.Assert(err, check.IsNil)
  1764  	c.Assert(waitRun("mynet0"), check.IsNil)
  1765  	verifyIPAddressConfig(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
  1766  	verifyIPAddresses(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
  1767  
  1768  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "mynet_ip", "--ip6", "2001:db8:1234::9999", "busybox", "top")
  1769  	c.Assert(err.Error(), checker.Contains, "invalid IPv4 address")
  1770  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "172.28.99.99", "--ip6", "mynet_ip6", "busybox", "top")
  1771  	c.Assert(err.Error(), checker.Contains, "invalid IPv6 address")
  1772  	// This is a case of IPv4 address to `--ip6`
  1773  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "172.28.99.99", "busybox", "top")
  1774  	c.Assert(err.Error(), checker.Contains, "invalid IPv6 address")
  1775  	// This is a special case of an IPv4-mapped IPv6 address
  1776  	_, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "::ffff:172.28.99.99", "busybox", "top")
  1777  	c.Assert(err.Error(), checker.Contains, "invalid IPv6 address")
  1778  }
  1779  
  1780  // Test case for 26220
  1781  func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *check.C) {
  1782  	out, _ := dockerCmd(c, "network", "inspect", "--format", "{{.Id}}", "bridge")
  1783  
  1784  	network := strings.TrimSpace(out)
  1785  
  1786  	name := "test"
  1787  	dockerCmd(c, "create", "--name", name, "busybox", "top")
  1788  
  1789  	_, _, err := dockerCmdWithError("network", "disconnect", network, name)
  1790  	c.Assert(err, check.IsNil)
  1791  }