Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions e2e/container/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package container

import (
"fmt"
"strings"
"testing"

"github.com/docker/cli/e2e/internal/fixtures"
"github.com/docker/cli/internal/test/environment"
"github.com/docker/docker/api/types/versions"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/golden"
Expand Down Expand Up @@ -149,3 +151,56 @@ func TestRunWithCgroupNamespace(t *testing.T) {
"cat", "/sys/fs/cgroup/cgroup.controllers")
result.Assert(t, icmd.Success)
}

func TestMountSubvolume(t *testing.T) {
skip.If(t, versions.LessThan(environment.DaemonAPIVersion(t), "1.45"))

volName := "test-volume-" + t.Name()
icmd.RunCommand("docker", "volume", "create", volName).Assert(t, icmd.Success)

t.Cleanup(func() {
icmd.RunCommand("docker", "volume", "remove", "-f", volName).Assert(t, icmd.Success)
})

defaultMountOpts := []string{
"type=volume",
"src=" + volName,
"dst=/volume",
}

// Populate the volume with test data.
icmd.RunCommand("docker", "run", "--rm", "--mount", strings.Join(defaultMountOpts, ","), fixtures.AlpineImage, "sh", "-c",
"echo foo > /volume/bar.txt && "+
"mkdir /volume/etc && echo root > /volume/etc/passwd && "+
"mkdir /volume/subdir && echo world > /volume/subdir/hello.txt;",
).Assert(t, icmd.Success)

runMount := func(cmd string, mountOpts ...string) *icmd.Result {
mountArg := strings.Join(append(defaultMountOpts, mountOpts...), ",")
return icmd.RunCommand("docker", "run", "--rm", "--mount", mountArg, fixtures.AlpineImage, cmd, "/volume")
}

for _, tc := range []struct {
name string
cmd string
subpath string

expectedOut string
expectedErr string
expectedCode int
}{
{name: "absolute", cmd: "cat", subpath: "/etc/passwd", expectedErr: "subpath must be a relative path within the volume", expectedCode: 125},
{name: "subpath not exists", cmd: "ls", subpath: "some-path/that/doesnt-exist", expectedErr: "cannot access path ", expectedCode: 127},
{name: "subdirectory mount", cmd: "ls", subpath: "subdir", expectedOut: "hello.txt"},
{name: "file mount", cmd: "cat", subpath: "bar.txt", expectedOut: "foo"},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
runMount(tc.cmd, "volume-subpath="+tc.subpath).Assert(t, icmd.Expected{
Err: tc.expectedErr,
ExitCode: tc.expectedCode,
Out: tc.expectedOut,
})
})
}
}
2 changes: 2 additions & 0 deletions opts/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ func (m *MountOpt) Set(value string) error {
return fmt.Errorf("invalid value for %s: %s (must be \"enabled\", \"disabled\", \"writable\", or \"readonly\")",
key, val)
}
case "volume-subpath":
volumeOptions().Subpath = val
case "volume-nocopy":
volumeOptions().NoCopy, err = strconv.ParseBool(val)
if err != nil {
Expand Down