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