github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/integration/network/service_test.go (about) 1 package network // import "github.com/Prakhar-Agarwal-byte/moby/integration/network" 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/Prakhar-Agarwal-byte/moby/api/types" 9 swarmtypes "github.com/Prakhar-Agarwal-byte/moby/api/types/swarm" 10 "github.com/Prakhar-Agarwal-byte/moby/api/types/versions" 11 "github.com/Prakhar-Agarwal-byte/moby/client" 12 "github.com/Prakhar-Agarwal-byte/moby/integration/internal/network" 13 "github.com/Prakhar-Agarwal-byte/moby/integration/internal/swarm" 14 "github.com/Prakhar-Agarwal-byte/moby/testutil" 15 "github.com/Prakhar-Agarwal-byte/moby/testutil/daemon" 16 "gotest.tools/v3/assert" 17 "gotest.tools/v3/icmd" 18 "gotest.tools/v3/poll" 19 "gotest.tools/v3/skip" 20 ) 21 22 // delInterface removes given network interface 23 func delInterface(ctx context.Context, t *testing.T, ifName string) { 24 t.Helper() 25 testutil.RunCommand(ctx, "ip", "link", "delete", ifName).Assert(t, icmd.Success) 26 testutil.RunCommand(ctx, "iptables", "-t", "nat", "--flush").Assert(t, icmd.Success) 27 testutil.RunCommand(ctx, "iptables", "--flush").Assert(t, icmd.Success) 28 } 29 30 func TestDaemonRestartWithLiveRestore(t *testing.T) { 31 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 32 skip.If(t, testEnv.IsRemoteDaemon) 33 skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "skip test from new feature") 34 skip.If(t, testEnv.IsRootless, "rootless mode has different view of network") 35 ctx := testutil.StartSpan(baseContext, t) 36 37 d := daemon.New(t) 38 defer d.Stop(t) 39 d.Start(t) 40 41 c := d.NewClientT(t) 42 defer c.Close() 43 44 // Verify bridge network's subnet 45 out, err := c.NetworkInspect(ctx, "bridge", types.NetworkInspectOptions{}) 46 assert.NilError(t, err) 47 subnet := out.IPAM.Config[0].Subnet 48 49 d.Restart(t, 50 "--live-restore=true", 51 "--default-address-pool", "base=175.30.0.0/16,size=16", 52 "--default-address-pool", "base=175.33.0.0/16,size=24", 53 ) 54 55 out1, err := c.NetworkInspect(ctx, "bridge", types.NetworkInspectOptions{}) 56 assert.NilError(t, err) 57 // Make sure docker0 doesn't get override with new IP in live restore case 58 assert.Equal(t, out1.IPAM.Config[0].Subnet, subnet) 59 } 60 61 func TestDaemonDefaultNetworkPools(t *testing.T) { 62 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 63 // Remove docker0 bridge and the start daemon defining the predefined address pools 64 skip.If(t, testEnv.IsRemoteDaemon) 65 skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "skip test from new feature") 66 skip.If(t, testEnv.IsRootless, "rootless mode has different view of network") 67 ctx := testutil.StartSpan(baseContext, t) 68 69 defaultNetworkBridge := "docker0" 70 delInterface(ctx, t, defaultNetworkBridge) 71 d := daemon.New(t) 72 defer d.Stop(t) 73 d.Start(t, 74 "--default-address-pool", "base=175.30.0.0/16,size=16", 75 "--default-address-pool", "base=175.33.0.0/16,size=24", 76 ) 77 78 c := d.NewClientT(t) 79 defer c.Close() 80 81 // Verify bridge network's subnet 82 out, err := c.NetworkInspect(ctx, "bridge", types.NetworkInspectOptions{}) 83 assert.NilError(t, err) 84 assert.Equal(t, out.IPAM.Config[0].Subnet, "175.30.0.0/16") 85 86 // Create a bridge network and verify its subnet is the second default pool 87 name := "elango" + t.Name() 88 network.CreateNoError(ctx, t, c, name, 89 network.WithDriver("bridge"), 90 ) 91 out, err = c.NetworkInspect(ctx, name, types.NetworkInspectOptions{}) 92 assert.NilError(t, err) 93 assert.Equal(t, out.IPAM.Config[0].Subnet, "175.33.0.0/24") 94 95 // Create a bridge network and verify its subnet is the third default pool 96 name = "saanvi" + t.Name() 97 network.CreateNoError(ctx, t, c, name, 98 network.WithDriver("bridge"), 99 ) 100 out, err = c.NetworkInspect(ctx, name, types.NetworkInspectOptions{}) 101 assert.NilError(t, err) 102 assert.Equal(t, out.IPAM.Config[0].Subnet, "175.33.1.0/24") 103 delInterface(ctx, t, defaultNetworkBridge) 104 } 105 106 func TestDaemonRestartWithExistingNetwork(t *testing.T) { 107 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 108 skip.If(t, testEnv.IsRemoteDaemon) 109 skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "skip test from new feature") 110 skip.If(t, testEnv.IsRootless, "rootless mode has different view of network") 111 ctx := testutil.StartSpan(baseContext, t) 112 113 defaultNetworkBridge := "docker0" 114 d := daemon.New(t) 115 d.Start(t) 116 defer d.Stop(t) 117 c := d.NewClientT(t) 118 defer c.Close() 119 120 // Create a bridge network 121 name := "elango" + t.Name() 122 network.CreateNoError(ctx, t, c, name, 123 network.WithDriver("bridge"), 124 ) 125 126 // Verify bridge network's subnet 127 out, err := c.NetworkInspect(ctx, name, types.NetworkInspectOptions{}) 128 assert.NilError(t, err) 129 networkip := out.IPAM.Config[0].Subnet 130 131 // Restart daemon with default address pool option 132 d.Restart(t, 133 "--default-address-pool", "base=175.30.0.0/16,size=16", 134 "--default-address-pool", "base=175.33.0.0/16,size=24") 135 136 out1, err := c.NetworkInspect(ctx, name, types.NetworkInspectOptions{}) 137 assert.NilError(t, err) 138 assert.Equal(t, out1.IPAM.Config[0].Subnet, networkip) 139 delInterface(ctx, t, defaultNetworkBridge) 140 } 141 142 func TestDaemonRestartWithExistingNetworkWithDefaultPoolRange(t *testing.T) { 143 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 144 skip.If(t, testEnv.IsRemoteDaemon) 145 skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "skip test from new feature") 146 skip.If(t, testEnv.IsRootless, "rootless mode has different view of network") 147 148 ctx := testutil.StartSpan(baseContext, t) 149 150 defaultNetworkBridge := "docker0" 151 d := daemon.New(t) 152 d.Start(t) 153 defer d.Stop(t) 154 c := d.NewClientT(t) 155 defer c.Close() 156 157 // Create a bridge network 158 name := "elango" + t.Name() 159 network.CreateNoError(ctx, t, c, name, 160 network.WithDriver("bridge"), 161 ) 162 163 // Verify bridge network's subnet 164 out, err := c.NetworkInspect(ctx, name, types.NetworkInspectOptions{}) 165 assert.NilError(t, err) 166 networkip := out.IPAM.Config[0].Subnet 167 168 // Create a bridge network 169 name = "sthira" + t.Name() 170 network.CreateNoError(ctx, t, c, name, 171 network.WithDriver("bridge"), 172 ) 173 out, err = c.NetworkInspect(ctx, name, types.NetworkInspectOptions{}) 174 assert.NilError(t, err) 175 networkip2 := out.IPAM.Config[0].Subnet 176 177 // Restart daemon with default address pool option 178 d.Restart(t, 179 "--default-address-pool", "base=175.18.0.0/16,size=16", 180 "--default-address-pool", "base=175.19.0.0/16,size=24", 181 ) 182 183 // Create a bridge network 184 name = "saanvi" + t.Name() 185 network.CreateNoError(ctx, t, c, name, 186 network.WithDriver("bridge"), 187 ) 188 out1, err := c.NetworkInspect(ctx, name, types.NetworkInspectOptions{}) 189 assert.NilError(t, err) 190 191 assert.Check(t, out1.IPAM.Config[0].Subnet != networkip) 192 assert.Check(t, out1.IPAM.Config[0].Subnet != networkip2) 193 delInterface(ctx, t, defaultNetworkBridge) 194 } 195 196 func TestDaemonWithBipAndDefaultNetworkPool(t *testing.T) { 197 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 198 skip.If(t, testEnv.IsRemoteDaemon) 199 skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.38"), "skip test from new feature") 200 skip.If(t, testEnv.IsRootless, "rootless mode has different view of network") 201 202 ctx := testutil.StartSpan(baseContext, t) 203 204 defaultNetworkBridge := "docker0" 205 d := daemon.New(t) 206 defer d.Stop(t) 207 d.Start(t, 208 "--bip=172.60.0.1/16", 209 "--default-address-pool", "base=175.30.0.0/16,size=16", 210 "--default-address-pool", "base=175.33.0.0/16,size=24", 211 ) 212 213 c := d.NewClientT(t) 214 defer c.Close() 215 216 // Verify bridge network's subnet 217 out, err := c.NetworkInspect(ctx, "bridge", types.NetworkInspectOptions{}) 218 assert.NilError(t, err) 219 // Make sure BIP IP doesn't get override with new default address pool . 220 assert.Equal(t, out.IPAM.Config[0].Subnet, "172.60.0.0/16") 221 delInterface(ctx, t, defaultNetworkBridge) 222 } 223 224 func TestServiceWithPredefinedNetwork(t *testing.T) { 225 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 226 skip.If(t, testEnv.IsRootless, "rootless mode doesn't support Swarm-mode") 227 ctx := setupTest(t) 228 229 d := swarm.NewSwarm(ctx, t, testEnv) 230 defer d.Stop(t) 231 c := d.NewClientT(t) 232 defer c.Close() 233 234 hostName := "host" 235 var instances uint64 = 1 236 serviceName := "TestService" + t.Name() 237 238 serviceID := swarm.CreateService(ctx, t, d, 239 swarm.ServiceWithReplicas(instances), 240 swarm.ServiceWithName(serviceName), 241 swarm.ServiceWithNetwork(hostName), 242 ) 243 244 poll.WaitOn(t, swarm.RunningTasksCount(ctx, c, serviceID, instances), swarm.ServicePoll) 245 246 _, _, err := c.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{}) 247 assert.NilError(t, err) 248 249 err = c.ServiceRemove(ctx, serviceID) 250 assert.NilError(t, err) 251 } 252 253 const ingressNet = "ingress" 254 255 func TestServiceRemoveKeepsIngressNetwork(t *testing.T) { 256 t.Skip("FLAKY_TEST") 257 skip.If(t, testEnv.IsRootless, "rootless mode doesn't support Swarm-mode") 258 259 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 260 ctx := setupTest(t) 261 262 d := swarm.NewSwarm(ctx, t, testEnv) 263 defer d.Stop(t) 264 c := d.NewClientT(t) 265 defer c.Close() 266 267 poll.WaitOn(t, swarmIngressReady(ctx, c), swarm.NetworkPoll) 268 269 var instances uint64 = 1 270 271 serviceID := swarm.CreateService(ctx, t, d, 272 swarm.ServiceWithReplicas(instances), 273 swarm.ServiceWithName(t.Name()+"-service"), 274 swarm.ServiceWithEndpoint(&swarmtypes.EndpointSpec{ 275 Ports: []swarmtypes.PortConfig{ 276 { 277 Protocol: swarmtypes.PortConfigProtocolTCP, 278 TargetPort: 80, 279 PublishMode: swarmtypes.PortConfigPublishModeIngress, 280 }, 281 }, 282 }), 283 ) 284 285 poll.WaitOn(t, swarm.RunningTasksCount(ctx, c, serviceID, instances), swarm.ServicePoll) 286 287 _, _, err := c.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{}) 288 assert.NilError(t, err) 289 290 err = c.ServiceRemove(ctx, serviceID) 291 assert.NilError(t, err) 292 293 poll.WaitOn(t, noServices(ctx, c), swarm.ServicePoll) 294 poll.WaitOn(t, swarm.NoTasks(ctx, c), swarm.ServicePoll) 295 296 // Ensure that "ingress" is not removed or corrupted 297 time.Sleep(10 * time.Second) 298 netInfo, err := c.NetworkInspect(ctx, ingressNet, types.NetworkInspectOptions{ 299 Verbose: true, 300 Scope: "swarm", 301 }) 302 assert.NilError(t, err, "Ingress network was removed after removing service!") 303 assert.Assert(t, len(netInfo.Containers) != 0, "No load balancing endpoints in ingress network") 304 assert.Assert(t, len(netInfo.Peers) != 0, "No peers (including self) in ingress network") 305 _, ok := netInfo.Containers["ingress-sbox"] 306 assert.Assert(t, ok, "ingress-sbox not present in ingress network") 307 } 308 309 //nolint:unused // for some reason, the "unused" linter marks this function as "unused" 310 func swarmIngressReady(ctx context.Context, client client.NetworkAPIClient) func(log poll.LogT) poll.Result { 311 return func(log poll.LogT) poll.Result { 312 netInfo, err := client.NetworkInspect(ctx, ingressNet, types.NetworkInspectOptions{ 313 Verbose: true, 314 Scope: "swarm", 315 }) 316 if err != nil { 317 return poll.Error(err) 318 } 319 np := len(netInfo.Peers) 320 nc := len(netInfo.Containers) 321 if np == 0 || nc == 0 { 322 return poll.Continue("ingress not ready: %d peers and %d containers", nc, np) 323 } 324 _, ok := netInfo.Containers["ingress-sbox"] 325 if !ok { 326 return poll.Continue("ingress not ready: does not contain the ingress-sbox") 327 } 328 return poll.Success() 329 } 330 } 331 332 func noServices(ctx context.Context, client client.ServiceAPIClient) func(log poll.LogT) poll.Result { 333 return func(log poll.LogT) poll.Result { 334 services, err := client.ServiceList(ctx, types.ServiceListOptions{}) 335 switch { 336 case err != nil: 337 return poll.Error(err) 338 case len(services) == 0: 339 return poll.Success() 340 default: 341 return poll.Continue("waiting for all services to be removed: service count at %d", len(services)) 342 } 343 } 344 } 345 346 func TestServiceWithDataPathPortInit(t *testing.T) { 347 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 348 skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.40"), "DataPathPort was added in API v1.40") 349 skip.If(t, testEnv.IsRootless, "rootless mode doesn't support Swarm-mode") 350 ctx := setupTest(t) 351 352 var datapathPort uint32 = 7777 353 d := swarm.NewSwarm(ctx, t, testEnv, daemon.WithSwarmDataPathPort(datapathPort)) 354 c := d.NewClientT(t) 355 // Create a overlay network 356 name := "saanvisthira" + t.Name() 357 overlayID := network.CreateNoError(ctx, t, c, name, 358 network.WithDriver("overlay")) 359 360 var instances uint64 = 1 361 serviceID := swarm.CreateService(ctx, t, d, 362 swarm.ServiceWithReplicas(instances), 363 swarm.ServiceWithName(name), 364 swarm.ServiceWithNetwork(name), 365 ) 366 367 poll.WaitOn(t, swarm.RunningTasksCount(ctx, c, serviceID, instances), swarm.ServicePoll) 368 369 info := d.Info(t) 370 assert.Equal(t, info.Swarm.Cluster.DataPathPort, datapathPort) 371 err := c.ServiceRemove(ctx, serviceID) 372 assert.NilError(t, err) 373 poll.WaitOn(t, noServices(ctx, c), swarm.ServicePoll) 374 poll.WaitOn(t, swarm.NoTasks(ctx, c), swarm.ServicePoll) 375 err = c.NetworkRemove(ctx, overlayID) 376 assert.NilError(t, err) 377 c.Close() 378 err = d.SwarmLeave(ctx, t, true) 379 assert.NilError(t, err) 380 d.Stop(t) 381 382 // Clean up , set it back to original one to make sure other tests don't fail 383 // call without datapath port option. 384 d = swarm.NewSwarm(ctx, t, testEnv) 385 defer d.Stop(t) 386 nc := d.NewClientT(t) 387 defer nc.Close() 388 // Create a overlay network 389 name = "not-saanvisthira" + t.Name() 390 overlayID = network.CreateNoError(ctx, t, nc, name, 391 network.WithDriver("overlay")) 392 393 serviceID = swarm.CreateService(ctx, t, d, 394 swarm.ServiceWithReplicas(instances), 395 swarm.ServiceWithName(name), 396 swarm.ServiceWithNetwork(name), 397 ) 398 399 poll.WaitOn(t, swarm.RunningTasksCount(ctx, nc, serviceID, instances), swarm.ServicePoll) 400 401 info = d.Info(t) 402 var defaultDataPathPort uint32 = 4789 403 assert.Equal(t, info.Swarm.Cluster.DataPathPort, defaultDataPathPort) 404 err = nc.ServiceRemove(ctx, serviceID) 405 assert.NilError(t, err) 406 poll.WaitOn(t, noServices(ctx, nc), swarm.ServicePoll) 407 poll.WaitOn(t, swarm.NoTasks(ctx, nc), swarm.ServicePoll) 408 err = nc.NetworkRemove(ctx, overlayID) 409 assert.NilError(t, err) 410 err = d.SwarmLeave(ctx, t, true) 411 assert.NilError(t, err) 412 } 413 414 func TestServiceWithDefaultAddressPoolInit(t *testing.T) { 415 skip.If(t, testEnv.DaemonInfo.OSType == "windows") 416 skip.If(t, testEnv.IsRootless, "rootless mode doesn't support Swarm-mode") 417 ctx := setupTest(t) 418 419 d := swarm.NewSwarm(ctx, t, testEnv, 420 daemon.WithSwarmDefaultAddrPool([]string{"20.20.0.0/16"}), 421 daemon.WithSwarmDefaultAddrPoolSubnetSize(24)) 422 defer d.Stop(t) 423 cli := d.NewClientT(t) 424 defer cli.Close() 425 426 // Create a overlay network 427 name := "sthira" + t.Name() 428 overlayID := network.CreateNoError(ctx, t, cli, name, 429 network.WithDriver("overlay"), 430 ) 431 432 var instances uint64 = 1 433 serviceName := "TestService" + t.Name() 434 serviceID := swarm.CreateService(ctx, t, d, 435 swarm.ServiceWithReplicas(instances), 436 swarm.ServiceWithName(serviceName), 437 swarm.ServiceWithNetwork(name), 438 ) 439 440 poll.WaitOn(t, swarm.RunningTasksCount(ctx, cli, serviceID, instances), swarm.ServicePoll) 441 442 _, _, err := cli.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{}) 443 assert.NilError(t, err) 444 445 out, err := cli.NetworkInspect(ctx, overlayID, types.NetworkInspectOptions{Verbose: true}) 446 assert.NilError(t, err) 447 t.Logf("%s: NetworkInspect: %+v", t.Name(), out) 448 assert.Assert(t, len(out.IPAM.Config) > 0) 449 // As of docker/swarmkit#2890, the ingress network uses the default address 450 // pool (whereas before, the subnet for the ingress network was hard-coded. 451 // This means that the ingress network gets the subnet 20.20.0.0/24, and 452 // the network we just created gets subnet 20.20.1.0/24. 453 assert.Equal(t, out.IPAM.Config[0].Subnet, "20.20.1.0/24") 454 455 // Also inspect ingress network and make sure its in the same subnet 456 out, err = cli.NetworkInspect(ctx, "ingress", types.NetworkInspectOptions{Verbose: true}) 457 assert.NilError(t, err) 458 assert.Assert(t, len(out.IPAM.Config) > 0) 459 assert.Equal(t, out.IPAM.Config[0].Subnet, "20.20.0.0/24") 460 461 err = cli.ServiceRemove(ctx, serviceID) 462 poll.WaitOn(t, noServices(ctx, cli), swarm.ServicePoll) 463 poll.WaitOn(t, swarm.NoTasks(ctx, cli), swarm.ServicePoll) 464 assert.NilError(t, err) 465 err = cli.NetworkRemove(ctx, overlayID) 466 assert.NilError(t, err) 467 err = d.SwarmLeave(ctx, t, true) 468 assert.NilError(t, err) 469 }