github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/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 }