package container // import "github.com/docker/docker/integration/container" import ( "context" "encoding/json" "fmt" "strconv" "testing" "time" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" ctr "github.com/docker/docker/integration/internal/container" "github.com/docker/docker/internal/test/request" "github.com/docker/docker/oci" "gotest.tools/assert" is "gotest.tools/assert/cmp" "gotest.tools/poll" "gotest.tools/skip" ) func TestCreateFailsWhenIdentifierDoesNotExist(t *testing.T) { defer setupTest(t)() client := request.NewAPIClient(t) testCases := []struct { doc string image string expectedError string }{ { doc: "image and tag", image: "test456:v1", expectedError: "No such image: test456:v1", }, { doc: "image no tag", image: "test456", expectedError: "No such image: test456", }, { doc: "digest", image: "sha256:0cb40641836c461bc97c793971d84d758371ed682042457523e4ae701efeaaaa", expectedError: "No such image: sha256:0cb40641836c461bc97c793971d84d758371ed682042457523e4ae701efeaaaa", }, } for _, tc := range testCases { tc := tc t.Run(tc.doc, func(t *testing.T) { t.Parallel() _, err := client.ContainerCreate(context.Background(), &container.Config{Image: tc.image}, &container.HostConfig{}, &network.NetworkingConfig{}, "", ) assert.Check(t, is.ErrorContains(err, tc.expectedError)) }) } } func TestCreateWithInvalidEnv(t *testing.T) { defer setupTest(t)() client := request.NewAPIClient(t) testCases := []struct { env string expectedError string }{ { env: "", expectedError: "invalid environment variable:", }, { env: "=", expectedError: "invalid environment variable: =", }, { env: "=foo", expectedError: "invalid environment variable: =foo", }, } for index, tc := range testCases { tc := tc t.Run(strconv.Itoa(index), func(t *testing.T) { t.Parallel() _, err := client.ContainerCreate(context.Background(), &container.Config{ Image: "busybox", Env: []string{tc.env}, }, &container.HostConfig{}, &network.NetworkingConfig{}, "", ) assert.Check(t, is.ErrorContains(err, tc.expectedError)) }) } } // Test case for #30166 (target was not validated) func TestCreateTmpfsMountsTarget(t *testing.T) { skip.If(t, testEnv.DaemonInfo.OSType != "linux") defer setupTest(t)() client := request.NewAPIClient(t) testCases := []struct { target string expectedError string }{ { target: ".", expectedError: "mount path must be absolute", }, { target: "foo", expectedError: "mount path must be absolute", }, { target: "/", expectedError: "destination can't be '/'", }, { target: "//", expectedError: "destination can't be '/'", }, } for _, tc := range testCases { _, err := client.ContainerCreate(context.Background(), &container.Config{ Image: "busybox", }, &container.HostConfig{ Tmpfs: map[string]string{tc.target: ""}, }, &network.NetworkingConfig{}, "", ) assert.Check(t, is.ErrorContains(err, tc.expectedError)) } } func TestCreateWithCustomMaskedPaths(t *testing.T) { skip.If(t, testEnv.DaemonInfo.OSType != "linux") defer setupTest(t)() client := request.NewAPIClient(t) ctx := context.Background() testCases := []struct { maskedPaths []string expected []string }{ { maskedPaths: []string{}, expected: []string{}, }, { maskedPaths: nil, expected: oci.DefaultSpec().Linux.MaskedPaths, }, { maskedPaths: []string{"/proc/kcore", "/proc/keys"}, expected: []string{"/proc/kcore", "/proc/keys"}, }, } checkInspect := func(t *testing.T, ctx context.Context, name string, expected []string) { _, b, err := client.ContainerInspectWithRaw(ctx, name, false) assert.NilError(t, err) var inspectJSON map[string]interface{} err = json.Unmarshal(b, &inspectJSON) assert.NilError(t, err) cfg, ok := inspectJSON["HostConfig"].(map[string]interface{}) assert.Check(t, is.Equal(true, ok), name) maskedPaths, ok := cfg["MaskedPaths"].([]interface{}) assert.Check(t, is.Equal(true, ok), name) mps := []string{} for _, mp := range maskedPaths { mps = append(mps, mp.(string)) } assert.DeepEqual(t, expected, mps) } for i, tc := range testCases { name := fmt.Sprintf("create-masked-paths-%d", i) config := container.Config{ Image: "busybox", Cmd: []string{"true"}, } hc := container.HostConfig{} if tc.maskedPaths != nil { hc.MaskedPaths = tc.maskedPaths } // Create the container. c, err := client.ContainerCreate(context.Background(), &config, &hc, &network.NetworkingConfig{}, name, ) assert.NilError(t, err) checkInspect(t, ctx, name, tc.expected) // Start the container. err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{}) assert.NilError(t, err) poll.WaitOn(t, ctr.IsInState(ctx, client, c.ID, "exited"), poll.WithDelay(100*time.Millisecond)) checkInspect(t, ctx, name, tc.expected) } } func TestCreateWithCustomReadonlyPaths(t *testing.T) { skip.If(t, testEnv.DaemonInfo.OSType != "linux") defer setupTest(t)() client := request.NewAPIClient(t) ctx := context.Background() testCases := []struct { doc string readonlyPaths []string expected []string }{ { readonlyPaths: []string{}, expected: []string{}, }, { readonlyPaths: nil, expected: oci.DefaultSpec().Linux.ReadonlyPaths, }, { readonlyPaths: []string{"/proc/asound", "/proc/bus"}, expected: []string{"/proc/asound", "/proc/bus"}, }, } checkInspect := func(t *testing.T, ctx context.Context, name string, expected []string) { _, b, err := client.ContainerInspectWithRaw(ctx, name, false) assert.NilError(t, err) var inspectJSON map[string]interface{} err = json.Unmarshal(b, &inspectJSON) assert.NilError(t, err) cfg, ok := inspectJSON["HostConfig"].(map[string]interface{}) assert.Check(t, is.Equal(true, ok), name) readonlyPaths, ok := cfg["ReadonlyPaths"].([]interface{}) assert.Check(t, is.Equal(true, ok), name) rops := []string{} for _, rop := range readonlyPaths { rops = append(rops, rop.(string)) } assert.DeepEqual(t, expected, rops) } for i, tc := range testCases { name := fmt.Sprintf("create-readonly-paths-%d", i) config := container.Config{ Image: "busybox", Cmd: []string{"true"}, } hc := container.HostConfig{} if tc.readonlyPaths != nil { hc.ReadonlyPaths = tc.readonlyPaths } // Create the container. c, err := client.ContainerCreate(context.Background(), &config, &hc, &network.NetworkingConfig{}, name, ) assert.NilError(t, err) checkInspect(t, ctx, name, tc.expected) // Start the container. err = client.ContainerStart(ctx, c.ID, types.ContainerStartOptions{}) assert.NilError(t, err) poll.WaitOn(t, ctr.IsInState(ctx, client, c.ID, "exited"), poll.WithDelay(100*time.Millisecond)) checkInspect(t, ctx, name, tc.expected) } }