Skip to content

Commit edc09e6

Browse files
committed
mount: Add volume-subpath option
Signed-off-by: Paweł Gronowski <[email protected]>
1 parent a253318 commit edc09e6

2 files changed

Lines changed: 57 additions & 0 deletions

File tree

e2e/container/run_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package container
22

33
import (
44
"fmt"
5+
"strings"
56
"testing"
67

78
"github.com/docker/cli/e2e/internal/fixtures"
89
"github.com/docker/cli/internal/test/environment"
10+
"github.com/docker/docker/api/types/versions"
911
"gotest.tools/v3/assert"
1012
is "gotest.tools/v3/assert/cmp"
1113
"gotest.tools/v3/golden"
@@ -149,3 +151,56 @@ func TestRunWithCgroupNamespace(t *testing.T) {
149151
"cat", "/sys/fs/cgroup/cgroup.controllers")
150152
result.Assert(t, icmd.Success)
151153
}
154+
155+
func TestMountSubvolume(t *testing.T) {
156+
skip.If(t, versions.LessThan(environment.DaemonAPIVersion(t), "1.45"))
157+
158+
volName := "test-volume-" + t.Name()
159+
icmd.RunCommand("docker", "volume", "create", volName).Assert(t, icmd.Success)
160+
161+
t.Cleanup(func() {
162+
icmd.RunCommand("docker", "volume", "remove", "-f", volName).Assert(t, icmd.Success)
163+
})
164+
165+
defaultMountOpts := []string{
166+
"type=volume",
167+
"src=" + volName,
168+
"dst=/volume",
169+
}
170+
171+
// Populate the volume with test data.
172+
icmd.RunCommand("docker", "run", "--rm", "--mount", strings.Join(defaultMountOpts, ","), fixtures.AlpineImage, "sh", "-c",
173+
"echo foo > /volume/bar.txt && "+
174+
"mkdir /volume/etc && echo root > /volume/etc/passwd && "+
175+
"mkdir /volume/subdir && echo world > /volume/subdir/hello.txt;",
176+
).Assert(t, icmd.Success)
177+
178+
runMount := func(cmd string, mountOpts ...string) *icmd.Result {
179+
mountArg := strings.Join(append(defaultMountOpts, mountOpts...), ",")
180+
return icmd.RunCommand("docker", "run", "--rm", "--mount", mountArg, fixtures.AlpineImage, cmd, "/volume")
181+
}
182+
183+
for _, tc := range []struct {
184+
name string
185+
cmd string
186+
subpath string
187+
188+
expectedOut string
189+
expectedErr string
190+
expectedCode int
191+
}{
192+
{name: "absolute", cmd: "cat", subpath: "/etc/passwd", expectedErr: "subpath must be a relative path within the volume", expectedCode: 125},
193+
{name: "subpath not exists", cmd: "ls", subpath: "some-path/that/doesnt-exist", expectedErr: "cannot access path ", expectedCode: 127},
194+
{name: "subdirectory mount", cmd: "ls", subpath: "subdir", expectedOut: "hello.txt"},
195+
{name: "file mount", cmd: "cat", subpath: "bar.txt", expectedOut: "foo"},
196+
} {
197+
tc := tc
198+
t.Run(tc.name, func(t *testing.T) {
199+
runMount(tc.cmd, "volume-subpath="+tc.subpath).Assert(t, icmd.Expected{
200+
Err: tc.expectedErr,
201+
ExitCode: tc.expectedCode,
202+
Out: tc.expectedOut,
203+
})
204+
})
205+
}
206+
}

opts/mount.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ func (m *MountOpt) Set(value string) error {
131131
return fmt.Errorf("invalid value for %s: %s (must be \"enabled\", \"disabled\", \"writable\", or \"readonly\")",
132132
key, val)
133133
}
134+
case "volume-subpath":
135+
volumeOptions().Subpath = val
134136
case "volume-nocopy":
135137
volumeOptions().NoCopy, err = strconv.ParseBool(val)
136138
if err != nil {

0 commit comments

Comments
 (0)