github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/integration/service/create_test.go (about)

     1  package service // import "github.com/docker/docker/integration/service"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/docker/docker/api/types"
    11  	"github.com/docker/docker/api/types/filters"
    12  	swarmtypes "github.com/docker/docker/api/types/swarm"
    13  	"github.com/docker/docker/api/types/versions"
    14  	"github.com/docker/docker/client"
    15  	"github.com/docker/docker/errdefs"
    16  	"github.com/docker/docker/integration/internal/network"
    17  	"github.com/docker/docker/integration/internal/swarm"
    18  	"github.com/docker/docker/internal/test/daemon"
    19  	"gotest.tools/assert"
    20  	is "gotest.tools/assert/cmp"
    21  	"gotest.tools/poll"
    22  	"gotest.tools/skip"
    23  )
    24  
    25  func TestServiceCreateInit(t *testing.T) {
    26  	defer setupTest(t)()
    27  	t.Run("daemonInitDisabled", testServiceCreateInit(false))
    28  	t.Run("daemonInitEnabled", testServiceCreateInit(true))
    29  }
    30  
    31  func testServiceCreateInit(daemonEnabled bool) func(t *testing.T) {
    32  	return func(t *testing.T) {
    33  		var ops = []func(*daemon.Daemon){}
    34  
    35  		if daemonEnabled {
    36  			ops = append(ops, daemon.WithInit)
    37  		}
    38  		d := swarm.NewSwarm(t, testEnv, ops...)
    39  		defer d.Stop(t)
    40  		client := d.NewClientT(t)
    41  		defer client.Close()
    42  
    43  		booleanTrue := true
    44  		booleanFalse := false
    45  
    46  		serviceID := swarm.CreateService(t, d)
    47  		poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
    48  		i := inspectServiceContainer(t, client, serviceID)
    49  		// HostConfig.Init == nil means that it delegates to daemon configuration
    50  		assert.Check(t, i.HostConfig.Init == nil)
    51  
    52  		serviceID = swarm.CreateService(t, d, swarm.ServiceWithInit(&booleanTrue))
    53  		poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
    54  		i = inspectServiceContainer(t, client, serviceID)
    55  		assert.Check(t, is.Equal(true, *i.HostConfig.Init))
    56  
    57  		serviceID = swarm.CreateService(t, d, swarm.ServiceWithInit(&booleanFalse))
    58  		poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, 1), swarm.ServicePoll)
    59  		i = inspectServiceContainer(t, client, serviceID)
    60  		assert.Check(t, is.Equal(false, *i.HostConfig.Init))
    61  	}
    62  }
    63  
    64  func inspectServiceContainer(t *testing.T, client client.APIClient, serviceID string) types.ContainerJSON {
    65  	t.Helper()
    66  	filter := filters.NewArgs()
    67  	filter.Add("label", fmt.Sprintf("com.docker.swarm.service.id=%s", serviceID))
    68  	containers, err := client.ContainerList(context.Background(), types.ContainerListOptions{Filters: filter})
    69  	assert.NilError(t, err)
    70  	assert.Check(t, is.Len(containers, 1))
    71  
    72  	i, err := client.ContainerInspect(context.Background(), containers[0].ID)
    73  	assert.NilError(t, err)
    74  	return i
    75  }
    76  
    77  func TestCreateServiceMultipleTimes(t *testing.T) {
    78  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
    79  	defer setupTest(t)()
    80  	d := swarm.NewSwarm(t, testEnv)
    81  	defer d.Stop(t)
    82  	client := d.NewClientT(t)
    83  	defer client.Close()
    84  	ctx := context.Background()
    85  
    86  	overlayName := "overlay1_" + t.Name()
    87  	overlayID := network.CreateNoError(t, ctx, client, overlayName,
    88  		network.WithCheckDuplicate(),
    89  		network.WithDriver("overlay"),
    90  	)
    91  
    92  	var instances uint64 = 4
    93  
    94  	serviceName := "TestService_" + t.Name()
    95  	serviceSpec := []swarm.ServiceSpecOpt{
    96  		swarm.ServiceWithReplicas(instances),
    97  		swarm.ServiceWithName(serviceName),
    98  		swarm.ServiceWithNetwork(overlayName),
    99  	}
   100  
   101  	serviceID := swarm.CreateService(t, d, serviceSpec...)
   102  	poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, instances), swarm.ServicePoll)
   103  
   104  	_, _, err := client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
   105  	assert.NilError(t, err)
   106  
   107  	err = client.ServiceRemove(context.Background(), serviceID)
   108  	assert.NilError(t, err)
   109  
   110  	poll.WaitOn(t, swarm.NoTasksForService(ctx, client, serviceID), swarm.ServicePoll)
   111  
   112  	serviceID2 := swarm.CreateService(t, d, serviceSpec...)
   113  	poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID2, instances), swarm.ServicePoll)
   114  
   115  	err = client.ServiceRemove(context.Background(), serviceID2)
   116  	assert.NilError(t, err)
   117  
   118  	poll.WaitOn(t, swarm.NoTasksForService(ctx, client, serviceID2), swarm.ServicePoll)
   119  
   120  	err = client.NetworkRemove(context.Background(), overlayID)
   121  	assert.NilError(t, err)
   122  
   123  	poll.WaitOn(t, network.IsRemoved(context.Background(), client, overlayID), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
   124  }
   125  
   126  func TestCreateServiceConflict(t *testing.T) {
   127  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
   128  	defer setupTest(t)()
   129  	d := swarm.NewSwarm(t, testEnv)
   130  	defer d.Stop(t)
   131  	c := d.NewClientT(t)
   132  	defer c.Close()
   133  	ctx := context.Background()
   134  
   135  	serviceName := "TestService_" + t.Name()
   136  	serviceSpec := []swarm.ServiceSpecOpt{
   137  		swarm.ServiceWithName(serviceName),
   138  	}
   139  
   140  	swarm.CreateService(t, d, serviceSpec...)
   141  
   142  	spec := swarm.CreateServiceSpec(t, serviceSpec...)
   143  	_, err := c.ServiceCreate(ctx, spec, types.ServiceCreateOptions{})
   144  	assert.Check(t, errdefs.IsConflict(err))
   145  	assert.ErrorContains(t, err, "service "+serviceName+" already exists")
   146  }
   147  
   148  func TestCreateServiceMaxReplicas(t *testing.T) {
   149  	defer setupTest(t)()
   150  	d := swarm.NewSwarm(t, testEnv)
   151  	defer d.Stop(t)
   152  	client := d.NewClientT(t)
   153  	defer client.Close()
   154  
   155  	var maxReplicas uint64 = 2
   156  	serviceSpec := []swarm.ServiceSpecOpt{
   157  		swarm.ServiceWithReplicas(maxReplicas),
   158  		swarm.ServiceWithMaxReplicas(maxReplicas),
   159  	}
   160  
   161  	serviceID := swarm.CreateService(t, d, serviceSpec...)
   162  	poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, maxReplicas), swarm.ServicePoll)
   163  
   164  	_, _, err := client.ServiceInspectWithRaw(context.Background(), serviceID, types.ServiceInspectOptions{})
   165  	assert.NilError(t, err)
   166  }
   167  
   168  func TestCreateWithDuplicateNetworkNames(t *testing.T) {
   169  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
   170  	defer setupTest(t)()
   171  	d := swarm.NewSwarm(t, testEnv)
   172  	defer d.Stop(t)
   173  	client := d.NewClientT(t)
   174  	defer client.Close()
   175  	ctx := context.Background()
   176  
   177  	name := "foo_" + t.Name()
   178  	n1 := network.CreateNoError(t, ctx, client, name, network.WithDriver("bridge"))
   179  	n2 := network.CreateNoError(t, ctx, client, name, network.WithDriver("bridge"))
   180  
   181  	// Duplicates with name but with different driver
   182  	n3 := network.CreateNoError(t, ctx, client, name, network.WithDriver("overlay"))
   183  
   184  	// Create Service with the same name
   185  	var instances uint64 = 1
   186  
   187  	serviceName := "top_" + t.Name()
   188  	serviceID := swarm.CreateService(t, d,
   189  		swarm.ServiceWithReplicas(instances),
   190  		swarm.ServiceWithName(serviceName),
   191  		swarm.ServiceWithNetwork(name),
   192  	)
   193  
   194  	poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, instances), swarm.ServicePoll)
   195  
   196  	resp, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
   197  	assert.NilError(t, err)
   198  	assert.Check(t, is.Equal(n3, resp.Spec.TaskTemplate.Networks[0].Target))
   199  
   200  	// Remove Service, and wait for its tasks to be removed
   201  	err = client.ServiceRemove(ctx, serviceID)
   202  	assert.NilError(t, err)
   203  	poll.WaitOn(t, swarm.NoTasksForService(ctx, client, serviceID), swarm.ServicePoll)
   204  
   205  	// Remove networks
   206  	err = client.NetworkRemove(context.Background(), n3)
   207  	assert.NilError(t, err)
   208  
   209  	err = client.NetworkRemove(context.Background(), n2)
   210  	assert.NilError(t, err)
   211  
   212  	err = client.NetworkRemove(context.Background(), n1)
   213  	assert.NilError(t, err)
   214  
   215  	// Make sure networks have been destroyed.
   216  	poll.WaitOn(t, network.IsRemoved(context.Background(), client, n3), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
   217  	poll.WaitOn(t, network.IsRemoved(context.Background(), client, n2), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
   218  	poll.WaitOn(t, network.IsRemoved(context.Background(), client, n1), poll.WithTimeout(1*time.Minute), poll.WithDelay(10*time.Second))
   219  }
   220  
   221  func TestCreateServiceSecretFileMode(t *testing.T) {
   222  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
   223  	defer setupTest(t)()
   224  	d := swarm.NewSwarm(t, testEnv)
   225  	defer d.Stop(t)
   226  	client := d.NewClientT(t)
   227  	defer client.Close()
   228  
   229  	ctx := context.Background()
   230  	secretName := "TestSecret_" + t.Name()
   231  	secretResp, err := client.SecretCreate(ctx, swarmtypes.SecretSpec{
   232  		Annotations: swarmtypes.Annotations{
   233  			Name: secretName,
   234  		},
   235  		Data: []byte("TESTSECRET"),
   236  	})
   237  	assert.NilError(t, err)
   238  
   239  	var instances uint64 = 1
   240  	serviceName := "TestService_" + t.Name()
   241  	serviceID := swarm.CreateService(t, d,
   242  		swarm.ServiceWithReplicas(instances),
   243  		swarm.ServiceWithName(serviceName),
   244  		swarm.ServiceWithCommand([]string{"/bin/sh", "-c", "ls -l /etc/secret || /bin/top"}),
   245  		swarm.ServiceWithSecret(&swarmtypes.SecretReference{
   246  			File: &swarmtypes.SecretReferenceFileTarget{
   247  				Name: "/etc/secret",
   248  				UID:  "0",
   249  				GID:  "0",
   250  				Mode: 0777,
   251  			},
   252  			SecretID:   secretResp.ID,
   253  			SecretName: secretName,
   254  		}),
   255  	)
   256  
   257  	poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, instances), swarm.ServicePoll)
   258  
   259  	filter := filters.NewArgs()
   260  	filter.Add("service", serviceID)
   261  	tasks, err := client.TaskList(ctx, types.TaskListOptions{
   262  		Filters: filter,
   263  	})
   264  	assert.NilError(t, err)
   265  	assert.Check(t, is.Equal(len(tasks), 1))
   266  
   267  	body, err := client.ContainerLogs(ctx, tasks[0].Status.ContainerStatus.ContainerID, types.ContainerLogsOptions{
   268  		ShowStdout: true,
   269  	})
   270  	assert.NilError(t, err)
   271  	defer body.Close()
   272  
   273  	content, err := ioutil.ReadAll(body)
   274  	assert.NilError(t, err)
   275  	assert.Check(t, is.Contains(string(content), "-rwxrwxrwx"))
   276  
   277  	err = client.ServiceRemove(ctx, serviceID)
   278  	assert.NilError(t, err)
   279  	poll.WaitOn(t, swarm.NoTasksForService(ctx, client, serviceID), swarm.ServicePoll)
   280  
   281  	err = client.SecretRemove(ctx, secretName)
   282  	assert.NilError(t, err)
   283  }
   284  
   285  func TestCreateServiceConfigFileMode(t *testing.T) {
   286  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
   287  	defer setupTest(t)()
   288  	d := swarm.NewSwarm(t, testEnv)
   289  	defer d.Stop(t)
   290  	client := d.NewClientT(t)
   291  	defer client.Close()
   292  
   293  	ctx := context.Background()
   294  	configName := "TestConfig_" + t.Name()
   295  	configResp, err := client.ConfigCreate(ctx, swarmtypes.ConfigSpec{
   296  		Annotations: swarmtypes.Annotations{
   297  			Name: configName,
   298  		},
   299  		Data: []byte("TESTCONFIG"),
   300  	})
   301  	assert.NilError(t, err)
   302  
   303  	var instances uint64 = 1
   304  	serviceName := "TestService_" + t.Name()
   305  	serviceID := swarm.CreateService(t, d,
   306  		swarm.ServiceWithName(serviceName),
   307  		swarm.ServiceWithCommand([]string{"/bin/sh", "-c", "ls -l /etc/config || /bin/top"}),
   308  		swarm.ServiceWithReplicas(instances),
   309  		swarm.ServiceWithConfig(&swarmtypes.ConfigReference{
   310  			File: &swarmtypes.ConfigReferenceFileTarget{
   311  				Name: "/etc/config",
   312  				UID:  "0",
   313  				GID:  "0",
   314  				Mode: 0777,
   315  			},
   316  			ConfigID:   configResp.ID,
   317  			ConfigName: configName,
   318  		}),
   319  	)
   320  
   321  	poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, instances))
   322  
   323  	filter := filters.NewArgs()
   324  	filter.Add("service", serviceID)
   325  	tasks, err := client.TaskList(ctx, types.TaskListOptions{
   326  		Filters: filter,
   327  	})
   328  	assert.NilError(t, err)
   329  	assert.Check(t, is.Equal(len(tasks), 1))
   330  
   331  	body, err := client.ContainerLogs(ctx, tasks[0].Status.ContainerStatus.ContainerID, types.ContainerLogsOptions{
   332  		ShowStdout: true,
   333  	})
   334  	assert.NilError(t, err)
   335  	defer body.Close()
   336  
   337  	content, err := ioutil.ReadAll(body)
   338  	assert.NilError(t, err)
   339  	assert.Check(t, is.Contains(string(content), "-rwxrwxrwx"))
   340  
   341  	err = client.ServiceRemove(ctx, serviceID)
   342  	assert.NilError(t, err)
   343  	poll.WaitOn(t, swarm.NoTasksForService(ctx, client, serviceID))
   344  
   345  	err = client.ConfigRemove(ctx, configName)
   346  	assert.NilError(t, err)
   347  }
   348  
   349  // TestServiceCreateSysctls tests that a service created with sysctl options in
   350  // the ContainerSpec correctly applies those options.
   351  //
   352  // To test this, we're going to create a service with the sysctl option
   353  //
   354  //   {"net.ipv4.ip_nonlocal_bind": "0"}
   355  //
   356  // We'll get the service's tasks to get the container ID, and then we'll
   357  // inspect the container. If the output of the container inspect contains the
   358  // sysctl option with the correct value, we can assume that the sysctl has been
   359  // plumbed correctly.
   360  //
   361  // Next, we'll remove that service and create a new service with that option
   362  // set to 1. This means that no matter what the default is, we can be confident
   363  // that the sysctl option is applying as intended.
   364  //
   365  // Additionally, we'll do service and task inspects to verify that the inspect
   366  // output includes the desired sysctl option.
   367  //
   368  // We're using net.ipv4.ip_nonlocal_bind because it's something that I'm fairly
   369  // confident won't be modified by the container runtime, and won't blow
   370  // anything up in the test environment
   371  func TestCreateServiceSysctls(t *testing.T) {
   372  	skip.If(
   373  		t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.40"),
   374  		"setting service sysctls is unsupported before api v1.40",
   375  	)
   376  
   377  	defer setupTest(t)()
   378  	d := swarm.NewSwarm(t, testEnv)
   379  	defer d.Stop(t)
   380  	client := d.NewClientT(t)
   381  	defer client.Close()
   382  
   383  	ctx := context.Background()
   384  
   385  	// run thie block twice, so that no matter what the default value of
   386  	// net.ipv4.ip_nonlocal_bind is, we can verify that setting the sysctl
   387  	// options works
   388  	for _, expected := range []string{"0", "1"} {
   389  
   390  		// store the map we're going to be using everywhere.
   391  		expectedSysctls := map[string]string{"net.ipv4.ip_nonlocal_bind": expected}
   392  
   393  		// Create the service with the sysctl options
   394  		var instances uint64 = 1
   395  		serviceID := swarm.CreateService(t, d,
   396  			swarm.ServiceWithSysctls(expectedSysctls),
   397  		)
   398  
   399  		// wait for the service to converge to 1 running task as expected
   400  		poll.WaitOn(t, swarm.RunningTasksCount(client, serviceID, instances))
   401  
   402  		// we're going to check 3 things:
   403  		//
   404  		//   1. Does the container, when inspected, have the sysctl option set?
   405  		//   2. Does the task have the sysctl in the spec?
   406  		//   3. Does the service have the sysctl in the spec?
   407  		//
   408  		// if all 3 of these things are true, we know that the sysctl has been
   409  		// plumbed correctly through the engine.
   410  		//
   411  		// We don't actually have to get inside the container and check its
   412  		// logs or anything. If we see the sysctl set on the container inspect,
   413  		// we know that the sysctl is plumbed correctly. everything below that
   414  		// level has been tested elsewhere. (thanks @thaJeztah, because an
   415  		// earlier version of this test had to get container logs and was much
   416  		// more complex)
   417  
   418  		// get all of the tasks of the service, so we can get the container
   419  		filter := filters.NewArgs()
   420  		filter.Add("service", serviceID)
   421  		tasks, err := client.TaskList(ctx, types.TaskListOptions{
   422  			Filters: filter,
   423  		})
   424  		assert.NilError(t, err)
   425  		assert.Check(t, is.Equal(len(tasks), 1))
   426  
   427  		// verify that the container has the sysctl option set
   428  		ctnr, err := client.ContainerInspect(ctx, tasks[0].Status.ContainerStatus.ContainerID)
   429  		assert.NilError(t, err)
   430  		assert.DeepEqual(t, ctnr.HostConfig.Sysctls, expectedSysctls)
   431  
   432  		// verify that the task has the sysctl option set in the task object
   433  		assert.DeepEqual(t, tasks[0].Spec.ContainerSpec.Sysctls, expectedSysctls)
   434  
   435  		// verify that the service also has the sysctl set in the spec.
   436  		service, _, err := client.ServiceInspectWithRaw(ctx, serviceID, types.ServiceInspectOptions{})
   437  		assert.NilError(t, err)
   438  		assert.DeepEqual(t,
   439  			service.Spec.TaskTemplate.ContainerSpec.Sysctls, expectedSysctls,
   440  		)
   441  	}
   442  }