github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/integration/network/service_test.go (about)

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