github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/integration-cli/docker_api_network_test.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net" 7 "net/http" 8 "net/url" 9 "strings" 10 "testing" 11 12 "github.com/Prakhar-Agarwal-byte/moby/api/types" 13 "github.com/Prakhar-Agarwal-byte/moby/api/types/filters" 14 "github.com/Prakhar-Agarwal-byte/moby/api/types/network" 15 "github.com/Prakhar-Agarwal-byte/moby/api/types/versions" 16 "github.com/Prakhar-Agarwal-byte/moby/integration-cli/cli" 17 "github.com/Prakhar-Agarwal-byte/moby/testutil" 18 "github.com/Prakhar-Agarwal-byte/moby/testutil/request" 19 "gotest.tools/v3/assert" 20 ) 21 22 func (s *DockerAPISuite) TestAPINetworkGetDefaults(c *testing.T) { 23 testRequires(c, DaemonIsLinux) 24 // By default docker daemon creates 3 networks. check if they are present 25 defaults := []string{"bridge", "host", "none"} 26 for _, nn := range defaults { 27 assert.Assert(c, isNetworkAvailable(c, nn)) 28 } 29 } 30 31 func (s *DockerAPISuite) TestAPINetworkFilter(c *testing.T) { 32 testRequires(c, DaemonIsLinux) 33 nr := getNetworkResource(c, getNetworkIDByName(c, "bridge")) 34 assert.Equal(c, nr.Name, "bridge") 35 } 36 37 func (s *DockerAPISuite) TestAPINetworkInspectBridge(c *testing.T) { 38 testRequires(c, DaemonIsLinux) 39 // Inspect default bridge network 40 nr := getNetworkResource(c, "bridge") 41 assert.Equal(c, nr.Name, "bridge") 42 43 // run a container and attach it to the default bridge network 44 out := cli.DockerCmd(c, "run", "-d", "--name", "test", "busybox", "top").Stdout() 45 containerID := strings.TrimSpace(out) 46 containerIP := findContainerIP(c, "test", "bridge") 47 48 // inspect default bridge network again and make sure the container is connected 49 nr = getNetworkResource(c, nr.ID) 50 assert.Equal(c, nr.Driver, "bridge") 51 assert.Equal(c, nr.Scope, "local") 52 assert.Equal(c, nr.Internal, false) 53 assert.Equal(c, nr.EnableIPv6, false) 54 assert.Equal(c, nr.IPAM.Driver, "default") 55 _, ok := nr.Containers[containerID] 56 assert.Assert(c, ok) 57 58 ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) 59 assert.NilError(c, err) 60 assert.Equal(c, ip.String(), containerIP) 61 } 62 63 func (s *DockerAPISuite) TestAPINetworkInspectUserDefinedNetwork(c *testing.T) { 64 testRequires(c, DaemonIsLinux) 65 // IPAM configuration inspect 66 ipam := &network.IPAM{ 67 Driver: "default", 68 Config: []network.IPAMConfig{{Subnet: "172.28.0.0/16", IPRange: "172.28.5.0/24", Gateway: "172.28.5.254"}}, 69 } 70 config := types.NetworkCreateRequest{ 71 Name: "br0", 72 NetworkCreate: types.NetworkCreate{ 73 Driver: "bridge", 74 IPAM: ipam, 75 Options: map[string]string{"foo": "bar", "opts": "dopts"}, 76 }, 77 } 78 id0 := createNetwork(c, config, http.StatusCreated) 79 assert.Assert(c, isNetworkAvailable(c, "br0")) 80 81 nr := getNetworkResource(c, id0) 82 assert.Equal(c, len(nr.IPAM.Config), 1) 83 assert.Equal(c, nr.IPAM.Config[0].Subnet, "172.28.0.0/16") 84 assert.Equal(c, nr.IPAM.Config[0].IPRange, "172.28.5.0/24") 85 assert.Equal(c, nr.IPAM.Config[0].Gateway, "172.28.5.254") 86 assert.Equal(c, nr.Options["foo"], "bar") 87 assert.Equal(c, nr.Options["opts"], "dopts") 88 89 // delete the network and make sure it is deleted 90 deleteNetwork(c, id0, true) 91 assert.Assert(c, !isNetworkAvailable(c, "br0")) 92 } 93 94 func (s *DockerAPISuite) TestAPINetworkConnectDisconnect(c *testing.T) { 95 testRequires(c, DaemonIsLinux) 96 // Create test network 97 name := "testnetwork" 98 config := types.NetworkCreateRequest{ 99 Name: name, 100 } 101 id := createNetwork(c, config, http.StatusCreated) 102 nr := getNetworkResource(c, id) 103 assert.Equal(c, nr.Name, name) 104 assert.Equal(c, nr.ID, id) 105 assert.Equal(c, len(nr.Containers), 0) 106 107 // run a container 108 out := cli.DockerCmd(c, "run", "-d", "--name", "test", "busybox", "top").Stdout() 109 containerID := strings.TrimSpace(out) 110 111 // connect the container to the test network 112 connectNetwork(c, nr.ID, containerID) 113 114 // inspect the network to make sure container is connected 115 nr = getNetworkResource(c, nr.ID) 116 assert.Equal(c, len(nr.Containers), 1) 117 _, ok := nr.Containers[containerID] 118 assert.Assert(c, ok) 119 120 // check if container IP matches network inspect 121 ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address) 122 assert.NilError(c, err) 123 containerIP := findContainerIP(c, "test", "testnetwork") 124 assert.Equal(c, ip.String(), containerIP) 125 126 // disconnect container from the network 127 disconnectNetwork(c, nr.ID, containerID) 128 nr = getNetworkResource(c, nr.ID) 129 assert.Equal(c, nr.Name, name) 130 assert.Equal(c, len(nr.Containers), 0) 131 132 // delete the network 133 deleteNetwork(c, nr.ID, true) 134 } 135 136 func (s *DockerAPISuite) TestAPINetworkIPAMMultipleBridgeNetworks(c *testing.T) { 137 testRequires(c, DaemonIsLinux) 138 // test0 bridge network 139 ipam0 := &network.IPAM{ 140 Driver: "default", 141 Config: []network.IPAMConfig{{Subnet: "192.178.0.0/16", IPRange: "192.178.128.0/17", Gateway: "192.178.138.100"}}, 142 } 143 config0 := types.NetworkCreateRequest{ 144 Name: "test0", 145 NetworkCreate: types.NetworkCreate{ 146 Driver: "bridge", 147 IPAM: ipam0, 148 }, 149 } 150 id0 := createNetwork(c, config0, http.StatusCreated) 151 assert.Assert(c, isNetworkAvailable(c, "test0")) 152 153 ipam1 := &network.IPAM{ 154 Driver: "default", 155 Config: []network.IPAMConfig{{Subnet: "192.178.128.0/17", Gateway: "192.178.128.1"}}, 156 } 157 // test1 bridge network overlaps with test0 158 config1 := types.NetworkCreateRequest{ 159 Name: "test1", 160 NetworkCreate: types.NetworkCreate{ 161 Driver: "bridge", 162 IPAM: ipam1, 163 }, 164 } 165 if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") { 166 createNetwork(c, config1, http.StatusInternalServerError) 167 } else { 168 createNetwork(c, config1, http.StatusForbidden) 169 } 170 assert.Assert(c, !isNetworkAvailable(c, "test1")) 171 172 ipam2 := &network.IPAM{ 173 Driver: "default", 174 Config: []network.IPAMConfig{{Subnet: "192.169.0.0/16", Gateway: "192.169.100.100"}}, 175 } 176 // test2 bridge network does not overlap 177 config2 := types.NetworkCreateRequest{ 178 Name: "test2", 179 NetworkCreate: types.NetworkCreate{ 180 Driver: "bridge", 181 IPAM: ipam2, 182 }, 183 } 184 createNetwork(c, config2, http.StatusCreated) 185 assert.Assert(c, isNetworkAvailable(c, "test2")) 186 187 // remove test0 and retry to create test1 188 deleteNetwork(c, id0, true) 189 createNetwork(c, config1, http.StatusCreated) 190 assert.Assert(c, isNetworkAvailable(c, "test1")) 191 192 // for networks w/o ipam specified, docker will choose proper non-overlapping subnets 193 createNetwork(c, types.NetworkCreateRequest{Name: "test3"}, http.StatusCreated) 194 assert.Assert(c, isNetworkAvailable(c, "test3")) 195 createNetwork(c, types.NetworkCreateRequest{Name: "test4"}, http.StatusCreated) 196 assert.Assert(c, isNetworkAvailable(c, "test4")) 197 createNetwork(c, types.NetworkCreateRequest{Name: "test5"}, http.StatusCreated) 198 assert.Assert(c, isNetworkAvailable(c, "test5")) 199 200 for i := 1; i < 6; i++ { 201 deleteNetwork(c, fmt.Sprintf("test%d", i), true) 202 } 203 } 204 205 func (s *DockerAPISuite) TestAPICreateDeletePredefinedNetworks(c *testing.T) { 206 testRequires(c, DaemonIsLinux, SwarmInactive) 207 createDeletePredefinedNetwork(c, "bridge") 208 createDeletePredefinedNetwork(c, "none") 209 createDeletePredefinedNetwork(c, "host") 210 } 211 212 func createDeletePredefinedNetwork(c *testing.T, name string) { 213 // Create pre-defined network 214 config := types.NetworkCreateRequest{Name: name} 215 expectedStatus := http.StatusForbidden 216 if versions.LessThan(testEnv.DaemonAPIVersion(), "1.34") { 217 // In the early test code it uses bool value to represent 218 // whether createNetwork() is expected to fail or not. 219 // Therefore, we use negation to handle the same logic after 220 // the code was changed in https://github.com/moby/moby/pull/35030 221 // -http.StatusCreated will also be checked as NOT equal to 222 // http.StatusCreated in createNetwork() function. 223 expectedStatus = -http.StatusCreated 224 } 225 createNetwork(c, config, expectedStatus) 226 deleteNetwork(c, name, false) 227 } 228 229 func isNetworkAvailable(c *testing.T, name string) bool { 230 resp, body, err := request.Get(testutil.GetContext(c), "/networks") 231 assert.NilError(c, err) 232 defer resp.Body.Close() 233 assert.Equal(c, resp.StatusCode, http.StatusOK) 234 235 var nJSON []types.NetworkResource 236 err = json.NewDecoder(body).Decode(&nJSON) 237 assert.NilError(c, err) 238 239 for _, n := range nJSON { 240 if n.Name == name { 241 return true 242 } 243 } 244 return false 245 } 246 247 func getNetworkIDByName(c *testing.T, name string) string { 248 filterJSON, err := filters.ToJSON(filters.NewArgs(filters.Arg("name", name))) 249 assert.NilError(c, err) 250 v := url.Values{} 251 v.Set("filters", filterJSON) 252 253 resp, body, err := request.Get(testutil.GetContext(c), "/networks?"+v.Encode()) 254 assert.Equal(c, resp.StatusCode, http.StatusOK) 255 assert.NilError(c, err) 256 257 var nJSON []types.NetworkResource 258 err = json.NewDecoder(body).Decode(&nJSON) 259 assert.NilError(c, err) 260 var res string 261 for _, n := range nJSON { 262 // Find exact match 263 if n.Name == name { 264 res = n.ID 265 } 266 } 267 assert.Assert(c, res != "") 268 269 return res 270 } 271 272 func getNetworkResource(c *testing.T, id string) *types.NetworkResource { 273 _, obj, err := request.Get(testutil.GetContext(c), "/networks/"+id) 274 assert.NilError(c, err) 275 276 nr := types.NetworkResource{} 277 err = json.NewDecoder(obj).Decode(&nr) 278 assert.NilError(c, err) 279 280 return &nr 281 } 282 283 func createNetwork(c *testing.T, config types.NetworkCreateRequest, expectedStatusCode int) string { 284 resp, body, err := request.Post(testutil.GetContext(c), "/networks/create", request.JSONBody(config)) 285 assert.NilError(c, err) 286 defer resp.Body.Close() 287 288 if expectedStatusCode >= 0 { 289 assert.Equal(c, resp.StatusCode, expectedStatusCode) 290 } else { 291 assert.Assert(c, resp.StatusCode != -expectedStatusCode) 292 } 293 294 if expectedStatusCode == http.StatusCreated || expectedStatusCode < 0 { 295 var nr types.NetworkCreateResponse 296 err = json.NewDecoder(body).Decode(&nr) 297 assert.NilError(c, err) 298 299 return nr.ID 300 } 301 return "" 302 } 303 304 func connectNetwork(c *testing.T, nid, cid string) { 305 config := types.NetworkConnect{ 306 Container: cid, 307 } 308 309 resp, _, err := request.Post(testutil.GetContext(c), "/networks/"+nid+"/connect", request.JSONBody(config)) 310 assert.Equal(c, resp.StatusCode, http.StatusOK) 311 assert.NilError(c, err) 312 } 313 314 func disconnectNetwork(c *testing.T, nid, cid string) { 315 config := types.NetworkConnect{ 316 Container: cid, 317 } 318 319 resp, _, err := request.Post(testutil.GetContext(c), "/networks/"+nid+"/disconnect", request.JSONBody(config)) 320 assert.Equal(c, resp.StatusCode, http.StatusOK) 321 assert.NilError(c, err) 322 } 323 324 func deleteNetwork(c *testing.T, id string, shouldSucceed bool) { 325 resp, _, err := request.Delete(testutil.GetContext(c), "/networks/"+id) 326 assert.NilError(c, err) 327 defer resp.Body.Close() 328 if !shouldSucceed { 329 assert.Assert(c, resp.StatusCode != http.StatusOK) 330 return 331 } 332 assert.Equal(c, resp.StatusCode, http.StatusNoContent) 333 }