gopkg.in/docker/docker.v20@v20.10.27/integration-cli/docker_cli_create_test.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/docker/docker/integration-cli/cli"
    12  	"github.com/docker/docker/integration-cli/cli/build"
    13  	"github.com/docker/docker/pkg/stringid"
    14  	"github.com/docker/docker/testutil/fakecontext"
    15  	"github.com/docker/go-connections/nat"
    16  	"gotest.tools/v3/assert"
    17  	is "gotest.tools/v3/assert/cmp"
    18  )
    19  
    20  // Make sure we can create a simple container with some args
    21  func (s *DockerSuite) TestCreateArgs(c *testing.T) {
    22  	// Intentionally clear entrypoint, as the Windows busybox image needs an entrypoint, which breaks this test
    23  	out, _ := dockerCmd(c, "create", "--entrypoint=", "busybox", "command", "arg1", "arg2", "arg with space", "-c", "flags")
    24  
    25  	cleanedContainerID := strings.TrimSpace(out)
    26  
    27  	out, _ = dockerCmd(c, "inspect", cleanedContainerID)
    28  
    29  	var containers []struct {
    30  		Path string
    31  		Args []string
    32  	}
    33  
    34  	err := json.Unmarshal([]byte(out), &containers)
    35  	assert.Assert(c, err == nil, "Error inspecting the container: %s", err)
    36  	assert.Equal(c, len(containers), 1)
    37  
    38  	cont := containers[0]
    39  	assert.Equal(c, cont.Path, "command", fmt.Sprintf("Unexpected container path. Expected command, received: %s", cont.Path))
    40  
    41  	b := false
    42  	expected := []string{"arg1", "arg2", "arg with space", "-c", "flags"}
    43  	for i, arg := range expected {
    44  		if arg != cont.Args[i] {
    45  			b = true
    46  			break
    47  		}
    48  	}
    49  	if len(cont.Args) != len(expected) || b {
    50  		c.Fatalf("Unexpected args. Expected %v, received: %v", expected, cont.Args)
    51  	}
    52  
    53  }
    54  
    55  // Make sure we can grow the container's rootfs at creation time.
    56  func (s *DockerSuite) TestCreateGrowRootfs(c *testing.T) {
    57  	// Windows and Devicemapper support growing the rootfs
    58  	if testEnv.OSType != "windows" {
    59  		testRequires(c, Devicemapper)
    60  	}
    61  	out, _ := dockerCmd(c, "create", "--storage-opt", "size=120G", "busybox")
    62  
    63  	cleanedContainerID := strings.TrimSpace(out)
    64  
    65  	inspectOut := inspectField(c, cleanedContainerID, "HostConfig.StorageOpt")
    66  	assert.Equal(c, inspectOut, "map[size:120G]")
    67  }
    68  
    69  // Make sure we cannot shrink the container's rootfs at creation time.
    70  func (s *DockerSuite) TestCreateShrinkRootfs(c *testing.T) {
    71  	testRequires(c, Devicemapper)
    72  
    73  	// Ensure this fails because of the defaultBaseFsSize is 10G
    74  	out, _, err := dockerCmdWithError("create", "--storage-opt", "size=5G", "busybox")
    75  	assert.ErrorContains(c, err, "", out)
    76  	assert.Assert(c, strings.Contains(out, "Container size cannot be smaller than"))
    77  }
    78  
    79  // Make sure we can set hostconfig options too
    80  func (s *DockerSuite) TestCreateHostConfig(c *testing.T) {
    81  	out, _ := dockerCmd(c, "create", "-P", "busybox", "echo")
    82  
    83  	cleanedContainerID := strings.TrimSpace(out)
    84  
    85  	out, _ = dockerCmd(c, "inspect", cleanedContainerID)
    86  
    87  	var containers []struct {
    88  		HostConfig *struct {
    89  			PublishAllPorts bool
    90  		}
    91  	}
    92  
    93  	err := json.Unmarshal([]byte(out), &containers)
    94  	assert.Assert(c, err == nil, "Error inspecting the container: %s", err)
    95  	assert.Equal(c, len(containers), 1)
    96  
    97  	cont := containers[0]
    98  	assert.Assert(c, cont.HostConfig != nil, "Expected HostConfig, got none")
    99  	assert.Assert(c, cont.HostConfig.PublishAllPorts, "Expected PublishAllPorts, got false")
   100  }
   101  
   102  func (s *DockerSuite) TestCreateWithPortRange(c *testing.T) {
   103  	out, _ := dockerCmd(c, "create", "-p", "3300-3303:3300-3303/tcp", "busybox", "echo")
   104  
   105  	cleanedContainerID := strings.TrimSpace(out)
   106  
   107  	out, _ = dockerCmd(c, "inspect", cleanedContainerID)
   108  
   109  	var containers []struct {
   110  		HostConfig *struct {
   111  			PortBindings map[nat.Port][]nat.PortBinding
   112  		}
   113  	}
   114  	err := json.Unmarshal([]byte(out), &containers)
   115  	assert.Assert(c, err == nil, "Error inspecting the container: %s", err)
   116  	assert.Equal(c, len(containers), 1)
   117  
   118  	cont := containers[0]
   119  
   120  	assert.Assert(c, cont.HostConfig != nil, "Expected HostConfig, got none")
   121  	assert.Equal(c, len(cont.HostConfig.PortBindings), 4, fmt.Sprintf("Expected 4 ports bindings, got %d", len(cont.HostConfig.PortBindings)))
   122  
   123  	for k, v := range cont.HostConfig.PortBindings {
   124  		assert.Equal(c, len(v), 1, fmt.Sprintf("Expected 1 ports binding, for the port  %s but found %s", k, v))
   125  		assert.Equal(c, k.Port(), v[0].HostPort, fmt.Sprintf("Expected host port %s to match published port %s", k.Port(), v[0].HostPort))
   126  
   127  	}
   128  
   129  }
   130  
   131  func (s *DockerSuite) TestCreateWithLargePortRange(c *testing.T) {
   132  	out, _ := dockerCmd(c, "create", "-p", "1-65535:1-65535/tcp", "busybox", "echo")
   133  
   134  	cleanedContainerID := strings.TrimSpace(out)
   135  
   136  	out, _ = dockerCmd(c, "inspect", cleanedContainerID)
   137  
   138  	var containers []struct {
   139  		HostConfig *struct {
   140  			PortBindings map[nat.Port][]nat.PortBinding
   141  		}
   142  	}
   143  
   144  	err := json.Unmarshal([]byte(out), &containers)
   145  	assert.Assert(c, err == nil, "Error inspecting the container: %s", err)
   146  	assert.Equal(c, len(containers), 1)
   147  
   148  	cont := containers[0]
   149  	assert.Assert(c, cont.HostConfig != nil, "Expected HostConfig, got none")
   150  	assert.Equal(c, len(cont.HostConfig.PortBindings), 65535)
   151  
   152  	for k, v := range cont.HostConfig.PortBindings {
   153  		assert.Equal(c, len(v), 1)
   154  		assert.Equal(c, k.Port(), v[0].HostPort, fmt.Sprintf("Expected host port %s to match published port %s", k.Port(), v[0].HostPort))
   155  	}
   156  
   157  }
   158  
   159  // "test123" should be printed by docker create + start
   160  func (s *DockerSuite) TestCreateEchoStdout(c *testing.T) {
   161  	out, _ := dockerCmd(c, "create", "busybox", "echo", "test123")
   162  
   163  	cleanedContainerID := strings.TrimSpace(out)
   164  
   165  	out, _ = dockerCmd(c, "start", "-ai", cleanedContainerID)
   166  	assert.Equal(c, out, "test123\n", "container should've printed 'test123', got %q", out)
   167  }
   168  
   169  func (s *DockerSuite) TestCreateVolumesCreated(c *testing.T) {
   170  	testRequires(c, testEnv.IsLocalDaemon)
   171  	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
   172  
   173  	name := "test_create_volume"
   174  	dockerCmd(c, "create", "--name", name, "-v", prefix+slash+"foo", "busybox")
   175  
   176  	dir, err := inspectMountSourceField(name, prefix+slash+"foo")
   177  	assert.Assert(c, err == nil, "Error getting volume host path: %q", err)
   178  
   179  	if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
   180  		c.Fatalf("Volume was not created")
   181  	}
   182  	if err != nil {
   183  		c.Fatalf("Error statting volume host path: %q", err)
   184  	}
   185  
   186  }
   187  
   188  func (s *DockerSuite) TestCreateLabels(c *testing.T) {
   189  	name := "test_create_labels"
   190  	expected := map[string]string{"k1": "v1", "k2": "v2"}
   191  	dockerCmd(c, "create", "--name", name, "-l", "k1=v1", "--label", "k2=v2", "busybox")
   192  
   193  	actual := make(map[string]string)
   194  	inspectFieldAndUnmarshall(c, name, "Config.Labels", &actual)
   195  
   196  	if !reflect.DeepEqual(expected, actual) {
   197  		c.Fatalf("Expected %s got %s", expected, actual)
   198  	}
   199  }
   200  
   201  func (s *DockerSuite) TestCreateLabelFromImage(c *testing.T) {
   202  	imageName := "testcreatebuildlabel"
   203  	buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox
   204  		LABEL k1=v1 k2=v2`))
   205  
   206  	name := "test_create_labels_from_image"
   207  	expected := map[string]string{"k2": "x", "k3": "v3", "k1": "v1"}
   208  	dockerCmd(c, "create", "--name", name, "-l", "k2=x", "--label", "k3=v3", imageName)
   209  
   210  	actual := make(map[string]string)
   211  	inspectFieldAndUnmarshall(c, name, "Config.Labels", &actual)
   212  
   213  	if !reflect.DeepEqual(expected, actual) {
   214  		c.Fatalf("Expected %s got %s", expected, actual)
   215  	}
   216  }
   217  
   218  func (s *DockerSuite) TestCreateHostnameWithNumber(c *testing.T) {
   219  	image := "busybox"
   220  	// Busybox on Windows does not implement hostname command
   221  	if testEnv.OSType == "windows" {
   222  		image = testEnv.PlatformDefaults.BaseImage
   223  	}
   224  	out, _ := dockerCmd(c, "run", "-h", "web.0", image, "hostname")
   225  	assert.Equal(c, strings.TrimSpace(out), "web.0", "hostname not set, expected `web.0`, got: %s", out)
   226  }
   227  
   228  func (s *DockerSuite) TestCreateRM(c *testing.T) {
   229  	// Test to make sure we can 'rm' a new container that is in
   230  	// "Created" state, and has ever been run. Test "rm -f" too.
   231  
   232  	// create a container
   233  	out, _ := dockerCmd(c, "create", "busybox")
   234  	cID := strings.TrimSpace(out)
   235  
   236  	dockerCmd(c, "rm", cID)
   237  
   238  	// Now do it again so we can "rm -f" this time
   239  	out, _ = dockerCmd(c, "create", "busybox")
   240  
   241  	cID = strings.TrimSpace(out)
   242  	dockerCmd(c, "rm", "-f", cID)
   243  }
   244  
   245  func (s *DockerSuite) TestCreateModeIpcContainer(c *testing.T) {
   246  	// Uses Linux specific functionality (--ipc)
   247  	testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon)
   248  
   249  	out, _ := dockerCmd(c, "create", "busybox")
   250  	id := strings.TrimSpace(out)
   251  
   252  	dockerCmd(c, "create", fmt.Sprintf("--ipc=container:%s", id), "busybox")
   253  }
   254  
   255  func (s *DockerSuite) TestCreateByImageID(c *testing.T) {
   256  	imageName := "testcreatebyimageid"
   257  	buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox
   258  		MAINTAINER dockerio`))
   259  	imageID := getIDByName(c, imageName)
   260  	truncatedImageID := stringid.TruncateID(imageID)
   261  
   262  	dockerCmd(c, "create", imageID)
   263  	dockerCmd(c, "create", truncatedImageID)
   264  
   265  	// Ensure this fails
   266  	out, exit, _ := dockerCmdWithError("create", fmt.Sprintf("%s:%s", imageName, imageID))
   267  	if exit == 0 {
   268  		c.Fatalf("expected non-zero exit code; received %d", exit)
   269  	}
   270  
   271  	if expected := "invalid reference format"; !strings.Contains(out, expected) {
   272  		c.Fatalf(`Expected %q in output; got: %s`, expected, out)
   273  	}
   274  
   275  	if i := strings.IndexRune(imageID, ':'); i >= 0 {
   276  		imageID = imageID[i+1:]
   277  	}
   278  	out, exit, _ = dockerCmdWithError("create", fmt.Sprintf("%s:%s", "wrongimage", imageID))
   279  	if exit == 0 {
   280  		c.Fatalf("expected non-zero exit code; received %d", exit)
   281  	}
   282  
   283  	if expected := "Unable to find image"; !strings.Contains(out, expected) {
   284  		c.Fatalf(`Expected %q in output; got: %s`, expected, out)
   285  	}
   286  }
   287  
   288  func (s *DockerSuite) TestCreateStopSignal(c *testing.T) {
   289  	name := "test_create_stop_signal"
   290  	dockerCmd(c, "create", "--name", name, "--stop-signal", "9", "busybox")
   291  
   292  	res := inspectFieldJSON(c, name, "Config.StopSignal")
   293  	assert.Assert(c, strings.Contains(res, "9"))
   294  }
   295  
   296  func (s *DockerSuite) TestCreateWithWorkdir(c *testing.T) {
   297  	name := "foo"
   298  
   299  	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
   300  	dir := prefix + slash + "home" + slash + "foo" + slash + "bar"
   301  
   302  	dockerCmd(c, "create", "--name", name, "-w", dir, "busybox")
   303  	// Windows does not create the workdir until the container is started
   304  	if testEnv.OSType == "windows" {
   305  		dockerCmd(c, "start", name)
   306  		if IsolationIsHyperv() {
   307  			// Hyper-V isolated containers do not allow file-operations on a
   308  			// running container. This test currently uses `docker cp` to verify
   309  			// that the WORKDIR was automatically created, which cannot be done
   310  			// while the container is running.
   311  			dockerCmd(c, "stop", name)
   312  		}
   313  	}
   314  	// TODO: rewrite this test to not use `docker cp` for verifying that the WORKDIR was created
   315  	dockerCmd(c, "cp", fmt.Sprintf("%s:%s", name, dir), prefix+slash+"tmp")
   316  }
   317  
   318  func (s *DockerSuite) TestCreateWithInvalidLogOpts(c *testing.T) {
   319  	name := "test-invalidate-log-opts"
   320  	out, _, err := dockerCmdWithError("create", "--name", name, "--log-opt", "invalid=true", "busybox")
   321  	assert.ErrorContains(c, err, "")
   322  	assert.Assert(c, strings.Contains(out, "unknown log opt"))
   323  	assert.Assert(c, is.Contains(out, "unknown log opt"))
   324  
   325  	out, _ = dockerCmd(c, "ps", "-a")
   326  	assert.Assert(c, !strings.Contains(out, name))
   327  }
   328  
   329  // #20972
   330  func (s *DockerSuite) TestCreate64ByteHexID(c *testing.T) {
   331  	out := inspectField(c, "busybox", "Id")
   332  	imageID := strings.TrimPrefix(strings.TrimSpace(out), "sha256:")
   333  
   334  	dockerCmd(c, "create", imageID)
   335  }
   336  
   337  // Test case for #23498
   338  func (s *DockerSuite) TestCreateUnsetEntrypoint(c *testing.T) {
   339  	name := "test-entrypoint"
   340  	dockerfile := `FROM busybox
   341  ADD entrypoint.sh /entrypoint.sh
   342  RUN chmod 755 /entrypoint.sh
   343  ENTRYPOINT ["/entrypoint.sh"]
   344  CMD echo foobar`
   345  
   346  	ctx := fakecontext.New(c, "",
   347  		fakecontext.WithDockerfile(dockerfile),
   348  		fakecontext.WithFiles(map[string]string{
   349  			"entrypoint.sh": `#!/bin/sh
   350  echo "I am an entrypoint"
   351  exec "$@"`,
   352  		}))
   353  	defer ctx.Close()
   354  
   355  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
   356  
   357  	out := cli.DockerCmd(c, "create", "--entrypoint=", name, "echo", "foo").Combined()
   358  	id := strings.TrimSpace(out)
   359  	assert.Assert(c, id != "")
   360  	out = cli.DockerCmd(c, "start", "-a", id).Combined()
   361  	assert.Equal(c, strings.TrimSpace(out), "foo")
   362  }
   363  
   364  // #22471
   365  func (s *DockerSuite) TestCreateStopTimeout(c *testing.T) {
   366  	name1 := "test_create_stop_timeout_1"
   367  	dockerCmd(c, "create", "--name", name1, "--stop-timeout", "15", "busybox")
   368  
   369  	res := inspectFieldJSON(c, name1, "Config.StopTimeout")
   370  	assert.Assert(c, strings.Contains(res, "15"))
   371  	name2 := "test_create_stop_timeout_2"
   372  	dockerCmd(c, "create", "--name", name2, "busybox")
   373  
   374  	res = inspectFieldJSON(c, name2, "Config.StopTimeout")
   375  	assert.Assert(c, strings.Contains(res, "null"))
   376  }