mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
3694c1e34e
This adds MaskedPaths and ReadOnlyPaths options to HostConfig for containers so that a user can override the default values. When the value sent through the API is nil the default is used. Otherwise the default is overridden. Adds integration tests for MaskedPaths and ReadonlyPaths. Signed-off-by: Jess Frazelle <acidburn@microsoft.com>
303 lines
7.2 KiB
Go
303 lines
7.2 KiB
Go
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"
|
|
"github.com/gotestyourself/gotestyourself/assert"
|
|
is "github.com/gotestyourself/gotestyourself/assert/cmp"
|
|
"github.com/gotestyourself/gotestyourself/poll"
|
|
"github.com/gotestyourself/gotestyourself/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)
|
|
}
|
|
}
|