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  }