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