docker_cli_network_unix_test.go 70 KB

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