Skip to content

Commit 61e5275

Browse files
committed
Add subpath support to volumes in --mount option
All the backend work was done a while back for image volumes, so this is effectively just plumbing the option in for volumes in the parser logic. It's a little uglier than I'd like because our volume mount parser produces an OCI Spec mount struct, which doesn't have a field for subpath, so we have to pass through the options array and parse it back out after, which is a little gross. But not gross enough to rewrite that parsing logic. Fixes #20661 Signed-off-by: Matt Heon <mheon@redhat.com>
1 parent 50714d2 commit 61e5275

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed

libpod/container.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ type ContainerNamedVolume struct {
257257
// This is used for emptyDir volumes from a kube yaml
258258
IsAnonymous bool `json:"setAnonymous,omitempty"`
259259
// SubPath determines which part of the Source will be mounted in the container
260-
SubPath string
260+
SubPath string `json:",omitempty"`
261261
}
262262

263263
// ContainerOverlayVolume is an overlay volume that will be mounted into the

pkg/specgenutil/volumes.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,14 @@ func parseMountOptions(mountType string, args []string) (*spec.Mount, error) {
377377
return nil, fmt.Errorf("host directory cannot be empty: %w", errOptionArg)
378378
}
379379
mnt.Source = value
380+
case "subpath", "volume-subpath":
381+
if mountType != define.TypeVolume {
382+
return nil, fmt.Errorf("cannot set option %q on non-volume mounts", name)
383+
}
384+
if !hasValue {
385+
return nil, fmt.Errorf("%v: %w", name, errOptionArg)
386+
}
387+
mnt.Options = append(mnt.Options, fmt.Sprintf("subpath=%s", value))
380388
case "target", "dst", "destination":
381389
if mnt.Destination != "" {
382390
return nil, fmt.Errorf("cannot pass %q option more than once: %w", name, errOptionArg)
@@ -579,7 +587,21 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) {
579587
if len(mnt.Destination) == 0 {
580588
return nil, errNoDest
581589
}
582-
newVolume.Options = mnt.Options
590+
591+
safeOpts := make([]string, 0, len(mnt.Options))
592+
for _, opt := range mnt.Options {
593+
splitOpt := strings.SplitN(opt, "=", 2)
594+
if splitOpt[0] == "subpath" {
595+
if len(splitOpt) != 2 {
596+
return nil, fmt.Errorf("subpath was not provided a path")
597+
}
598+
newVolume.SubPath = splitOpt[1]
599+
} else {
600+
safeOpts = append(safeOpts, opt)
601+
}
602+
}
603+
604+
newVolume.Options = safeOpts
583605
newVolume.Name = mnt.Source
584606
newVolume.Dest = mnt.Destination
585607
return newVolume, nil

test/e2e/run_volume_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,4 +1069,24 @@ RUN chmod 755 /test1 /test2 /test3`, ALPINE)
10691069

10701070
mountVolumeAndCheckDirectory(volName, "/test3", "test2", imgName)
10711071
})
1072+
1073+
It("podman run --mount type=volume,subpath=", func() {
1074+
volName := "testvol"
1075+
mkvol := podmanTest.Podman([]string{"volume", "create", volName})
1076+
mkvol.WaitWithDefaultTimeout()
1077+
Expect(mkvol).Should(ExitCleanly())
1078+
1079+
subvol := "/test/test2/"
1080+
pathInCtr := "/mnt"
1081+
pathToCreate := filepath.Join(pathInCtr, subvol)
1082+
popvol := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/mnt", volName), ALPINE, "sh", "-c", fmt.Sprintf("mkdir -p %s; touch %s; touch %s", pathToCreate, filepath.Join(pathToCreate, "foo"), filepath.Join(pathToCreate, "bar"))})
1083+
popvol.WaitWithDefaultTimeout()
1084+
Expect(popvol).Should(ExitCleanly())
1085+
1086+
checkCtr := podmanTest.Podman([]string{"run", "--mount", fmt.Sprintf("type=volume,source=%s,target=%s,subpath=%s", volName, pathInCtr, subvol), ALPINE, "ls", pathInCtr})
1087+
checkCtr.WaitWithDefaultTimeout()
1088+
Expect(checkCtr).To(ExitCleanly())
1089+
Expect(checkCtr.OutputToString()).To(ContainSubstring("foo"))
1090+
Expect(checkCtr.OutputToString()).To(ContainSubstring("bar"))
1091+
})
10721092
})

0 commit comments

Comments
 (0)