Merge pull request #20356 from vrothberg/RUN-1935

new 'no-dereference' mount option
This commit is contained in:
openshift-merge-bot[bot]
2023-11-21 14:40:03 +00:00
committed by GitHub
10 changed files with 105 additions and 10 deletions

View File

@ -75,6 +75,8 @@ Current supported mount TYPEs are **bind**, **devpts**, **glob**, **image**, **r
. U, chown: true or false (default). Change recursively the owner and group of the source volume based on the UID and GID of the container.
. no-dereference: do not dereference symlinks but copy the link source into the mount destination.
Options specific to tmpfs and ramfs:
· ro, readonly: true or false (default).

2
go.mod
View File

@ -12,7 +12,7 @@ require (
github.com/containernetworking/cni v1.1.2
github.com/containernetworking/plugins v1.3.0
github.com/containers/buildah v1.33.1
github.com/containers/common v0.57.0
github.com/containers/common v0.57.1-0.20231121105603-d54dcfe962d6
github.com/containers/conmon v2.0.20+incompatible
github.com/containers/gvisor-tap-vsock v0.7.1
github.com/containers/image/v5 v5.29.0

4
go.sum
View File

@ -255,8 +255,8 @@ github.com/containernetworking/plugins v1.3.0 h1:QVNXMT6XloyMUoO2wUOqWTC1hWFV62Q
github.com/containernetworking/plugins v1.3.0/go.mod h1:Pc2wcedTQQCVuROOOaLBPPxrEXqqXBFt3cZ+/yVg6l0=
github.com/containers/buildah v1.33.1 h1:s+5LaZx+vkOV/BboM6QZbf0Uma/A9W/B1REoUiM3CQo=
github.com/containers/buildah v1.33.1/go.mod h1:xEvekGaEeflDV4kxdKcTk0NbTuV4FsbPW4UYReLkHIw=
github.com/containers/common v0.57.0 h1:5O/+6QUBafKK0/zeok9y1rLPukfWgdE0sT4nuzmyAqk=
github.com/containers/common v0.57.0/go.mod h1:t/Z+/sFrapvFMEJe3YnecN49/Tae2wYEQShbEN6SRaU=
github.com/containers/common v0.57.1-0.20231121105603-d54dcfe962d6 h1:4IAcuB9ZYlMIX5rnap2ax9IdFtivbTvUIPh7WgUglvU=
github.com/containers/common v0.57.1-0.20231121105603-d54dcfe962d6/go.mod h1:gUsz+eYo0q1NMwiukwI8E6LAqyYd0DapZ71hKC+MbJw=
github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg=
github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I=
github.com/containers/gvisor-tap-vsock v0.7.1 h1:+Rc+sOPplrkQb/BUXeN0ug8TxjgyrIqo/9P/eNS2A4c=

View File

@ -366,7 +366,11 @@ func (c *Container) generateSpec(ctx context.Context) (s *spec.Spec, cleanupFunc
if err := c.relabel(m.Source, c.MountLabel(), label.IsShared(o)); err != nil {
return nil, nil, err
}
case "no-dereference":
// crun calls the option `copy-symlink`.
// Podman decided for --no-dereference as many
// bin-utils tools (e..g, touch, chown, cp) do.
options = append(options, "copy-symlink")
default:
options = append(options, o)
}

View File

@ -355,7 +355,7 @@ func parseMountOptions(mountType string, args []string) (*spec.Mount, error) {
default:
return nil, fmt.Errorf("%s mount option must be 'private' or 'shared': %w", kv[0], util.ErrBadMntOption)
}
case "shared", "rshared", "private", "rprivate", "slave", "rslave", "unbindable", "runbindable", "Z", "z":
case "shared", "rshared", "private", "rprivate", "slave", "rslave", "unbindable", "runbindable", "Z", "z", "no-dereference":
mnt.Options = append(mnt.Options, kv[0])
case "src", "source":
if mountType == define.TypeTmpfs {

View File

@ -28,7 +28,7 @@ type defaultMountOptions struct {
// The sourcePath variable, if not empty, contains a bind mount source.
func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string, error) {
var (
foundWrite, foundSize, foundProp, foundMode, foundExec, foundSuid, foundDev, foundCopyUp, foundBind, foundZ, foundU, foundOverlay, foundIdmap, foundCopy, foundNoSwap bool
foundWrite, foundSize, foundProp, foundMode, foundExec, foundSuid, foundDev, foundCopyUp, foundBind, foundZ, foundU, foundOverlay, foundIdmap, foundCopy, foundNoSwap, foundNoDereference bool
)
newOptions := make([]string, 0, len(options))
@ -148,6 +148,11 @@ func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string
foundNoSwap = true
newOptions = append(newOptions, opt)
continue
case "no-dereference":
if foundNoDereference {
return nil, fmt.Errorf("the 'no-dereference' option can only be set once: %w", ErrDupeMntOption)
}
foundNoDereference = true
case define.TypeBind, "rbind":
if isTmpfs {
return nil, fmt.Errorf("the 'bind' and 'rbind' options are not allowed with tmpfs mounts: %w", ErrBadMntOption)

View File

@ -321,4 +321,83 @@ EOF
fi
}
# vim: filetype=sh
@test "podman mount no-dereference" {
# Test how bind and glob-mounts behave with respect to relative (rel) and
# absolute (abs) symlinks.
if [ $(podman_runtime) != "crun" ]; then
# Requires crun >= 1.11.0
skip "only crun supports the no-dereference (copy-symlink) mount option"
fi
# One directory for testing relative symlinks, another for absolute ones.
rel_dir=$PODMAN_TMPDIR/rel-dir
abs_dir=$PODMAN_TMPDIR/abs-dir
mkdir $rel_dir $abs_dir
# Create random values to discrimate data in the rel/abs directory and the
# one from the image.
rel_random_host="rel_on_the_host_$(random_string 15)"
abs_random_host="abs_on_the_host_$(random_string 15)"
random_img="on_the_image_$(random_string 15)"
# Relative symlink
echo "$rel_random_host" > $rel_dir/data
ln -r -s $rel_dir/data $rel_dir/link
# Absolute symlink
echo "$abs_random_host" > $abs_dir/data
ln -s $abs_dir/data $abs_dir/link
dockerfile=$PODMAN_TMPDIR/Dockerfile
cat >$dockerfile <<EOF
FROM $IMAGE
RUN echo $random_img > /tmp/data
EOF
img="localhost/preserve:symlinks"
run_podman build -t $img -f $dockerfile
link_path="/tmp/link"
create_path="/tmp/i/do/not/exist/link"
tests="
0 | bind | $rel_dir/link | /tmp/link | | /tmp/link | $rel_random_host | $link_path | bind mount relative symlink: mounts target from the host
0 | bind | $abs_dir/link | /tmp/link | | /tmp/link | $abs_random_host | $link_path | bind mount absolute symlink: mounts target from the host
0 | glob | $rel_dir/lin* | /tmp/ | | /tmp/link | $rel_random_host | $link_path | glob mount relative symlink: mounts target from the host
0 | glob | $abs_dir/lin* | /tmp/ | | /tmp/link | $abs_random_host | $link_path | glob mount absolute symlink: mounts target from the host
0 | glob | $rel_dir/* | /tmp/ | | /tmp/link | $rel_random_host | $link_path | glob mount entire directory: mounts relative target from the host
0 | glob | $abs_dir/* | /tmp/ | | /tmp/link | $abs_random_host | $link_path | glob mount entire directory: mounts absolute target from the host
0 | bind | $rel_dir/link | /tmp/link | ,no-dereference | '/tmp/link' -> 'data' | $random_img | $link_path | no_deref: bind mount relative symlink: points to file on the image
0 | glob | $rel_dir/lin* | /tmp/ | ,no-dereference | '/tmp/link' -> 'data' | $random_img | $link_path | no_deref: glob mount relative symlink: points to file on the image
0 | bind | $rel_dir/ | /tmp/ | ,no-dereference | '/tmp/link' -> 'data' | $rel_random_host | $link_path | no_deref: bind mount the entire directory: preserves symlink automatically
0 | glob | $rel_dir/* | /tmp/ | ,no-dereference | '/tmp/link' -> 'data' | $rel_random_host | $link_path | no_deref: glob mount the entire directory: preserves symlink automatically
1 | bind | $abs_dir/link | /tmp/link | ,no-dereference | '/tmp/link' -> '$abs_dir/data' | cat: can't open '/tmp/link': No such file or directory | $link_path | bind mount *preserved* absolute symlink: now points to a non-existent file on the container
1 | glob | $abs_dir/lin* | /tmp/ | ,no-dereference | '/tmp/link' -> '$abs_dir/data' | cat: can't open '/tmp/link': No such file or directory | $link_path | glob mount *preserved* absolute symlink: now points to a non-existent file on the container
0 | bind | $rel_dir/link | $create_path | | $create_path | $rel_random_host | $create_path | bind mount relative symlink: creates dirs and mounts target from the host
1 | bind | $rel_dir/link | $create_path | ,no-dereference | '$create_path' -> 'data' | cat: can't open '$create_path': No such file or directory | $create_path | no_deref: bind mount relative symlink: creates dirs and mounts target from the host
"
while read exit_code mount_type mount_src mount_dst mount_opts line_0 line_1 path description; do
if [[ $mount_opts == "''" ]];then
unset mount_opts
fi
run_podman $exit_code run \
--mount type=$mount_type,src=$mount_src,dst=$mount_dst$mount_opts \
--rm --privileged $img sh -c "stat -c '%N' $path; cat $path"
assert "${lines[0]}" = "$line_0" "$description"
assert "${lines[1]}" = "$line_1" "$description"
done < <(parse_table "$tests")
# Make sure that it's presvered across starts and stops
run_podman create --mount type=glob,src=$rel_dir/*,dst=/tmp/,no-dereference --privileged $img sh -c "stat -c '%N' /tmp/link; cat /tmp/link"
cid="$output"
run_podman start -a $cid
assert "${lines[0]}" = "'/tmp/link' -> 'data'" "symlink is preserved"
assert "${lines[1]}" = "$rel_random_host" "glob macthes symlink and host 'data' file"
run_podman start -a $cid
assert "${lines[0]}" = "'/tmp/link' -> 'data'" "symlink is preserved"
assert "${lines[1]}" = "$rel_random_host" "glob macthes symlink and host 'data' file"
run_podman rm -f -t=0 $cid
run_podman rmi -f $img
}

View File

@ -14,7 +14,7 @@ import (
// ValidateVolumeOpts validates a volume's options
func ValidateVolumeOpts(options []string) ([]string, error) {
var foundRootPropagation, foundRWRO, foundLabelChange, bindType, foundExec, foundDev, foundSuid, foundChown, foundUpperDir, foundWorkDir, foundCopy int
var foundRootPropagation, foundRWRO, foundLabelChange, bindType, foundExec, foundDev, foundSuid, foundChown, foundUpperDir, foundWorkDir, foundCopy, foundCopySymlink int
finalOpts := make([]string, 0, len(options))
for _, opt := range options {
// support advanced options like upperdir=/path, workdir=/path
@ -93,6 +93,11 @@ func ValidateVolumeOpts(options []string) ([]string, error) {
if foundCopy > 1 {
return nil, fmt.Errorf("invalid options %q, can only specify 1 'copy' or 'nocopy' option", strings.Join(options, ", "))
}
case "no-dereference":
foundCopySymlink++
if foundCopySymlink > 1 {
return nil, fmt.Errorf("invalid options %q, can only specify 1 'no-dereference' option", strings.Join(options, ", "))
}
default:
return nil, fmt.Errorf("invalid option type %q", opt)
}

View File

@ -1,4 +1,4 @@
package version
// Version is the version of the build.
const Version = "0.57.0"
const Version = "0.57.1-dev"

2
vendor/modules.txt vendored
View File

@ -167,7 +167,7 @@ github.com/containers/buildah/pkg/sshagent
github.com/containers/buildah/pkg/util
github.com/containers/buildah/pkg/volumes
github.com/containers/buildah/util
# github.com/containers/common v0.57.0
# github.com/containers/common v0.57.1-0.20231121105603-d54dcfe962d6
## explicit; go 1.18
github.com/containers/common/internal/attributedstring
github.com/containers/common/libimage