github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/integration-cli/docker_cli_service_create_test.go (about)

     1  // +build !windows
     2  
     3  package main
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"github.com/docker/docker/api/types"
    12  	"github.com/docker/docker/api/types/mount"
    13  	"github.com/docker/docker/api/types/swarm"
    14  	"github.com/docker/docker/integration-cli/checker"
    15  	"github.com/go-check/check"
    16  )
    17  
    18  func (s *DockerSwarmSuite) TestServiceCreateMountVolume(c *check.C) {
    19  	d := s.AddDaemon(c, true, true)
    20  	out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--mount", "type=volume,source=foo,target=/foo,volume-nocopy", "busybox", "top")
    21  	c.Assert(err, checker.IsNil, check.Commentf(out))
    22  	id := strings.TrimSpace(out)
    23  
    24  	var tasks []swarm.Task
    25  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
    26  		tasks = d.GetServiceTasks(c, id)
    27  		return len(tasks) > 0, nil
    28  	}, checker.Equals, true)
    29  
    30  	task := tasks[0]
    31  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
    32  		if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" {
    33  			task = d.GetTask(c, task.ID)
    34  		}
    35  		return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil
    36  	}, checker.Equals, true)
    37  
    38  	// check container mount config
    39  	out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .HostConfig.Mounts}}", task.Status.ContainerStatus.ContainerID)
    40  	c.Assert(err, checker.IsNil, check.Commentf(out))
    41  
    42  	var mountConfig []mount.Mount
    43  	c.Assert(json.Unmarshal([]byte(out), &mountConfig), checker.IsNil)
    44  	c.Assert(mountConfig, checker.HasLen, 1)
    45  
    46  	c.Assert(mountConfig[0].Source, checker.Equals, "foo")
    47  	c.Assert(mountConfig[0].Target, checker.Equals, "/foo")
    48  	c.Assert(mountConfig[0].Type, checker.Equals, mount.TypeVolume)
    49  	c.Assert(mountConfig[0].VolumeOptions, checker.NotNil)
    50  	c.Assert(mountConfig[0].VolumeOptions.NoCopy, checker.True)
    51  
    52  	// check container mounts actual
    53  	out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .Mounts}}", task.Status.ContainerStatus.ContainerID)
    54  	c.Assert(err, checker.IsNil, check.Commentf(out))
    55  
    56  	var mounts []types.MountPoint
    57  	c.Assert(json.Unmarshal([]byte(out), &mounts), checker.IsNil)
    58  	c.Assert(mounts, checker.HasLen, 1)
    59  
    60  	c.Assert(mounts[0].Type, checker.Equals, mount.TypeVolume)
    61  	c.Assert(mounts[0].Name, checker.Equals, "foo")
    62  	c.Assert(mounts[0].Destination, checker.Equals, "/foo")
    63  	c.Assert(mounts[0].RW, checker.Equals, true)
    64  }
    65  
    66  func (s *DockerSwarmSuite) TestServiceCreateWithSecretSimple(c *check.C) {
    67  	d := s.AddDaemon(c, true, true)
    68  
    69  	serviceName := "test-service-secret"
    70  	testName := "test_secret"
    71  	id := d.CreateSecret(c, swarm.SecretSpec{
    72  		Annotations: swarm.Annotations{
    73  			Name: testName,
    74  		},
    75  		Data: []byte("TESTINGDATA"),
    76  	})
    77  	c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
    78  
    79  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "--secret", testName, "busybox", "top")
    80  	c.Assert(err, checker.IsNil, check.Commentf(out))
    81  
    82  	out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Secrets }}", serviceName)
    83  	c.Assert(err, checker.IsNil)
    84  
    85  	var refs []swarm.SecretReference
    86  	c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
    87  	c.Assert(refs, checker.HasLen, 1)
    88  
    89  	c.Assert(refs[0].SecretName, checker.Equals, testName)
    90  	c.Assert(refs[0].File, checker.Not(checker.IsNil))
    91  	c.Assert(refs[0].File.Name, checker.Equals, testName)
    92  	c.Assert(refs[0].File.UID, checker.Equals, "0")
    93  	c.Assert(refs[0].File.GID, checker.Equals, "0")
    94  
    95  	out, err = d.Cmd("service", "rm", serviceName)
    96  	c.Assert(err, checker.IsNil, check.Commentf(out))
    97  	d.DeleteSecret(c, testName)
    98  }
    99  
   100  func (s *DockerSwarmSuite) TestServiceCreateWithSecretSourceTargetPaths(c *check.C) {
   101  	d := s.AddDaemon(c, true, true)
   102  
   103  	testPaths := map[string]string{
   104  		"app":                  "/etc/secret",
   105  		"test_secret":          "test_secret",
   106  		"relative_secret":      "relative/secret",
   107  		"escapes_in_container": "../secret",
   108  	}
   109  
   110  	var secretFlags []string
   111  
   112  	for testName, testTarget := range testPaths {
   113  		id := d.CreateSecret(c, swarm.SecretSpec{
   114  			Annotations: swarm.Annotations{
   115  				Name: testName,
   116  			},
   117  			Data: []byte("TESTINGDATA " + testName + " " + testTarget),
   118  		})
   119  		c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
   120  
   121  		secretFlags = append(secretFlags, "--secret", fmt.Sprintf("source=%s,target=%s", testName, testTarget))
   122  	}
   123  
   124  	serviceName := "svc"
   125  	serviceCmd := []string{"service", "create", "--detach", "--no-resolve-image", "--name", serviceName}
   126  	serviceCmd = append(serviceCmd, secretFlags...)
   127  	serviceCmd = append(serviceCmd, "busybox", "top")
   128  	out, err := d.Cmd(serviceCmd...)
   129  	c.Assert(err, checker.IsNil, check.Commentf(out))
   130  
   131  	out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Secrets }}", serviceName)
   132  	c.Assert(err, checker.IsNil)
   133  
   134  	var refs []swarm.SecretReference
   135  	c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
   136  	c.Assert(refs, checker.HasLen, len(testPaths))
   137  
   138  	var tasks []swarm.Task
   139  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   140  		tasks = d.GetServiceTasks(c, serviceName)
   141  		return len(tasks) > 0, nil
   142  	}, checker.Equals, true)
   143  
   144  	task := tasks[0]
   145  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   146  		if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" {
   147  			task = d.GetTask(c, task.ID)
   148  		}
   149  		return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil
   150  	}, checker.Equals, true)
   151  
   152  	for testName, testTarget := range testPaths {
   153  		path := testTarget
   154  		if !filepath.IsAbs(path) {
   155  			path = filepath.Join("/run/secrets", path)
   156  		}
   157  		out, err := d.Cmd("exec", task.Status.ContainerStatus.ContainerID, "cat", path)
   158  		c.Assert(err, checker.IsNil)
   159  		c.Assert(out, checker.Equals, "TESTINGDATA "+testName+" "+testTarget)
   160  	}
   161  
   162  	out, err = d.Cmd("service", "rm", serviceName)
   163  	c.Assert(err, checker.IsNil, check.Commentf(out))
   164  }
   165  
   166  func (s *DockerSwarmSuite) TestServiceCreateWithSecretReferencedTwice(c *check.C) {
   167  	d := s.AddDaemon(c, true, true)
   168  
   169  	id := d.CreateSecret(c, swarm.SecretSpec{
   170  		Annotations: swarm.Annotations{
   171  			Name: "mysecret",
   172  		},
   173  		Data: []byte("TESTINGDATA"),
   174  	})
   175  	c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("secrets: %s", id))
   176  
   177  	serviceName := "svc"
   178  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "--secret", "source=mysecret,target=target1", "--secret", "source=mysecret,target=target2", "busybox", "top")
   179  	c.Assert(err, checker.IsNil, check.Commentf(out))
   180  
   181  	out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Secrets }}", serviceName)
   182  	c.Assert(err, checker.IsNil)
   183  
   184  	var refs []swarm.SecretReference
   185  	c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
   186  	c.Assert(refs, checker.HasLen, 2)
   187  
   188  	var tasks []swarm.Task
   189  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   190  		tasks = d.GetServiceTasks(c, serviceName)
   191  		return len(tasks) > 0, nil
   192  	}, checker.Equals, true)
   193  
   194  	task := tasks[0]
   195  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   196  		if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" {
   197  			task = d.GetTask(c, task.ID)
   198  		}
   199  		return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil
   200  	}, checker.Equals, true)
   201  
   202  	for _, target := range []string{"target1", "target2"} {
   203  		c.Assert(err, checker.IsNil, check.Commentf(out))
   204  		path := filepath.Join("/run/secrets", target)
   205  		out, err := d.Cmd("exec", task.Status.ContainerStatus.ContainerID, "cat", path)
   206  		c.Assert(err, checker.IsNil)
   207  		c.Assert(out, checker.Equals, "TESTINGDATA")
   208  	}
   209  
   210  	out, err = d.Cmd("service", "rm", serviceName)
   211  	c.Assert(err, checker.IsNil, check.Commentf(out))
   212  }
   213  
   214  func (s *DockerSwarmSuite) TestServiceCreateWithConfigSimple(c *check.C) {
   215  	d := s.AddDaemon(c, true, true)
   216  
   217  	serviceName := "test-service-config"
   218  	testName := "test_config"
   219  	id := d.CreateConfig(c, swarm.ConfigSpec{
   220  		Annotations: swarm.Annotations{
   221  			Name: testName,
   222  		},
   223  		Data: []byte("TESTINGDATA"),
   224  	})
   225  	c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
   226  
   227  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "--config", testName, "busybox", "top")
   228  	c.Assert(err, checker.IsNil, check.Commentf(out))
   229  
   230  	out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Configs }}", serviceName)
   231  	c.Assert(err, checker.IsNil)
   232  
   233  	var refs []swarm.ConfigReference
   234  	c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
   235  	c.Assert(refs, checker.HasLen, 1)
   236  
   237  	c.Assert(refs[0].ConfigName, checker.Equals, testName)
   238  	c.Assert(refs[0].File, checker.Not(checker.IsNil))
   239  	c.Assert(refs[0].File.Name, checker.Equals, testName)
   240  	c.Assert(refs[0].File.UID, checker.Equals, "0")
   241  	c.Assert(refs[0].File.GID, checker.Equals, "0")
   242  
   243  	out, err = d.Cmd("service", "rm", serviceName)
   244  	c.Assert(err, checker.IsNil, check.Commentf(out))
   245  	d.DeleteConfig(c, testName)
   246  }
   247  
   248  func (s *DockerSwarmSuite) TestServiceCreateWithConfigSourceTargetPaths(c *check.C) {
   249  	d := s.AddDaemon(c, true, true)
   250  
   251  	testPaths := map[string]string{
   252  		"app":             "/etc/config",
   253  		"test_config":     "test_config",
   254  		"relative_config": "relative/config",
   255  	}
   256  
   257  	var configFlags []string
   258  
   259  	for testName, testTarget := range testPaths {
   260  		id := d.CreateConfig(c, swarm.ConfigSpec{
   261  			Annotations: swarm.Annotations{
   262  				Name: testName,
   263  			},
   264  			Data: []byte("TESTINGDATA " + testName + " " + testTarget),
   265  		})
   266  		c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
   267  
   268  		configFlags = append(configFlags, "--config", fmt.Sprintf("source=%s,target=%s", testName, testTarget))
   269  	}
   270  
   271  	serviceName := "svc"
   272  	serviceCmd := []string{"service", "create", "--detach", "--no-resolve-image", "--name", serviceName}
   273  	serviceCmd = append(serviceCmd, configFlags...)
   274  	serviceCmd = append(serviceCmd, "busybox", "top")
   275  	out, err := d.Cmd(serviceCmd...)
   276  	c.Assert(err, checker.IsNil, check.Commentf(out))
   277  
   278  	out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Configs }}", serviceName)
   279  	c.Assert(err, checker.IsNil)
   280  
   281  	var refs []swarm.ConfigReference
   282  	c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
   283  	c.Assert(refs, checker.HasLen, len(testPaths))
   284  
   285  	var tasks []swarm.Task
   286  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   287  		tasks = d.GetServiceTasks(c, serviceName)
   288  		return len(tasks) > 0, nil
   289  	}, checker.Equals, true)
   290  
   291  	task := tasks[0]
   292  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   293  		if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" {
   294  			task = d.GetTask(c, task.ID)
   295  		}
   296  		return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil
   297  	}, checker.Equals, true)
   298  
   299  	for testName, testTarget := range testPaths {
   300  		path := testTarget
   301  		if !filepath.IsAbs(path) {
   302  			path = filepath.Join("/", path)
   303  		}
   304  		out, err := d.Cmd("exec", task.Status.ContainerStatus.ContainerID, "cat", path)
   305  		c.Assert(err, checker.IsNil)
   306  		c.Assert(out, checker.Equals, "TESTINGDATA "+testName+" "+testTarget)
   307  	}
   308  
   309  	out, err = d.Cmd("service", "rm", serviceName)
   310  	c.Assert(err, checker.IsNil, check.Commentf(out))
   311  }
   312  
   313  func (s *DockerSwarmSuite) TestServiceCreateWithConfigReferencedTwice(c *check.C) {
   314  	d := s.AddDaemon(c, true, true)
   315  
   316  	id := d.CreateConfig(c, swarm.ConfigSpec{
   317  		Annotations: swarm.Annotations{
   318  			Name: "myconfig",
   319  		},
   320  		Data: []byte("TESTINGDATA"),
   321  	})
   322  	c.Assert(id, checker.Not(checker.Equals), "", check.Commentf("configs: %s", id))
   323  
   324  	serviceName := "svc"
   325  	out, err := d.Cmd("service", "create", "--detach", "--no-resolve-image", "--name", serviceName, "--config", "source=myconfig,target=target1", "--config", "source=myconfig,target=target2", "busybox", "top")
   326  	c.Assert(err, checker.IsNil, check.Commentf(out))
   327  
   328  	out, err = d.Cmd("service", "inspect", "--format", "{{ json .Spec.TaskTemplate.ContainerSpec.Configs }}", serviceName)
   329  	c.Assert(err, checker.IsNil)
   330  
   331  	var refs []swarm.ConfigReference
   332  	c.Assert(json.Unmarshal([]byte(out), &refs), checker.IsNil)
   333  	c.Assert(refs, checker.HasLen, 2)
   334  
   335  	var tasks []swarm.Task
   336  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   337  		tasks = d.GetServiceTasks(c, serviceName)
   338  		return len(tasks) > 0, nil
   339  	}, checker.Equals, true)
   340  
   341  	task := tasks[0]
   342  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   343  		if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" {
   344  			task = d.GetTask(c, task.ID)
   345  		}
   346  		return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil
   347  	}, checker.Equals, true)
   348  
   349  	for _, target := range []string{"target1", "target2"} {
   350  		c.Assert(err, checker.IsNil, check.Commentf(out))
   351  		path := filepath.Join("/", target)
   352  		out, err := d.Cmd("exec", task.Status.ContainerStatus.ContainerID, "cat", path)
   353  		c.Assert(err, checker.IsNil)
   354  		c.Assert(out, checker.Equals, "TESTINGDATA")
   355  	}
   356  
   357  	out, err = d.Cmd("service", "rm", serviceName)
   358  	c.Assert(err, checker.IsNil, check.Commentf(out))
   359  }
   360  
   361  func (s *DockerSwarmSuite) TestServiceCreateMountTmpfs(c *check.C) {
   362  	d := s.AddDaemon(c, true, true)
   363  	out, err := d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--mount", "type=tmpfs,target=/foo,tmpfs-size=1MB", "busybox", "sh", "-c", "mount | grep foo; tail -f /dev/null")
   364  	c.Assert(err, checker.IsNil, check.Commentf(out))
   365  	id := strings.TrimSpace(out)
   366  
   367  	var tasks []swarm.Task
   368  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   369  		tasks = d.GetServiceTasks(c, id)
   370  		return len(tasks) > 0, nil
   371  	}, checker.Equals, true)
   372  
   373  	task := tasks[0]
   374  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   375  		if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" {
   376  			task = d.GetTask(c, task.ID)
   377  		}
   378  		return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil
   379  	}, checker.Equals, true)
   380  
   381  	// check container mount config
   382  	out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .HostConfig.Mounts}}", task.Status.ContainerStatus.ContainerID)
   383  	c.Assert(err, checker.IsNil, check.Commentf(out))
   384  
   385  	var mountConfig []mount.Mount
   386  	c.Assert(json.Unmarshal([]byte(out), &mountConfig), checker.IsNil)
   387  	c.Assert(mountConfig, checker.HasLen, 1)
   388  
   389  	c.Assert(mountConfig[0].Source, checker.Equals, "")
   390  	c.Assert(mountConfig[0].Target, checker.Equals, "/foo")
   391  	c.Assert(mountConfig[0].Type, checker.Equals, mount.TypeTmpfs)
   392  	c.Assert(mountConfig[0].TmpfsOptions, checker.NotNil)
   393  	c.Assert(mountConfig[0].TmpfsOptions.SizeBytes, checker.Equals, int64(1048576))
   394  
   395  	// check container mounts actual
   396  	out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .Mounts}}", task.Status.ContainerStatus.ContainerID)
   397  	c.Assert(err, checker.IsNil, check.Commentf(out))
   398  
   399  	var mounts []types.MountPoint
   400  	c.Assert(json.Unmarshal([]byte(out), &mounts), checker.IsNil)
   401  	c.Assert(mounts, checker.HasLen, 1)
   402  
   403  	c.Assert(mounts[0].Type, checker.Equals, mount.TypeTmpfs)
   404  	c.Assert(mounts[0].Name, checker.Equals, "")
   405  	c.Assert(mounts[0].Destination, checker.Equals, "/foo")
   406  	c.Assert(mounts[0].RW, checker.Equals, true)
   407  
   408  	out, err = s.nodeCmd(c, task.NodeID, "logs", task.Status.ContainerStatus.ContainerID)
   409  	c.Assert(err, checker.IsNil, check.Commentf(out))
   410  	c.Assert(strings.TrimSpace(out), checker.HasPrefix, "tmpfs on /foo type tmpfs")
   411  	c.Assert(strings.TrimSpace(out), checker.Contains, "size=1024k")
   412  }
   413  
   414  func (s *DockerSwarmSuite) TestServiceCreateWithNetworkAlias(c *check.C) {
   415  	d := s.AddDaemon(c, true, true)
   416  	out, err := d.Cmd("network", "create", "--scope=swarm", "test_swarm_br")
   417  	c.Assert(err, checker.IsNil, check.Commentf(out))
   418  
   419  	out, err = d.Cmd("service", "create", "--no-resolve-image", "--detach=true", "--network=name=test_swarm_br,alias=srv_alias", "--name=alias_tst_container", "busybox", "top")
   420  	c.Assert(err, checker.IsNil, check.Commentf(out))
   421  	id := strings.TrimSpace(out)
   422  
   423  	var tasks []swarm.Task
   424  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   425  		tasks = d.GetServiceTasks(c, id)
   426  		return len(tasks) > 0, nil
   427  	}, checker.Equals, true)
   428  
   429  	task := tasks[0]
   430  	waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) {
   431  		if task.NodeID == "" || task.Status.ContainerStatus.ContainerID == "" {
   432  			task = d.GetTask(c, task.ID)
   433  		}
   434  		return task.NodeID != "" && task.Status.ContainerStatus.ContainerID != "", nil
   435  	}, checker.Equals, true)
   436  
   437  	// check container alias config
   438  	out, err = s.nodeCmd(c, task.NodeID, "inspect", "--format", "{{json .NetworkSettings.Networks.test_swarm_br.Aliases}}", task.Status.ContainerStatus.ContainerID)
   439  	c.Assert(err, checker.IsNil, check.Commentf(out))
   440  
   441  	// Make sure the only alias seen is the container-id
   442  	var aliases []string
   443  	c.Assert(json.Unmarshal([]byte(out), &aliases), checker.IsNil)
   444  	c.Assert(aliases, checker.HasLen, 1)
   445  
   446  	c.Assert(task.Status.ContainerStatus.ContainerID, checker.Contains, aliases[0])
   447  }