Browse code

Add Subnets info for user-defined network

* If user doesn't specify the subnets to create a network, it will pick
subnets from inside preferred pool. This PR aims to inspect these subnets info

* Add integration tests for docker inspect the subnets.

* docker-py project is already synchronized.

* jenkins checks depend on https://github.com/docker/docker-py/pull/888

Fixes issue #18626

Signed-off-by: Wen Cheng Ma <wenchma@cn.ibm.com>

Wen Cheng Ma authored on 2015/12/28 13:56:57
Showing 8 changed files
... ...
@@ -184,12 +184,17 @@ func buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
184 184
 func buildIpamResources(r *types.NetworkResource, nw libnetwork.Network) {
185 185
 	id, opts, ipv4conf, ipv6conf := nw.Info().IpamConfig()
186 186
 
187
+	ipv4Info, ipv6Info := nw.Info().IpamInfo()
188
+
187 189
 	r.IPAM.Driver = id
188 190
 
189 191
 	r.IPAM.Options = opts
190 192
 
191 193
 	r.IPAM.Config = []network.IPAMConfig{}
192 194
 	for _, ip4 := range ipv4conf {
195
+		if ip4.PreferredPool == "" {
196
+			continue
197
+		}
193 198
 		iData := network.IPAMConfig{}
194 199
 		iData.Subnet = ip4.PreferredPool
195 200
 		iData.IPRange = ip4.SubPool
... ...
@@ -198,7 +203,21 @@ func buildIpamResources(r *types.NetworkResource, nw libnetwork.Network) {
198 198
 		r.IPAM.Config = append(r.IPAM.Config, iData)
199 199
 	}
200 200
 
201
+	if len(r.IPAM.Config) == 0 {
202
+		for _, ip4Info := range ipv4Info {
203
+			iData := network.IPAMConfig{}
204
+			iData.Subnet = ip4Info.IPAMData.Pool.String()
205
+			iData.Gateway = ip4Info.IPAMData.Gateway.String()
206
+			r.IPAM.Config = append(r.IPAM.Config, iData)
207
+		}
208
+	}
209
+
210
+	hasIpv6Conf := false
201 211
 	for _, ip6 := range ipv6conf {
212
+		if ip6.PreferredPool == "" {
213
+			continue
214
+		}
215
+		hasIpv6Conf = true
202 216
 		iData := network.IPAMConfig{}
203 217
 		iData.Subnet = ip6.PreferredPool
204 218
 		iData.IPRange = ip6.SubPool
... ...
@@ -206,6 +225,15 @@ func buildIpamResources(r *types.NetworkResource, nw libnetwork.Network) {
206 206
 		iData.AuxAddress = ip6.AuxAddresses
207 207
 		r.IPAM.Config = append(r.IPAM.Config, iData)
208 208
 	}
209
+
210
+	if !hasIpv6Conf {
211
+		for _, ip6Info := range ipv6Info {
212
+			iData := network.IPAMConfig{}
213
+			iData.Subnet = ip6Info.IPAMData.Pool.String()
214
+			iData.Gateway = ip6Info.IPAMData.Gateway.String()
215
+			r.IPAM.Config = append(r.IPAM.Config, iData)
216
+		}
217
+	}
209 218
 }
210 219
 
211 220
 func buildEndpointResource(e libnetwork.Endpoint) types.EndpointResource {
... ...
@@ -121,6 +121,7 @@ This section lists each version from latest to oldest.  Each listing includes a
121 121
   for custom IPAM plugins.
122 122
 * `GET /networks/{network-id}` Now returns IPAM config options for custom IPAM plugins if any
123 123
   are available.
124
+* `GET /networks/<network-id>` now returns subnets info for user-defined networks.
124 125
 
125 126
 ### v1.21 API changes
126 127
 
... ...
@@ -2937,7 +2937,7 @@ Status Codes:
2937 2937
 
2938 2938
 **Example request**:
2939 2939
 
2940
-    GET /networks/f2de39df4171b0dc801e8002d1d999b77256983dfc63041c0f34030aa3977566 HTTP/1.1
2940
+    GET /networks/7d86d31b1478e7cca9ebed7e73aa0fdeec46c5ca29497431d3007d2d9e15ed99 HTTP/1.1
2941 2941
 
2942 2942
 **Example response**:
2943 2943
 
... ...
@@ -2946,15 +2946,16 @@ HTTP/1.1 200 OK
2946 2946
 Content-Type: application/json
2947 2947
 
2948 2948
 {
2949
-  "Name": "bridge",
2950
-  "Id": "f2de39df4171b0dc801e8002d1d999b77256983dfc63041c0f34030aa3977566",
2949
+  "Name": "net01",
2950
+  "Id": "7d86d31b1478e7cca9ebed7e73aa0fdeec46c5ca29497431d3007d2d9e15ed99",
2951 2951
   "Scope": "local",
2952 2952
   "Driver": "bridge",
2953 2953
   "IPAM": {
2954 2954
     "Driver": "default",
2955 2955
     "Config": [
2956 2956
       {
2957
-        "Subnet": "172.17.0.0/16"
2957
+        "Subnet": "172.19.0.0/16",
2958
+        "Gateway": "172.19.0.1/16"
2958 2959
       }
2959 2960
     ],
2960 2961
     "Options": {
... ...
@@ -2962,11 +2963,11 @@ Content-Type: application/json
2962 2962
     }
2963 2963
   },
2964 2964
   "Containers": {
2965
-    "39b69226f9d79f5634485fb236a23b2fe4e96a0a94128390a7fbbcc167065867": {
2966
-      "Name": "mad_mclean",
2967
-      "EndpointID": "ed2419a97c1d9954d05b46e462e7002ea552f216e9b136b80a7db8d98b442eda",
2968
-      "MacAddress": "02:42:ac:11:00:02",
2969
-      "IPv4Address": "172.17.0.2/16",
2965
+    "19a4d5d687db25203351ed79d478946f861258f018fe384f229f2efa4b23513c": {
2966
+      "Name": "test",
2967
+      "EndpointID": "628cadb8bcb92de107b2a1e516cbffe463e321f548feb37697cce00ad694f21a",
2968
+      "MacAddress": "02:42:ac:13:00:02",
2969
+      "IPv4Address": "172.19.0.2/16",
2970 2970
       "IPv6Address": ""
2971 2971
     }
2972 2972
   },
... ...
@@ -17,7 +17,7 @@ parent = "smn_cli"
17 17
       -f, --format=       Format the output using the given go template.
18 18
       --help             Print usage
19 19
 
20
-Returns information about one or more networks. By default, this command renders all results in a JSON object. For example, if you connect two containers to a network:
20
+Returns information about one or more networks. By default, this command renders all results in a JSON object. For example, if you connect two containers to the default `bridge` network:
21 21
 
22 22
 ```bash
23 23
 $ sudo docker run -itd --name=container1 busybox
... ...
@@ -78,6 +78,32 @@ $ sudo docker network inspect bridge
78 78
 ]
79 79
 ```
80 80
 
81
+Returns the information about the user-defined network:
82
+
83
+```bash
84
+$ docker network create simple-network
85
+69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a
86
+$ docker network inspect simple-network
87
+[
88
+    {
89
+        "Name": "simple-network",
90
+        "Id": "69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a",
91
+        "Scope": "local",
92
+        "Driver": "bridge",
93
+        "IPAM": {
94
+            "Driver": "default",
95
+            "Config": [
96
+                {
97
+                    "Subnet": "172.22.0.0/16",
98
+                    "Gateway": "172.22.0.1/16"
99
+                }
100
+            ]
101
+        },
102
+        "Containers": {},
103
+        "Options": {}
104
+    }
105
+]
106
+```
81 107
 
82 108
 ## Related information
83 109
 
... ...
@@ -305,19 +305,22 @@ features and some old features that aren't available.
305 305
 
306 306
 ```
307 307
 $ docker network create --driver bridge isolated_nw
308
-c5ee82f76de30319c75554a57164c682e7372d2c694fec41e42ac3b77e570f6b
308
+1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b
309 309
 
310 310
 $ docker network inspect isolated_nw
311 311
 [
312 312
     {
313 313
         "Name": "isolated_nw",
314
-        "Id": "c5ee82f76de30319c75554a57164c682e7372d2c694fec41e42ac3b77e570f6b",
314
+        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
315 315
         "Scope": "local",
316 316
         "Driver": "bridge",
317 317
         "IPAM": {
318 318
             "Driver": "default",
319 319
             "Config": [
320
-                {}
320
+                {
321
+                    "Subnet": "172.21.0.0/16",
322
+                    "Gateway": "172.21.0.1/16"
323
+                }
321 324
             ]
322 325
         },
323 326
         "Containers": {},
... ...
@@ -338,13 +341,13 @@ After you create the network, you can launch containers on it using  the `docker
338 338
 
339 339
 ```
340 340
 $ docker run --net=isolated_nw -itd --name=container3 busybox
341
-885b7b4f792bae534416c95caa35ba272f201fa181e18e59beba0c80d7d77c1d
341
+8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c
342 342
 
343 343
 $ docker network inspect isolated_nw
344 344
 [
345 345
     {
346 346
         "Name": "isolated_nw",
347
-        "Id": "c5ee82f76de30319c75554a57164c682e7372d2c694fec41e42ac3b77e570f6b",
347
+        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
348 348
         "Scope": "local",
349 349
         "Driver": "bridge",
350 350
         "IPAM": {
... ...
@@ -354,8 +357,8 @@ $ docker network inspect isolated_nw
354 354
             ]
355 355
         },
356 356
         "Containers": {
357
-            "885b7b4f792bae534416c95caa35ba272f201fa181e18e59beba0c80d7d77c1d": {
358
-                "EndpointID": "514e1b419074397ea92bcfaa6698d17feb62db49d1320a27393b853ec65319c3",
357
+            "8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c": {
358
+                "EndpointID": "93b2db4a9b9a997beb912d28bcfc117f7b0eb924ff91d48cfa251d473e6a9b08",
359 359
                 "MacAddress": "02:42:ac:15:00:02",
360 360
                 "IPv4Address": "172.21.0.2/16",
361 361
                 "IPv6Address": ""
... ...
@@ -36,18 +36,21 @@ A `bridge` network resides on a single host running an instance of Docker Engine
36 36
 
37 37
 ```bash
38 38
 $ docker network create simple-network
39
-de792b8258895cf5dc3b43835e9d61a9803500b991654dacb1f4f0546b1c88f8
39
+69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a
40 40
 $ docker network inspect simple-network
41 41
 [
42 42
     {
43 43
         "Name": "simple-network",
44
-        "Id": "de792b8258895cf5dc3b43835e9d61a9803500b991654dacb1f4f0546b1c88f8",
44
+        "Id": "69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a",
45 45
         "Scope": "local",
46 46
         "Driver": "bridge",
47 47
         "IPAM": {
48 48
             "Driver": "default",
49 49
             "Config": [
50
-                {}
50
+                {
51
+                    "Subnet": "172.22.0.0/16",
52
+                    "Gateway": "172.22.0.1/16"
53
+                }
51 54
             ]
52 55
         },
53 56
         "Containers": {},
... ...
@@ -134,7 +137,8 @@ $ docker network inspect isolated_nw
134 134
             "Driver": "default",
135 135
             "Config": [
136 136
                 {
137
-                    "Subnet": "172.25.0.0/16"
137
+                    "Subnet": "172.21.0.0/16",
138
+                    "Gateway": "172.21.0.1/16"
138 139
                 }
139 140
             ]
140 141
         },
... ...
@@ -662,7 +666,8 @@ $ docker network inspect isolated_nw
662 662
             "Driver": "default",
663 663
             "Config": [
664 664
                 {
665
-                    "Subnet": "172.25.0.0/16"
665
+                    "Subnet": "172.21.0.0/16",
666
+                    "Gateway": "172.21.0.1/16"
666 667
                 }
667 668
             ]
668 669
         },
... ...
@@ -746,7 +751,8 @@ docker network inspect isolated_nw
746 746
             "Driver": "default",
747 747
             "Config": [
748 748
                 {
749
-                    "Subnet": "172.25.0.0/16"
749
+                    "Subnet": "172.21.0.0/16",
750
+                    "Gateway": "172.21.0.1/16"
750 751
                 }
751 752
             ]
752 753
         },
... ...
@@ -282,11 +282,11 @@ func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *check.C) {
282 282
 	defer func() {
283 283
 		dockerCmd(c, "network", "rm", "dev")
284 284
 	}()
285
-	containerID := strings.TrimSpace(out)
285
+	networkID := strings.TrimSpace(out)
286 286
 
287 287
 	// filter with partial ID and partial name
288 288
 	// only show 'bridge' and 'dev' network
289
-	out, _ = dockerCmd(c, "network", "ls", "-f", "id="+containerID[0:5], "-f", "name=dge")
289
+	out, _ = dockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5], "-f", "name=dge")
290 290
 	assertNwList(c, out, []string{"dev", "bridge"})
291 291
 
292 292
 	// only show built-in network (bridge, none, host)
... ...
@@ -324,10 +324,11 @@ func (s *DockerSuite) TestDockerNetworkDeleteMultiple(c *check.C) {
324 324
 	dockerCmd(c, "network", "create", "testDelMulti2")
325 325
 	assertNwIsAvailable(c, "testDelMulti2")
326 326
 	out, _ := dockerCmd(c, "run", "-d", "--net", "testDelMulti2", "busybox", "top")
327
-	waitRun(strings.TrimSpace(out))
327
+	containerID := strings.TrimSpace(out)
328
+	waitRun(containerID)
328 329
 
329 330
 	// delete three networks at the same time, since testDelMulti2
330
-	// contains active container, it's deletion should fail.
331
+	// contains active container, its deletion should fail.
331 332
 	out, _, err := dockerCmdWithError("network", "rm", "testDelMulti0", "testDelMulti1", "testDelMulti2")
332 333
 	// err should not be nil due to deleting testDelMulti2 failed.
333 334
 	c.Assert(err, checker.NotNil, check.Commentf("out: %s", out))
... ...
@@ -335,7 +336,7 @@ func (s *DockerSuite) TestDockerNetworkDeleteMultiple(c *check.C) {
335 335
 	c.Assert(out, checker.Contains, "has active endpoints")
336 336
 	assertNwNotAvailable(c, "testDelMulti0")
337 337
 	assertNwNotAvailable(c, "testDelMulti1")
338
-	// testDelMulti2 can't be deleted, so it should exists
338
+	// testDelMulti2 can't be deleted, so it should exist
339 339
 	assertNwIsAvailable(c, "testDelMulti2")
340 340
 }
341 341
 
... ...
@@ -535,8 +536,46 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpamOptions(c *check.C) {
535 535
 	c.Assert(opts["opt2"], checker.Equals, "drv2")
536 536
 }
537 537
 
538
-func (s *DockerNetworkSuite) TestDockerNetworkInspect(c *check.C) {
539
-	// if unspecified, network gateway will be selected from inside preferred pool
538
+func (s *DockerNetworkSuite) TestDockerNetworkInspectDefault(c *check.C) {
539
+	nr := getNetworkResource(c, "none")
540
+	c.Assert(nr.Driver, checker.Equals, "null")
541
+	c.Assert(nr.Scope, checker.Equals, "local")
542
+	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
543
+	c.Assert(len(nr.IPAM.Config), checker.Equals, 0)
544
+
545
+	nr = getNetworkResource(c, "host")
546
+	c.Assert(nr.Driver, checker.Equals, "host")
547
+	c.Assert(nr.Scope, checker.Equals, "local")
548
+	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
549
+	c.Assert(len(nr.IPAM.Config), checker.Equals, 0)
550
+
551
+	nr = getNetworkResource(c, "bridge")
552
+	c.Assert(nr.Driver, checker.Equals, "bridge")
553
+	c.Assert(nr.Scope, checker.Equals, "local")
554
+	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
555
+	c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
556
+	c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil)
557
+	c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil)
558
+}
559
+
560
+func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomUnspecified(c *check.C) {
561
+	// if unspecified, network subnet will be selected from inside preferred pool
562
+	dockerCmd(c, "network", "create", "test01")
563
+	assertNwIsAvailable(c, "test01")
564
+
565
+	nr := getNetworkResource(c, "test01")
566
+	c.Assert(nr.Driver, checker.Equals, "bridge")
567
+	c.Assert(nr.Scope, checker.Equals, "local")
568
+	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
569
+	c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
570
+	c.Assert(nr.IPAM.Config[0].Subnet, checker.NotNil)
571
+	c.Assert(nr.IPAM.Config[0].Gateway, checker.NotNil)
572
+
573
+	dockerCmd(c, "network", "rm", "test01")
574
+	assertNwNotAvailable(c, "test01")
575
+}
576
+
577
+func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomSpecified(c *check.C) {
540 578
 	dockerCmd(c, "network", "create", "--driver=bridge", "--subnet=172.28.0.0/16", "--ip-range=172.28.5.0/24", "--gateway=172.28.5.254", "br0")
541 579
 	assertNwIsAvailable(c, "br0")
542 580
 
... ...
@@ -549,6 +588,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkInspect(c *check.C) {
549 549
 	c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24")
550 550
 	c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254")
551 551
 	dockerCmd(c, "network", "rm", "br0")
552
+	assertNwNotAvailable(c, "test01")
552 553
 }
553 554
 
554 555
 func (s *DockerNetworkSuite) TestDockerNetworkIpamInvalidCombinations(c *check.C) {
... ...
@@ -572,6 +612,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkIpamInvalidCombinations(c *check.C
572 572
 	_, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.128.0/17", "test1")
573 573
 	c.Assert(err, check.NotNil)
574 574
 	dockerCmd(c, "network", "rm", "test0")
575
+	assertNwNotAvailable(c, "test0")
575 576
 }
576 577
 
577 578
 func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) {
... ...
@@ -584,6 +625,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *check.C) {
584 584
 	c.Assert(opts["opt1"], checker.Equals, "drv1")
585 585
 	c.Assert(opts["opt2"], checker.Equals, "drv2")
586 586
 	dockerCmd(c, "network", "rm", "testopt")
587
+	assertNwNotAvailable(c, "testopt")
587 588
 
588 589
 }
589 590
 
... ...
@@ -818,7 +860,7 @@ func connectContainerToNetworks(c *check.C, d *Daemon, cName string, nws []strin
818 818
 	out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top")
819 819
 	c.Assert(err, checker.IsNil, check.Commentf(out))
820 820
 
821
-	// Attach the container to other three networks
821
+	// Attach the container to other networks
822 822
 	for _, nw := range nws {
823 823
 		out, err = d.Cmd("network", "create", nw)
824 824
 		c.Assert(err, checker.IsNil, check.Commentf(out))
... ...
@@ -828,7 +870,7 @@ func connectContainerToNetworks(c *check.C, d *Daemon, cName string, nws []strin
828 828
 }
829 829
 
830 830
 func verifyContainerIsConnectedToNetworks(c *check.C, d *Daemon, cName string, nws []string) {
831
-	// Verify container is connected to all three networks
831
+	// Verify container is connected to all the networks
832 832
 	for _, nw := range nws {
833 833
 		out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName)
834 834
 		c.Assert(err, checker.IsNil, check.Commentf(out))
... ...
@@ -878,7 +920,8 @@ func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRe
878 878
 
879 879
 func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *check.C) {
880 880
 	out, _ := dockerCmd(c, "network", "create", "one")
881
-	dockerCmd(c, "run", "-d", "--net", strings.TrimSpace(out), "busybox", "top")
881
+	containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top")
882
+	c.Assert(err, checker.IsNil, check.Commentf(containerOut))
882 883
 }
883 884
 
884 885
 func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *check.C) {
... ...
@@ -12,7 +12,7 @@ NETWORK [NETWORK...]
12 12
 
13 13
 # DESCRIPTION
14 14
 
15
-Returns information about one or more networks. By default, this command renders all results in a JSON object. For example, if you connect two containers to a network:
15
+Returns information about one or more networks. By default, this command renders all results in a JSON object. For example, if you connect two containers to the default `bridge` network:
16 16
 
17 17
 ```bash
18 18
 $ sudo docker run -itd --name=container1 busybox
... ...
@@ -73,6 +73,33 @@ $ sudo docker network inspect bridge
73 73
 ]
74 74
 ```
75 75
 
76
+Returns the information about the user-defined network:
77
+
78
+```bash
79
+$ docker network create simple-network
80
+69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a
81
+$ docker network inspect simple-network
82
+[
83
+    {
84
+        "Name": "simple-network",
85
+        "Id": "69568e6336d8c96bbf57869030919f7c69524f71183b44d80948bd3927c87f6a",
86
+        "Scope": "local",
87
+        "Driver": "bridge",
88
+        "IPAM": {
89
+            "Driver": "default",
90
+            "Config": [
91
+                {
92
+                    "Subnet": "172.22.0.0/16",
93
+                    "Gateway": "172.22.0.1/16"
94
+                }
95
+            ]
96
+        },
97
+        "Containers": {},
98
+        "Options": {}
99
+    }
100
+]
101
+```
102
+
76 103
 # OPTIONS
77 104
 **-f**, **--format**=""
78 105
   Format the output using the given go template.