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