mirror of https://github.com/containers/podman.git
Merge pull request #19309 from rhatdan/volumes
Add glob support to podman run/create --mount
This commit is contained in:
commit
538ac5dc8f
|
@ -6,7 +6,7 @@
|
|||
|
||||
Attach a filesystem mount to the container
|
||||
|
||||
Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and **devpts**. <sup>[[1]](#Footnote1)</sup>
|
||||
Current supported mount TYPEs are **bind**, **devpts**, **glob**, **image**, **tmpfs** and **volume**. <sup>[[1]](#Footnote1)</sup>
|
||||
|
||||
e.g.
|
||||
|
||||
|
@ -16,6 +16,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and
|
|||
|
||||
type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared,U=true
|
||||
|
||||
type=glob,src=/usr/lib/libfoo*,destination=/usr/lib,ro=true
|
||||
|
||||
type=volume,source=vol1,destination=/path/in/container,ro=true
|
||||
|
||||
type=tmpfs,tmpfs-size=512M,destination=/path/in/container
|
||||
|
@ -26,10 +28,12 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and
|
|||
|
||||
Common Options:
|
||||
|
||||
· src, source: mount source spec for bind and volume. Mandatory for bind.
|
||||
· src, source: mount source spec for bind, glob, and volume. Mandatory for bind and glob.
|
||||
|
||||
· dst, destination, target: mount destination spec.
|
||||
|
||||
Paths matching globs, are mounted on the destination directory with the identical name inside the container.
|
||||
|
||||
Options specific to volume:
|
||||
|
||||
· ro, readonly: true or false (default).
|
||||
|
@ -47,7 +51,7 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and
|
|||
|
||||
· rw, readwrite: true or false (default).
|
||||
|
||||
Options specific to bind:
|
||||
Options specific to bind and glob:
|
||||
|
||||
· ro, readonly: true or false (default).
|
||||
|
||||
|
|
|
@ -443,6 +443,12 @@ $ podman create --name container3 --requires container1,container2 -t -i fedora
|
|||
$ podman start --attach container3
|
||||
```
|
||||
|
||||
### Exposing shared libraries inside of container as read-only using a glob
|
||||
|
||||
```
|
||||
$ podman create --mount type=glob,src=/usr/lib64/libnvidia\*,ro -i -t fedora /bin/bash
|
||||
```
|
||||
|
||||
### Configure keep supplemental groups for access to volume
|
||||
|
||||
```
|
||||
|
|
|
@ -468,6 +468,12 @@ $ podman run --read-only -i -t fedora /bin/bash
|
|||
$ podman run --read-only --read-only-tmpfs=false --tmpfs /run -i -t fedora /bin/bash
|
||||
```
|
||||
|
||||
### Exposing shared libraries inside of container as read-only using a glob
|
||||
|
||||
```
|
||||
$ podman run --mount type=glob,src=/usr/lib64/libnvidia\*,ro=true -i -t fedora /bin/bash
|
||||
```
|
||||
|
||||
### Exposing log messages from the container to the host's log
|
||||
|
||||
Bind mount the _/dev/log_ directory to have messages that are logged in the container show up in the host's
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
|
@ -18,7 +19,7 @@ import (
|
|||
var (
|
||||
errOptionArg = errors.New("must provide an argument for option")
|
||||
errNoDest = errors.New("must set volume destination")
|
||||
errInvalidSyntax = errors.New("incorrect mount format: should be --mount type=<bind|tmpfs|volume>,[src=<host-dir|volume-name>,]target=<ctr-dir>[,options]")
|
||||
errInvalidSyntax = errors.New("incorrect mount format: should be --mount type=<bind|glob|tmpfs|volume>,[src=<host-dir|volume-name>,]target=<ctr-dir>[,options]")
|
||||
)
|
||||
|
||||
// Parse all volume-related options in the create config into a set of mounts
|
||||
|
@ -196,6 +197,20 @@ func Mounts(mountFlag []string, configMounts []string) (map[string]spec.Mount, m
|
|||
return fmt.Errorf("%v: %w", mount.Destination, specgen.ErrDuplicateDest)
|
||||
}
|
||||
finalMounts[mount.Destination] = mount
|
||||
case "glob":
|
||||
mounts, err := getGlobMounts(tokens)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, mount := range mounts {
|
||||
if _, ok := finalMounts[mount.Destination]; ok {
|
||||
if ignoreDup {
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("%v: %w", mount.Destination, specgen.ErrDuplicateDest)
|
||||
}
|
||||
finalMounts[mount.Destination] = mount
|
||||
}
|
||||
case define.TypeTmpfs:
|
||||
mount, err := getTmpfsMount(tokens)
|
||||
if err != nil {
|
||||
|
@ -438,12 +453,49 @@ func parseMountOptions(mountType string, args []string) (*spec.Mount, error) {
|
|||
return nil, fmt.Errorf("%s: %w", kv[0], util.ErrBadMntOption)
|
||||
}
|
||||
}
|
||||
if len(mnt.Destination) == 0 {
|
||||
if mountType != "glob" && len(mnt.Destination) == 0 {
|
||||
return nil, errNoDest
|
||||
}
|
||||
return &mnt, nil
|
||||
}
|
||||
|
||||
// Parse glob mounts entry from the --mount flag.
|
||||
func getGlobMounts(args []string) ([]spec.Mount, error) {
|
||||
mounts := []spec.Mount{}
|
||||
|
||||
mnt, err := parseMountOptions("glob", args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
globs, err := filepath.Glob(mnt.Source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(globs) == 0 {
|
||||
return nil, fmt.Errorf("no file paths matching glob %q", mnt.Source)
|
||||
}
|
||||
|
||||
options, err := parse.ValidateVolumeOpts(mnt.Options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, src := range globs {
|
||||
var newMount spec.Mount
|
||||
newMount.Type = define.TypeBind
|
||||
newMount.Options = options
|
||||
newMount.Source = src
|
||||
if len(mnt.Destination) == 0 {
|
||||
newMount.Destination = src
|
||||
} else {
|
||||
newMount.Destination = filepath.Join(mnt.Destination, filepath.Base(src))
|
||||
}
|
||||
mounts = append(mounts, newMount)
|
||||
}
|
||||
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
// Parse a single bind mount entry from the --mount flag.
|
||||
func getBindMount(args []string) (spec.Mount, error) {
|
||||
newMount := spec.Mount{
|
||||
|
|
|
@ -664,7 +664,7 @@ func ConvertContainer(container *parser.UnitFile, names map[string]string, isUse
|
|||
paramsMap[kv[0]] = kv[1]
|
||||
}
|
||||
if paramType, ok := paramsMap["type"]; ok {
|
||||
if paramType == "volume" || paramType == "bind" {
|
||||
if paramType == "volume" || paramType == "bind" || paramType == "glob" {
|
||||
var err error
|
||||
if paramSource, ok := paramsMap["source"]; ok {
|
||||
paramsMap["source"], err = handleStorageSource(container, service, paramSource, names)
|
||||
|
|
|
@ -247,4 +247,43 @@ EOF
|
|||
buildah rm $external_cid
|
||||
}
|
||||
|
||||
@test "podman volume globs" {
|
||||
v1a=v1_$(random_string)
|
||||
v1b=v1_$(random_string)
|
||||
v2=v2_$(random_string)
|
||||
vol1a=${PODMAN_TMPDIR}/$v1a
|
||||
vol1b=${PODMAN_TMPDIR}/$v1b
|
||||
vol2=${PODMAN_TMPDIR}/$v2
|
||||
touch $vol1a $vol1b $vol2
|
||||
|
||||
# if volumes source and dest match then pass
|
||||
run_podman run --rm --mount type=glob,src=${PODMAN_TMPDIR}/v1\*,ro $IMAGE ls $vol1a $vol1b
|
||||
run_podman 1 run --rm --mount source=${PODMAN_TMPDIR}/v1\*,type=glob,ro $IMAGE ls $vol2
|
||||
is "$output" ".*No such file or directory" "$vol2 should not be mounted in the container"
|
||||
|
||||
run_podman 125 run --rm --mount source=${PODMAN_TMPDIR}/v3\*,type=glob,ro $IMAGE ls $vol2
|
||||
is "$output" "Error: no file paths matching glob \"${PODMAN_TMPDIR}/v3\*\"" "Glob does not match so should throw error"
|
||||
|
||||
run_podman 1 run --rm --mount source=${PODMAN_TMPDIR}/v2\*,type=glob,ro,Z $IMAGE touch $vol2
|
||||
is "$output" "touch: $vol2: Read-only file system" "Mount should be read-only"
|
||||
|
||||
run_podman run --rm --mount source=${PODMAN_TMPDIR}/v2\*,type=glob,ro=false,Z $IMAGE touch $vol2
|
||||
|
||||
run_podman run --rm --mount type=glob,src=${PODMAN_TMPDIR}/v1\*,destination=/non/existing/directory,ro $IMAGE ls /non/existing/directory
|
||||
is "$output" ".*$v1a" "podman images --inspect should include $v1a"
|
||||
is "$output" ".*$v1b" "podman images --inspect should include $v1b"
|
||||
|
||||
run_podman create --rm --mount type=glob,src=${PODMAN_TMPDIR}/v1\*,ro $IMAGE ls $vol1a $vol1b
|
||||
cid=$output
|
||||
run_podman container inspect $output
|
||||
is "$output" ".*$vol1a" "podman images --inspect should include $vol1a"
|
||||
is "$output" ".*$vol1b" "podman images --inspect should include $vol1b"
|
||||
|
||||
run_podman 125 run --rm --mount source=${PODMAN_TMPDIR}/v2\*,type=bind,ro=false $IMAGE touch $vol2
|
||||
is "$output" "Error: must set volume destination" "Bind mounts require destination"
|
||||
|
||||
run_podman 125 run --rm --mount source=${PODMAN_TMPDIR}/v2\*,destination=/tmp/foobar, ro=false $IMAGE touch $vol2
|
||||
is "$output" "Error: invalid reference format" "Default mounts don not support globs"
|
||||
}
|
||||
|
||||
# vim: filetype=sh
|
||||
|
|
Loading…
Reference in New Issue