github.com/getong/docker@v1.13.1/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 "time" 10 11 "os/exec" 12 13 "io/ioutil" 14 15 "github.com/docker/docker/pkg/integration/checker" 16 "github.com/docker/docker/pkg/stringid" 17 "github.com/docker/go-connections/nat" 18 "github.com/go-check/check" 19 ) 20 21 // Make sure we can create a simple container with some args 22 func (s *DockerSuite) TestCreateArgs(c *check.C) { 23 // Intentionally clear entrypoint, as the Windows busybox image needs an entrypoint, which breaks this test 24 out, _ := dockerCmd(c, "create", "--entrypoint=", "busybox", "command", "arg1", "arg2", "arg with space", "-c", "flags") 25 26 cleanedContainerID := strings.TrimSpace(out) 27 28 out, _ = dockerCmd(c, "inspect", cleanedContainerID) 29 30 containers := []struct { 31 ID string 32 Created time.Time 33 Path string 34 Args []string 35 Image string 36 }{} 37 38 err := json.Unmarshal([]byte(out), &containers) 39 c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err)) 40 c.Assert(containers, checker.HasLen, 1) 41 42 cont := containers[0] 43 c.Assert(string(cont.Path), checker.Equals, "command", check.Commentf("Unexpected container path. Expected command, received: %s", cont.Path)) 44 45 b := false 46 expected := []string{"arg1", "arg2", "arg with space", "-c", "flags"} 47 for i, arg := range expected { 48 if arg != cont.Args[i] { 49 b = true 50 break 51 } 52 } 53 if len(cont.Args) != len(expected) || b { 54 c.Fatalf("Unexpected args. Expected %v, received: %v", expected, cont.Args) 55 } 56 57 } 58 59 // Make sure we can grow the container's rootfs at creation time. 60 func (s *DockerSuite) TestCreateGrowRootfs(c *check.C) { 61 // Windows and Devicemapper support growing the rootfs 62 if daemonPlatform != "windows" { 63 testRequires(c, Devicemapper) 64 } 65 out, _ := dockerCmd(c, "create", "--storage-opt", "size=120G", "busybox") 66 67 cleanedContainerID := strings.TrimSpace(out) 68 69 inspectOut := inspectField(c, cleanedContainerID, "HostConfig.StorageOpt") 70 c.Assert(inspectOut, checker.Equals, "map[size:120G]") 71 } 72 73 // Make sure we cannot shrink the container's rootfs at creation time. 74 func (s *DockerSuite) TestCreateShrinkRootfs(c *check.C) { 75 testRequires(c, Devicemapper) 76 77 // Ensure this fails because of the defaultBaseFsSize is 10G 78 out, _, err := dockerCmdWithError("create", "--storage-opt", "size=5G", "busybox") 79 c.Assert(err, check.NotNil, check.Commentf(out)) 80 c.Assert(out, checker.Contains, "Container size cannot be smaller than") 81 } 82 83 // Make sure we can set hostconfig options too 84 func (s *DockerSuite) TestCreateHostConfig(c *check.C) { 85 out, _ := dockerCmd(c, "create", "-P", "busybox", "echo") 86 87 cleanedContainerID := strings.TrimSpace(out) 88 89 out, _ = dockerCmd(c, "inspect", cleanedContainerID) 90 91 containers := []struct { 92 HostConfig *struct { 93 PublishAllPorts bool 94 } 95 }{} 96 97 err := json.Unmarshal([]byte(out), &containers) 98 c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err)) 99 c.Assert(containers, checker.HasLen, 1) 100 101 cont := containers[0] 102 c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none")) 103 c.Assert(cont.HostConfig.PublishAllPorts, check.NotNil, check.Commentf("Expected PublishAllPorts, got false")) 104 } 105 106 func (s *DockerSuite) TestCreateWithPortRange(c *check.C) { 107 out, _ := dockerCmd(c, "create", "-p", "3300-3303:3300-3303/tcp", "busybox", "echo") 108 109 cleanedContainerID := strings.TrimSpace(out) 110 111 out, _ = dockerCmd(c, "inspect", cleanedContainerID) 112 113 containers := []struct { 114 HostConfig *struct { 115 PortBindings map[nat.Port][]nat.PortBinding 116 } 117 }{} 118 err := json.Unmarshal([]byte(out), &containers) 119 c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err)) 120 c.Assert(containers, checker.HasLen, 1) 121 122 cont := containers[0] 123 124 c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none")) 125 c.Assert(cont.HostConfig.PortBindings, checker.HasLen, 4, check.Commentf("Expected 4 ports bindings, got %d", len(cont.HostConfig.PortBindings))) 126 127 for k, v := range cont.HostConfig.PortBindings { 128 c.Assert(v, checker.HasLen, 1, check.Commentf("Expected 1 ports binding, for the port %s but found %s", k, v)) 129 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)) 130 131 } 132 133 } 134 135 func (s *DockerSuite) TestCreateWithLargePortRange(c *check.C) { 136 out, _ := dockerCmd(c, "create", "-p", "1-65535:1-65535/tcp", "busybox", "echo") 137 138 cleanedContainerID := strings.TrimSpace(out) 139 140 out, _ = dockerCmd(c, "inspect", cleanedContainerID) 141 142 containers := []struct { 143 HostConfig *struct { 144 PortBindings map[nat.Port][]nat.PortBinding 145 } 146 }{} 147 148 err := json.Unmarshal([]byte(out), &containers) 149 c.Assert(err, check.IsNil, check.Commentf("Error inspecting the container: %s", err)) 150 c.Assert(containers, checker.HasLen, 1) 151 152 cont := containers[0] 153 c.Assert(cont.HostConfig, check.NotNil, check.Commentf("Expected HostConfig, got none")) 154 c.Assert(cont.HostConfig.PortBindings, checker.HasLen, 65535) 155 156 for k, v := range cont.HostConfig.PortBindings { 157 c.Assert(v, checker.HasLen, 1) 158 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)) 159 } 160 161 } 162 163 // "test123" should be printed by docker create + start 164 func (s *DockerSuite) TestCreateEchoStdout(c *check.C) { 165 out, _ := dockerCmd(c, "create", "busybox", "echo", "test123") 166 167 cleanedContainerID := strings.TrimSpace(out) 168 169 out, _ = dockerCmd(c, "start", "-ai", cleanedContainerID) 170 c.Assert(out, checker.Equals, "test123\n", check.Commentf("container should've printed 'test123', got %q", out)) 171 172 } 173 174 func (s *DockerSuite) TestCreateVolumesCreated(c *check.C) { 175 testRequires(c, SameHostDaemon) 176 prefix, slash := getPrefixAndSlashFromDaemonPlatform() 177 178 name := "test_create_volume" 179 dockerCmd(c, "create", "--name", name, "-v", prefix+slash+"foo", "busybox") 180 181 dir, err := inspectMountSourceField(name, prefix+slash+"foo") 182 c.Assert(err, check.IsNil, check.Commentf("Error getting volume host path: %q", err)) 183 184 if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) { 185 c.Fatalf("Volume was not created") 186 } 187 if err != nil { 188 c.Fatalf("Error statting volume host path: %q", err) 189 } 190 191 } 192 193 func (s *DockerSuite) TestCreateLabels(c *check.C) { 194 name := "test_create_labels" 195 expected := map[string]string{"k1": "v1", "k2": "v2"} 196 dockerCmd(c, "create", "--name", name, "-l", "k1=v1", "--label", "k2=v2", "busybox") 197 198 actual := make(map[string]string) 199 inspectFieldAndMarshall(c, name, "Config.Labels", &actual) 200 201 if !reflect.DeepEqual(expected, actual) { 202 c.Fatalf("Expected %s got %s", expected, actual) 203 } 204 } 205 206 func (s *DockerSuite) TestCreateLabelFromImage(c *check.C) { 207 imageName := "testcreatebuildlabel" 208 _, err := buildImage(imageName, 209 `FROM busybox 210 LABEL k1=v1 k2=v2`, 211 true) 212 213 c.Assert(err, check.IsNil) 214 215 name := "test_create_labels_from_image" 216 expected := map[string]string{"k2": "x", "k3": "v3", "k1": "v1"} 217 dockerCmd(c, "create", "--name", name, "-l", "k2=x", "--label", "k3=v3", imageName) 218 219 actual := make(map[string]string) 220 inspectFieldAndMarshall(c, name, "Config.Labels", &actual) 221 222 if !reflect.DeepEqual(expected, actual) { 223 c.Fatalf("Expected %s got %s", expected, actual) 224 } 225 } 226 227 func (s *DockerSuite) TestCreateHostnameWithNumber(c *check.C) { 228 image := "busybox" 229 // Busybox on Windows does not implement hostname command 230 if daemonPlatform == "windows" { 231 image = WindowsBaseImage 232 } 233 out, _ := dockerCmd(c, "run", "-h", "web.0", image, "hostname") 234 c.Assert(strings.TrimSpace(out), checker.Equals, "web.0", check.Commentf("hostname not set, expected `web.0`, got: %s", out)) 235 236 } 237 238 func (s *DockerSuite) TestCreateRM(c *check.C) { 239 // Test to make sure we can 'rm' a new container that is in 240 // "Created" state, and has ever been run. Test "rm -f" too. 241 242 // create a container 243 out, _ := dockerCmd(c, "create", "busybox") 244 cID := strings.TrimSpace(out) 245 246 dockerCmd(c, "rm", cID) 247 248 // Now do it again so we can "rm -f" this time 249 out, _ = dockerCmd(c, "create", "busybox") 250 251 cID = strings.TrimSpace(out) 252 dockerCmd(c, "rm", "-f", cID) 253 } 254 255 func (s *DockerSuite) TestCreateModeIpcContainer(c *check.C) { 256 // Uses Linux specific functionality (--ipc) 257 testRequires(c, DaemonIsLinux, SameHostDaemon) 258 259 out, _ := dockerCmd(c, "create", "busybox") 260 id := strings.TrimSpace(out) 261 262 dockerCmd(c, "create", fmt.Sprintf("--ipc=container:%s", id), "busybox") 263 } 264 265 func (s *DockerSuite) TestCreateByImageID(c *check.C) { 266 imageName := "testcreatebyimageid" 267 imageID, err := buildImage(imageName, 268 `FROM busybox 269 MAINTAINER dockerio`, 270 true) 271 if err != nil { 272 c.Fatal(err) 273 } 274 truncatedImageID := stringid.TruncateID(imageID) 275 276 dockerCmd(c, "create", imageID) 277 dockerCmd(c, "create", truncatedImageID) 278 dockerCmd(c, "create", fmt.Sprintf("%s:%s", imageName, truncatedImageID)) 279 280 // Ensure this fails 281 out, exit, _ := dockerCmdWithError("create", fmt.Sprintf("%s:%s", imageName, imageID)) 282 if exit == 0 { 283 c.Fatalf("expected non-zero exit code; received %d", exit) 284 } 285 286 if expected := "Error parsing reference"; !strings.Contains(out, expected) { 287 c.Fatalf(`Expected %q in output; got: %s`, expected, out) 288 } 289 290 out, exit, _ = dockerCmdWithError("create", fmt.Sprintf("%s:%s", "wrongimage", truncatedImageID)) 291 if exit == 0 { 292 c.Fatalf("expected non-zero exit code; received %d", exit) 293 } 294 295 if expected := "Unable to find image"; !strings.Contains(out, expected) { 296 c.Fatalf(`Expected %q in output; got: %s`, expected, out) 297 } 298 } 299 300 func (s *DockerTrustSuite) TestTrustedCreate(c *check.C) { 301 repoName := s.setupTrustedImage(c, "trusted-create") 302 303 // Try create 304 createCmd := exec.Command(dockerBinary, "create", repoName) 305 s.trustedCmd(createCmd) 306 out, _, err := runCommandWithOutput(createCmd) 307 c.Assert(err, check.IsNil) 308 c.Assert(string(out), checker.Contains, "Tagging", check.Commentf("Missing expected output on trusted push:\n%s", out)) 309 310 dockerCmd(c, "rmi", repoName) 311 312 // Try untrusted create to ensure we pushed the tag to the registry 313 createCmd = exec.Command(dockerBinary, "create", "--disable-content-trust=true", repoName) 314 s.trustedCmd(createCmd) 315 out, _, err = runCommandWithOutput(createCmd) 316 c.Assert(err, check.IsNil) 317 c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf("Missing expected output on trusted create with --disable-content-trust:\n%s", out)) 318 319 } 320 321 func (s *DockerTrustSuite) TestUntrustedCreate(c *check.C) { 322 repoName := fmt.Sprintf("%v/dockercliuntrusted/createtest", privateRegistryURL) 323 withTagName := fmt.Sprintf("%s:latest", repoName) 324 // tag the image and upload it to the private registry 325 dockerCmd(c, "tag", "busybox", withTagName) 326 dockerCmd(c, "push", withTagName) 327 dockerCmd(c, "rmi", withTagName) 328 329 // Try trusted create on untrusted tag 330 createCmd := exec.Command(dockerBinary, "create", withTagName) 331 s.trustedCmd(createCmd) 332 out, _, err := runCommandWithOutput(createCmd) 333 c.Assert(err, check.Not(check.IsNil)) 334 c.Assert(string(out), checker.Contains, fmt.Sprintf("does not have trust data for %s", repoName), check.Commentf("Missing expected output on trusted create:\n%s", out)) 335 336 } 337 338 func (s *DockerTrustSuite) TestTrustedIsolatedCreate(c *check.C) { 339 repoName := s.setupTrustedImage(c, "trusted-isolated-create") 340 341 // Try create 342 createCmd := exec.Command(dockerBinary, "--config", "/tmp/docker-isolated-create", "create", repoName) 343 s.trustedCmd(createCmd) 344 out, _, err := runCommandWithOutput(createCmd) 345 c.Assert(err, check.IsNil) 346 c.Assert(string(out), checker.Contains, "Tagging", check.Commentf("Missing expected output on trusted push:\n%s", out)) 347 348 dockerCmd(c, "rmi", repoName) 349 } 350 351 func (s *DockerTrustSuite) TestCreateWhenCertExpired(c *check.C) { 352 c.Skip("Currently changes system time, causing instability") 353 repoName := s.setupTrustedImage(c, "trusted-create-expired") 354 355 // Certificates have 10 years of expiration 356 elevenYearsFromNow := time.Now().Add(time.Hour * 24 * 365 * 11) 357 358 runAtDifferentDate(elevenYearsFromNow, func() { 359 // Try create 360 createCmd := exec.Command(dockerBinary, "create", repoName) 361 s.trustedCmd(createCmd) 362 out, _, err := runCommandWithOutput(createCmd) 363 c.Assert(err, check.Not(check.IsNil)) 364 c.Assert(string(out), checker.Contains, "could not validate the path to a trusted root", check.Commentf("Missing expected output on trusted create in the distant future:\n%s", out)) 365 }) 366 367 runAtDifferentDate(elevenYearsFromNow, func() { 368 // Try create 369 createCmd := exec.Command(dockerBinary, "create", "--disable-content-trust", repoName) 370 s.trustedCmd(createCmd) 371 out, _, err := runCommandWithOutput(createCmd) 372 c.Assert(err, check.Not(check.IsNil)) 373 c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf("Missing expected output on trusted create in the distant future:\n%s", out)) 374 375 }) 376 } 377 378 func (s *DockerTrustSuite) TestTrustedCreateFromBadTrustServer(c *check.C) { 379 repoName := fmt.Sprintf("%v/dockerclievilcreate/trusted:latest", privateRegistryURL) 380 evilLocalConfigDir, err := ioutil.TempDir("", "evilcreate-local-config-dir") 381 c.Assert(err, check.IsNil) 382 383 // tag the image and upload it to the private registry 384 dockerCmd(c, "tag", "busybox", repoName) 385 386 pushCmd := exec.Command(dockerBinary, "push", repoName) 387 s.trustedCmd(pushCmd) 388 out, _, err := runCommandWithOutput(pushCmd) 389 c.Assert(err, check.IsNil) 390 c.Assert(string(out), checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push:\n%s", out)) 391 392 dockerCmd(c, "rmi", repoName) 393 394 // Try create 395 createCmd := exec.Command(dockerBinary, "create", repoName) 396 s.trustedCmd(createCmd) 397 out, _, err = runCommandWithOutput(createCmd) 398 c.Assert(err, check.IsNil) 399 c.Assert(string(out), checker.Contains, "Tagging", check.Commentf("Missing expected output on trusted push:\n%s", out)) 400 401 dockerCmd(c, "rmi", repoName) 402 403 // Kill the notary server, start a new "evil" one. 404 s.not.Close() 405 s.not, err = newTestNotary(c) 406 c.Assert(err, check.IsNil) 407 408 // In order to make an evil server, lets re-init a client (with a different trust dir) and push new data. 409 // tag an image and upload it to the private registry 410 dockerCmd(c, "--config", evilLocalConfigDir, "tag", "busybox", repoName) 411 412 // Push up to the new server 413 pushCmd = exec.Command(dockerBinary, "--config", evilLocalConfigDir, "push", repoName) 414 s.trustedCmd(pushCmd) 415 out, _, err = runCommandWithOutput(pushCmd) 416 c.Assert(err, check.IsNil) 417 c.Assert(string(out), checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push:\n%s", out)) 418 419 // Now, try creating with the original client from this new trust server. This should fail because the new root is invalid. 420 createCmd = exec.Command(dockerBinary, "create", repoName) 421 s.trustedCmd(createCmd) 422 out, _, err = runCommandWithOutput(createCmd) 423 if err == nil { 424 c.Fatalf("Continuing with cached data even though it's an invalid root rotation: %s\n%s", err, out) 425 } 426 if !strings.Contains(out, "could not rotate trust to a new trusted root") { 427 c.Fatalf("Missing expected output on trusted create:\n%s", out) 428 } 429 430 } 431 432 func (s *DockerSuite) TestCreateStopSignal(c *check.C) { 433 name := "test_create_stop_signal" 434 dockerCmd(c, "create", "--name", name, "--stop-signal", "9", "busybox") 435 436 res := inspectFieldJSON(c, name, "Config.StopSignal") 437 c.Assert(res, checker.Contains, "9") 438 439 } 440 441 func (s *DockerSuite) TestCreateWithWorkdir(c *check.C) { 442 name := "foo" 443 444 prefix, slash := getPrefixAndSlashFromDaemonPlatform() 445 dir := prefix + slash + "home" + slash + "foo" + slash + "bar" 446 447 dockerCmd(c, "create", "--name", name, "-w", dir, "busybox") 448 // Windows does not create the workdir until the container is started 449 if daemonPlatform == "windows" { 450 dockerCmd(c, "start", name) 451 } 452 dockerCmd(c, "cp", fmt.Sprintf("%s:%s", name, dir), prefix+slash+"tmp") 453 } 454 455 func (s *DockerSuite) TestCreateWithInvalidLogOpts(c *check.C) { 456 name := "test-invalidate-log-opts" 457 out, _, err := dockerCmdWithError("create", "--name", name, "--log-opt", "invalid=true", "busybox") 458 c.Assert(err, checker.NotNil) 459 c.Assert(out, checker.Contains, "unknown log opt") 460 461 out, _ = dockerCmd(c, "ps", "-a") 462 c.Assert(out, checker.Not(checker.Contains), name) 463 } 464 465 // #20972 466 func (s *DockerSuite) TestCreate64ByteHexID(c *check.C) { 467 out := inspectField(c, "busybox", "Id") 468 imageID := strings.TrimPrefix(strings.TrimSpace(string(out)), "sha256:") 469 470 dockerCmd(c, "create", imageID) 471 } 472 473 // Test case for #23498 474 func (s *DockerSuite) TestCreateUnsetEntrypoint(c *check.C) { 475 name := "test-entrypoint" 476 dockerfile := `FROM busybox 477 ADD entrypoint.sh /entrypoint.sh 478 RUN chmod 755 /entrypoint.sh 479 ENTRYPOINT ["/entrypoint.sh"] 480 CMD echo foobar` 481 482 ctx, err := fakeContext(dockerfile, map[string]string{ 483 "entrypoint.sh": `#!/bin/sh 484 echo "I am an entrypoint" 485 exec "$@"`, 486 }) 487 c.Assert(err, check.IsNil) 488 defer ctx.Close() 489 490 _, err = buildImageFromContext(name, ctx, true) 491 c.Assert(err, check.IsNil) 492 493 out, _ := dockerCmd(c, "create", "--entrypoint=", name, "echo", "foo") 494 id := strings.TrimSpace(out) 495 c.Assert(id, check.Not(check.Equals), "") 496 out, _ = dockerCmd(c, "start", "-a", id) 497 c.Assert(strings.TrimSpace(out), check.Equals, "foo") 498 } 499 500 // #22471 501 func (s *DockerSuite) TestCreateStopTimeout(c *check.C) { 502 name1 := "test_create_stop_timeout_1" 503 dockerCmd(c, "create", "--name", name1, "--stop-timeout", "15", "busybox") 504 505 res := inspectFieldJSON(c, name1, "Config.StopTimeout") 506 c.Assert(res, checker.Contains, "15") 507 508 name2 := "test_create_stop_timeout_2" 509 dockerCmd(c, "create", "--name", name2, "busybox") 510 511 res = inspectFieldJSON(c, name2, "Config.StopTimeout") 512 c.Assert(res, checker.Contains, "null") 513 }