github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/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  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  //nolint:unused // for some reason, the "unused" linter marks this function as "unused"
   296  func swarmIngressReady(client client.NetworkAPIClient) func(log poll.LogT) poll.Result {
   297  	return func(log poll.LogT) poll.Result {
   298  		netInfo, err := client.NetworkInspect(context.Background(), ingressNet, types.NetworkInspectOptions{
   299  			Verbose: true,
   300  			Scope:   "swarm",
   301  		})
   302  		if err != nil {
   303  			return poll.Error(err)
   304  		}
   305  		np := len(netInfo.Peers)
   306  		nc := len(netInfo.Containers)
   307  		if np == 0 || nc == 0 {
   308  			return poll.Continue("ingress not ready: %d peers and %d containers", nc, np)
   309  		}
   310  		_, ok := netInfo.Containers["ingress-sbox"]
   311  		if !ok {
   312  			return poll.Continue("ingress not ready: does not contain the ingress-sbox")
   313  		}
   314  		return poll.Success()
   315  	}
   316  }
   317  
   318  func noServices(ctx context.Context, client client.ServiceAPIClient) func(log poll.LogT) poll.Result {
   319  	return func(log poll.LogT) poll.Result {
   320  		services, err := client.ServiceList(ctx, types.ServiceListOptions{})
   321  		switch {
   322  		case err != nil:
   323  			return poll.Error(err)
   324  		case len(services) == 0:
   325  			return poll.Success()
   326  		default:
   327  			return poll.Continue("waiting for all services to be removed: service count at %d", len(services))
   328  		}
   329  	}
   330  }
   331  
   332  func TestServiceWithDataPathPortInit(t *testing.T) {
   333  	skip.If(t, testEnv.OSType == "windows")
   334  	skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.40"), "DataPathPort was added in API v1.40")
   335  	skip.If(t, testEnv.IsRootless, "rootless mode doesn't support Swarm-mode")
   336  	defer setupTest(t)()
   337  	var datapathPort uint32 = 7777
   338  	d := swarm.NewSwarm(t, testEnv, daemon.WithSwarmDataPathPort(datapathPort))
   339  	c := d.NewClientT(t)
   340  	ctx := context.Background()
   341  	// Create a overlay network
   342  	name := "saanvisthira" + t.Name()
   343  	overlayID := network.CreateNoError(context.Background(), t, c, name,
   344  		network.WithDriver("overlay"))
   345  
   346  	var instances uint64 = 1
   347  	serviceID := swarm.CreateService(t, d,
   348  		swarm.ServiceWithReplicas(instances),
   349  		swarm.ServiceWithName(name),
   350  		swarm.ServiceWithNetwork(name),
   351  	)
   352  
   353  	poll.WaitOn(t, swarm.RunningTasksCount(c, serviceID, instances), swarm.ServicePoll)
   354  
   355  	info := d.Info(t)
   356  	assert.Equal(t, info.Swarm.Cluster.DataPathPort, datapathPort)
   357  	err := c.ServiceRemove(ctx, serviceID)
   358  	assert.NilError(t, err)
   359  	poll.WaitOn(t, noServices(ctx, c), swarm.ServicePoll)
   360  	poll.WaitOn(t, swarm.NoTasks(ctx, c), swarm.ServicePoll)
   361  	err = c.NetworkRemove(ctx, overlayID)
   362  	assert.NilError(t, err)
   363  	c.Close()
   364  	err = d.SwarmLeave(t, true)
   365  	assert.NilError(t, err)
   366  	d.Stop(t)
   367  
   368  	// Clean up , set it back to original one to make sure other tests don't fail
   369  	// call without datapath port option.
   370  	d = swarm.NewSwarm(t, testEnv)
   371  	defer d.Stop(t)
   372  	nc := d.NewClientT(t)
   373  	defer nc.Close()
   374  	// Create a overlay network
   375  	name = "not-saanvisthira" + t.Name()
   376  	overlayID = network.CreateNoError(ctx, t, nc, name,
   377  		network.WithDriver("overlay"))
   378  
   379  	serviceID = swarm.CreateService(t, d,
   380  		swarm.ServiceWithReplicas(instances),
   381  		swarm.ServiceWithName(name),
   382  		swarm.ServiceWithNetwork(name),
   383  	)
   384  
   385  	poll.WaitOn(t, swarm.RunningTasksCount(nc, serviceID, instances), swarm.ServicePoll)
   386  
   387  	info = d.Info(t)
   388  	var defaultDataPathPort uint32 = 4789
   389  	assert.Equal(t, info.Swarm.Cluster.DataPathPort, defaultDataPathPort)
   390  	err = nc.ServiceRemove(ctx, serviceID)
   391  	assert.NilError(t, err)
   392  	poll.WaitOn(t, noServices(ctx, nc), swarm.ServicePoll)
   393  	poll.WaitOn(t, swarm.NoTasks(ctx, nc), swarm.ServicePoll)
   394  	err = nc.NetworkRemove(ctx, overlayID)
   395  	assert.NilError(t, err)
   396  	err = d.SwarmLeave(t, true)
   397  	assert.NilError(t, err)
   398  }
   399  
   400  func TestServiceWithDefaultAddressPoolInit(t *testing.T) {
   401  	skip.If(t, testEnv.OSType == "windows")
   402  	skip.If(t, testEnv.IsRootless, "rootless mode doesn't support Swarm-mode")
   403  	defer setupTest(t)()
   404  	d := swarm.NewSwarm(t, testEnv,
   405  		daemon.WithSwarmDefaultAddrPool([]string{"20.20.0.0/16"}),
   406  		daemon.WithSwarmDefaultAddrPoolSubnetSize(24))
   407  	defer d.Stop(t)
   408  	cli := d.NewClientT(t)
   409  	defer cli.Close()
   410  	ctx := context.Background()
   411  
   412  	// Create a overlay network
   413  	name := "sthira" + t.Name()
   414  	overlayID := network.CreateNoError(ctx, t, cli, name,
   415  		network.WithDriver("overlay"),
   416  		network.WithCheckDuplicate(),
   417  	)
   418  
   419  	var instances uint64 = 1
   420  	serviceName := "TestService" + t.Name()
   421  	serviceID := swarm.CreateService(t, d,
   422  		swarm.ServiceWithReplicas(instances),
   423  		swarm.ServiceWithName(serviceName),
   424  		swarm.ServiceWithNetwork(name),
   425  	)
   426  
   427  	poll.WaitOn(t, swarm.RunningTasksCount(cli, serviceID, instances), swarm.ServicePoll)
   428  
   429  	_, _, err := cli.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
   430  	assert.NilError(t, err)
   431  
   432  	out, err := cli.NetworkInspect(ctx, overlayID, types.NetworkInspectOptions{Verbose: true})
   433  	assert.NilError(t, err)
   434  	t.Logf("%s: NetworkInspect: %+v", t.Name(), out)
   435  	assert.Assert(t, len(out.IPAM.Config) > 0)
   436  	// As of docker/swarmkit#2890, the ingress network uses the default address
   437  	// pool (whereas before, the subnet for the ingress network was hard-coded.
   438  	// This means that the ingress network gets the subnet 20.20.0.0/24, and
   439  	// the network we just created gets subnet 20.20.1.0/24.
   440  	assert.Equal(t, out.IPAM.Config[0].Subnet, "20.20.1.0/24")
   441  
   442  	// Also inspect ingress network and make sure its in the same subnet
   443  	out, err = cli.NetworkInspect(ctx, "ingress", types.NetworkInspectOptions{Verbose: true})
   444  	assert.NilError(t, err)
   445  	assert.Assert(t, len(out.IPAM.Config) > 0)
   446  	assert.Equal(t, out.IPAM.Config[0].Subnet, "20.20.0.0/24")
   447  
   448  	err = cli.ServiceRemove(ctx, serviceID)
   449  	poll.WaitOn(t, noServices(ctx, cli), swarm.ServicePoll)
   450  	poll.WaitOn(t, swarm.NoTasks(ctx, cli), swarm.ServicePoll)
   451  	assert.NilError(t, err)
   452  	err = cli.NetworkRemove(ctx, overlayID)
   453  	assert.NilError(t, err)
   454  	err = d.SwarmLeave(t, true)
   455  	assert.NilError(t, err)
   456  }