12 "github.com/docker/docker/integration-cli/checker"
13 "github.com/docker/docker/integration-cli/cli"
14 "github.com/docker/docker/integration-cli/cli/build"
15 "github.com/docker/docker/integration-cli/cli/build/fakecontext"
16 "github.com/docker/docker/pkg/stringid"
17 icmd "github.com/docker/docker/pkg/testutil/cmd"
18 "github.com/docker/go-connections/nat"
19 "github.com/go-check/check"
22 // Make sure we can create a simple container with some args
23 func (s *DockerSuite) TestCreateArgs(c *check.C) {
24 // Intentionally clear entrypoint, as the Windows busybox image needs an entrypoint, which breaks this test
25 out, _ := dockerCmd(c, "create", "--entrypoint=", "busybox", "command", "arg1", "arg2", "arg with space", "-c", "flags")
27 cleanedContainerID := strings.TrimSpace(out)
29 out, _ = dockerCmd(c, "inspect", cleanedContainerID)
31 containers := []struct {
39 err := json.Unmarshal([]byte(out), &containers)
40 c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
41 c.Assert(containers, checker.HasLen, 1)
44 c.Assert(string(cont.Path), checker.Equals, "command", check.Commentf("Unexpected container path. Expected command, received: %s", cont.Path))
47 expected := []string{"arg1", "arg2", "arg with space", "-c", "flags"}
48 for i, arg := range expected {
49 if arg != cont.Args[i] {
54 if len(cont.Args) != len(expected) || b {
55 c.Fatalf("Unexpected args. Expected %v, received: %v", expected, cont.Args)
60 // Make sure we can grow the container's rootfs at creation time.
61 func (s *DockerSuite) TestCreateGrowRootfs(c *check.C) {
62 // Windows and Devicemapper support growing the rootfs
63 if testEnv.DaemonPlatform() != "windows" {
64 testRequires(c, Devicemapper)
66 out, _ := dockerCmd(c, "create", "--storage-opt", "size=120G", "busybox")
68 cleanedContainerID := strings.TrimSpace(out)
70 inspectOut := inspectField(c, cleanedContainerID, "HostConfig.StorageOpt")
71 c.Assert(inspectOut, checker.Equals, "map[size:120G]")
74 // Make sure we cannot shrink the container's rootfs at creation time.
75 func (s *DockerSuite) TestCreateShrinkRootfs(c *check.C) {
76 testRequires(c, Devicemapper)
78 // Ensure this fails because of the defaultBaseFsSize is 10G
79 out, _, err := dockerCmdWithError("create", "--storage-opt", "size=5G", "busybox")
80 c.Assert(err, check.NotNil, check.Commentf(out))
81 c.Assert(out, checker.Contains, "Container size cannot be smaller than")
84 // Make sure we can set hostconfig options too
85 func (s *DockerSuite) TestCreateHostConfig(c *check.C) {
86 out, _ := dockerCmd(c, "create", "-P", "busybox", "echo")
88 cleanedContainerID := strings.TrimSpace(out)
90 out, _ = dockerCmd(c, "inspect", cleanedContainerID)
92 containers := []struct {
98 err := json.Unmarshal([]byte(out), &containers)
99 c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
100 c.Assert(containers, checker.HasLen, 1)
102 cont := containers[0]
103 c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none"))
104 c.Assert(cont.HostConfig.PublishAllPorts, check.NotNil, check.Commentf("Expected PublishAllPorts, got false"))
107 func (s *DockerSuite) TestCreateWithPortRange(c *check.C) {
108 out, _ := dockerCmd(c, "create", "-p", "3300-3303:3300-3303/tcp", "busybox", "echo")
110 cleanedContainerID := strings.TrimSpace(out)
112 out, _ = dockerCmd(c, "inspect", cleanedContainerID)
114 containers := []struct {
116 PortBindings map[nat.Port][]nat.PortBinding
119 err := json.Unmarshal([]byte(out), &containers)
120 c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
121 c.Assert(containers, checker.HasLen, 1)
123 cont := containers[0]
125 c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none"))
126 c.Assert(cont.HostConfig.PortBindings, checker.HasLen, 4, check.Commentf("Expected 4 ports bindings, got %d", len(cont.HostConfig.PortBindings)))
128 for k, v := range cont.HostConfig.PortBindings {
129 c.Assert(v, checker.HasLen, 1, check.Commentf("Expected 1 ports binding, for the port %s but found %s", k, v))
130 c.Assert(k.Port(), checker.Equals, v[0].HostPort, check.Commentf("Expected host port %s to match published port %s", k.Port(), v[0].HostPort))
136 func (s *DockerSuite) TestCreateWithLargePortRange(c *check.C) {
137 out, _ := dockerCmd(c, "create", "-p", "1-65535:1-65535/tcp", "busybox", "echo")
139 cleanedContainerID := strings.TrimSpace(out)
141 out, _ = dockerCmd(c, "inspect", cleanedContainerID)
143 containers := []struct {
145 PortBindings map[nat.Port][]nat.PortBinding
149 err := json.Unmarshal([]byte(out), &containers)
150 c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err))
151 c.Assert(containers, checker.HasLen, 1)
153 cont := containers[0]
154 c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none"))
155 c.Assert(cont.HostConfig.PortBindings, checker.HasLen, 65535)
157 for k, v := range cont.HostConfig.PortBindings {
158 c.Assert(v, checker.HasLen, 1)
159 c.Assert(k.Port(), checker.Equals, v[0].HostPort, check.Commentf("Expected host port %s to match published port %s", k.Port(), v[0].HostPort))
164 // "test123" should be printed by docker create + start
165 func (s *DockerSuite) TestCreateEchoStdout(c *check.C) {
166 out, _ := dockerCmd(c, "create", "busybox", "echo", "test123")
168 cleanedContainerID := strings.TrimSpace(out)
170 out, _ = dockerCmd(c, "start", "-ai", cleanedContainerID)
171 c.Assert(out, checker.Equals, "test123\n", check.Commentf("container should've printed 'test123', got %q", out))
175 func (s *DockerSuite) TestCreateVolumesCreated(c *check.C) {
176 testRequires(c, SameHostDaemon)
177 prefix, slash := getPrefixAndSlashFromDaemonPlatform()
179 name := "test_create_volume"
180 dockerCmd(c, "create", "--name", name, "-v", prefix+slash+"foo", "busybox")
182 dir, err := inspectMountSourceField(name, prefix+slash+"foo")
183 c.Assert(err, check.IsNil, check.Commentf("Error getting volume host path: %q", err))
185 if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
186 c.Fatalf("Volume was not created")
189 c.Fatalf("Error statting volume host path: %q", err)
194 func (s *DockerSuite) TestCreateLabels(c *check.C) {
195 name := "test_create_labels"
196 expected := map[string]string{"k1": "v1", "k2": "v2"}
197 dockerCmd(c, "create", "--name", name, "-l", "k1=v1", "--label", "k2=v2", "busybox")
199 actual := make(map[string]string)
200 inspectFieldAndUnmarshall(c, name, "Config.Labels", &actual)
202 if !reflect.DeepEqual(expected, actual) {
203 c.Fatalf("Expected %s got %s", expected, actual)
207 func (s *DockerSuite) TestCreateLabelFromImage(c *check.C) {
208 imageName := "testcreatebuildlabel"
209 buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox
212 name := "test_create_labels_from_image"
213 expected := map[string]string{"k2": "x", "k3": "v3", "k1": "v1"}
214 dockerCmd(c, "create", "--name", name, "-l", "k2=x", "--label", "k3=v3", imageName)
216 actual := make(map[string]string)
217 inspectFieldAndUnmarshall(c, name, "Config.Labels", &actual)
219 if !reflect.DeepEqual(expected, actual) {
220 c.Fatalf("Expected %s got %s", expected, actual)
224 func (s *DockerSuite) TestCreateHostnameWithNumber(c *check.C) {
226 // Busybox on Windows does not implement hostname command
227 if testEnv.DaemonPlatform() == "windows" {
228 image = testEnv.MinimalBaseImage()
230 out, _ := dockerCmd(c, "run", "-h", "web.0", image, "hostname")
231 c.Assert(strings.TrimSpace(out), checker.Equals, "web.0", check.Commentf("hostname not set, expected `web.0`, got: %s", out))
235 func (s *DockerSuite) TestCreateRM(c *check.C) {
236 // Test to make sure we can 'rm' a new container that is in
237 // "Created" state, and has ever been run. Test "rm -f" too.
239 // create a container
240 out, _ := dockerCmd(c, "create", "busybox")
241 cID := strings.TrimSpace(out)
243 dockerCmd(c, "rm", cID)
245 // Now do it again so we can "rm -f" this time
246 out, _ = dockerCmd(c, "create", "busybox")
248 cID = strings.TrimSpace(out)
249 dockerCmd(c, "rm", "-f", cID)
252 func (s *DockerSuite) TestCreateModeIpcContainer(c *check.C) {
253 // Uses Linux specific functionality (--ipc)
254 testRequires(c, DaemonIsLinux, SameHostDaemon)
256 out, _ := dockerCmd(c, "create", "busybox")
257 id := strings.TrimSpace(out)
259 dockerCmd(c, "create", fmt.Sprintf("--ipc=container:%s", id), "busybox")
262 func (s *DockerSuite) TestCreateByImageID(c *check.C) {
263 imageName := "testcreatebyimageid"
264 buildImageSuccessfully(c, imageName, build.WithDockerfile(`FROM busybox
265 MAINTAINER dockerio`))
266 imageID := getIDByName(c, imageName)
267 truncatedImageID := stringid.TruncateID(imageID)
269 dockerCmd(c, "create", imageID)
270 dockerCmd(c, "create", truncatedImageID)
271 dockerCmd(c, "create", fmt.Sprintf("%s:%s", imageName, truncatedImageID))
274 out, exit, _ := dockerCmdWithError("create", fmt.Sprintf("%s:%s", imageName, imageID))
276 c.Fatalf("expected non-zero exit code; received %d", exit)
279 if expected := "invalid reference format"; !strings.Contains(out, expected) {
280 c.Fatalf(`Expected %q in output; got: %s`, expected, out)
283 out, exit, _ = dockerCmdWithError("create", fmt.Sprintf("%s:%s", "wrongimage", truncatedImageID))
285 c.Fatalf("expected non-zero exit code; received %d", exit)
288 if expected := "Unable to find image"; !strings.Contains(out, expected) {
289 c.Fatalf(`Expected %q in output; got: %s`, expected, out)
293 func (s *DockerTrustSuite) TestTrustedCreate(c *check.C) {
294 repoName := s.setupTrustedImage(c, "trusted-create")
297 cli.Docker(cli.Args("create", repoName), trustedCmd).Assert(c, SuccessTagging)
298 cli.DockerCmd(c, "rmi", repoName)
300 // Try untrusted create to ensure we pushed the tag to the registry
301 cli.Docker(cli.Args("create", "--disable-content-trust=true", repoName)).Assert(c, SuccessDownloadedOnStderr)
304 func (s *DockerTrustSuite) TestUntrustedCreate(c *check.C) {
305 repoName := fmt.Sprintf("%v/dockercliuntrusted/createtest", privateRegistryURL)
306 withTagName := fmt.Sprintf("%s:latest", repoName)
307 // tag the image and upload it to the private registry
308 cli.DockerCmd(c, "tag", "busybox", withTagName)
309 cli.DockerCmd(c, "push", withTagName)
310 cli.DockerCmd(c, "rmi", withTagName)
312 // Try trusted create on untrusted tag
313 cli.Docker(cli.Args("create", withTagName), trustedCmd).Assert(c, icmd.Expected{
315 Err: fmt.Sprintf("does not have trust data for %s", repoName),
319 func (s *DockerTrustSuite) TestTrustedIsolatedCreate(c *check.C) {
320 repoName := s.setupTrustedImage(c, "trusted-isolated-create")
323 cli.Docker(cli.Args("--config", "/tmp/docker-isolated-create", "create", repoName), trustedCmd).Assert(c, SuccessTagging)
324 defer os.RemoveAll("/tmp/docker-isolated-create")
326 cli.DockerCmd(c, "rmi", repoName)
329 func (s *DockerTrustSuite) TestTrustedCreateFromBadTrustServer(c *check.C) {
330 repoName := fmt.Sprintf("%v/dockerclievilcreate/trusted:latest", privateRegistryURL)
331 evilLocalConfigDir, err := ioutil.TempDir("", "evilcreate-local-config-dir")
332 c.Assert(err, check.IsNil)
334 // tag the image and upload it to the private registry
335 cli.DockerCmd(c, "tag", "busybox", repoName)
336 cli.Docker(cli.Args("push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
337 cli.DockerCmd(c, "rmi", repoName)
340 cli.Docker(cli.Args("create", repoName), trustedCmd).Assert(c, SuccessTagging)
341 cli.DockerCmd(c, "rmi", repoName)
343 // Kill the notary server, start a new "evil" one.
345 s.not, err = newTestNotary(c)
346 c.Assert(err, check.IsNil)
348 // In order to make an evil server, lets re-init a client (with a different trust dir) and push new data.
349 // tag an image and upload it to the private registry
350 cli.DockerCmd(c, "--config", evilLocalConfigDir, "tag", "busybox", repoName)
352 // Push up to the new server
353 cli.Docker(cli.Args("--config", evilLocalConfigDir, "push", repoName), trustedCmd).Assert(c, SuccessSigningAndPushing)
355 // Now, try creating with the original client from this new trust server. This should fail because the new root is invalid.
356 cli.Docker(cli.Args("create", repoName), trustedCmd).Assert(c, icmd.Expected{
358 Err: "could not rotate trust to a new trusted root",
362 func (s *DockerSuite) TestCreateStopSignal(c *check.C) {
363 name := "test_create_stop_signal"
364 dockerCmd(c, "create", "--name", name, "--stop-signal", "9", "busybox")
366 res := inspectFieldJSON(c, name, "Config.StopSignal")
367 c.Assert(res, checker.Contains, "9")
371 func (s *DockerSuite) TestCreateWithWorkdir(c *check.C) {
374 prefix, slash := getPrefixAndSlashFromDaemonPlatform()
375 dir := prefix + slash + "home" + slash + "foo" + slash + "bar"
377 dockerCmd(c, "create", "--name", name, "-w", dir, "busybox")
378 // Windows does not create the workdir until the container is started
379 if testEnv.DaemonPlatform() == "windows" {
380 dockerCmd(c, "start", name)
382 dockerCmd(c, "cp", fmt.Sprintf("%s:%s", name, dir), prefix+slash+"tmp")
385 func (s *DockerSuite) TestCreateWithInvalidLogOpts(c *check.C) {
386 name := "test-invalidate-log-opts"
387 out, _, err := dockerCmdWithError("create", "--name", name, "--log-opt", "invalid=true", "busybox")
388 c.Assert(err, checker.NotNil)
389 c.Assert(out, checker.Contains, "unknown log opt")
391 out, _ = dockerCmd(c, "ps", "-a")
392 c.Assert(out, checker.Not(checker.Contains), name)
396 func (s *DockerSuite) TestCreate64ByteHexID(c *check.C) {
397 out := inspectField(c, "busybox", "Id")
398 imageID := strings.TrimPrefix(strings.TrimSpace(string(out)), "sha256:")
400 dockerCmd(c, "create", imageID)
403 // Test case for #23498
404 func (s *DockerSuite) TestCreateUnsetEntrypoint(c *check.C) {
405 name := "test-entrypoint"
406 dockerfile := `FROM busybox
407 ADD entrypoint.sh /entrypoint.sh
408 RUN chmod 755 /entrypoint.sh
409 ENTRYPOINT ["/entrypoint.sh"]
412 ctx := fakecontext.New(c, "",
413 fakecontext.WithDockerfile(dockerfile),
414 fakecontext.WithFiles(map[string]string{
415 "entrypoint.sh": `#!/bin/sh
416 echo "I am an entrypoint"
421 cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
423 out := cli.DockerCmd(c, "create", "--entrypoint=", name, "echo", "foo").Combined()
424 id := strings.TrimSpace(out)
425 c.Assert(id, check.Not(check.Equals), "")
426 out = cli.DockerCmd(c, "start", "-a", id).Combined()
427 c.Assert(strings.TrimSpace(out), check.Equals, "foo")
431 func (s *DockerSuite) TestCreateStopTimeout(c *check.C) {
432 name1 := "test_create_stop_timeout_1"
433 dockerCmd(c, "create", "--name", name1, "--stop-timeout", "15", "busybox")
435 res := inspectFieldJSON(c, name1, "Config.StopTimeout")
436 c.Assert(res, checker.Contains, "15")
438 name2 := "test_create_stop_timeout_2"
439 dockerCmd(c, "create", "--name", name2, "busybox")
441 res = inspectFieldJSON(c, name2, "Config.StopTimeout")
442 c.Assert(res, checker.Contains, "null")