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