diff options
-rw-r--r-- | .cirrus.yml | 8 | ||||
-rw-r--r-- | .copr/prepare.sh | 2 | ||||
-rwxr-xr-x | .tool/lint | 1 | ||||
-rw-r--r-- | CONTRIBUTING.md | 3 | ||||
-rw-r--r-- | Dockerfile | 8 | ||||
-rw-r--r-- | Dockerfile.centos | 8 | ||||
-rw-r--r-- | Dockerfile.fedora | 8 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | RELEASE_NOTES.md | 1 | ||||
-rw-r--r-- | contrib/spec/podman.spec.in | 2 | ||||
-rw-r--r-- | docs/podman-create.1.md | 1 | ||||
-rw-r--r-- | docs/podman-run.1.md | 1 | ||||
-rw-r--r-- | libpod/container.go | 4 | ||||
-rw-r--r-- | libpod/container_inspect.go | 180 | ||||
-rw-r--r-- | libpod/options.go | 2 | ||||
-rw-r--r-- | libpod/pod.go | 6 | ||||
-rw-r--r-- | libpod/volume.go | 1 | ||||
-rw-r--r-- | pkg/spec/storage.go | 11 | ||||
-rw-r--r-- | pkg/util/mountOpts.go | 15 | ||||
-rw-r--r-- | test/e2e/run_test.go | 8 |
20 files changed, 200 insertions, 72 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 4344b6b0a..848dc2b6d 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -31,9 +31,9 @@ env: #### #### Cache-image names to test with ### - FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-5157899144265728" - PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-28-libpod-5157899144265728" - UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-5157899144265728" + FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-4844850202017792" + PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-28-libpod-4844850202017792" + UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-4844850202017792" #### #### Variables for composing new cache-images (used in PR testing) from @@ -43,7 +43,7 @@ env: # Git commits to use while building dependencies into cache-images FEDORA_CNI_COMMIT: "412b6d31280682bb4fab4446f113c22ff1886554" CNI_COMMIT: "7480240de9749f9a0a5c8614b17f1f03e0c06ab9" - CONMON_COMMIT: "f02c053eb37010fc76d1e2966de7f2cb9f969ef2" + CONMON_COMMIT: "8455ce1ef385120deb827d0f0588c04357bad4c4" CRIU_COMMIT: "c74b83cd49c00589c0c0468ba5fe685b67fdbd0a" # Special image w/ nested-libvirt + tools for creating new cache and base images IMAGE_BUILDER_CACHE_IMAGE_NAME: "image-builder-image-1541772081" diff --git a/.copr/prepare.sh b/.copr/prepare.sh index 57c380b02..d7c5083ca 100644 --- a/.copr/prepare.sh +++ b/.copr/prepare.sh @@ -29,4 +29,4 @@ fi mkdir build/ git archive --prefix "libpod-${COMMIT_SHORT}/" --format "tar.gz" HEAD -o "build/libpod-${COMMIT_SHORT}.tar.gz" git clone https://github.com/containers/conmon -cd conmon && git checkout 59952292a3b07ac125575024ae21956efe0ecdfb && git archive --prefix "conmon/" --format "tar.gz" HEAD -o "../build/conmon.tar.gz" +cd conmon && git checkout 8455ce1ef385120deb827d0f0588c04357bad4c4 && git archive --prefix "conmon/" --format "tar.gz" HEAD -o "../build/conmon.tar.gz" diff --git a/.tool/lint b/.tool/lint index 01f44311d..67dfd4b28 100755 --- a/.tool/lint +++ b/.tool/lint @@ -39,7 +39,6 @@ ${LINTER} \ --exclude='.*_test\.go:.*error return value not checked.*\(errcheck\)$'\ --exclude='duplicate of.*_test.go.*\(dupl\)$'\ --exclude='cmd\/client\/.*\.go.*\(dupl\)$'\ - --exclude='libpod\/.*_easyjson.go:.*'\ --exclude='vendor\/.*'\ --exclude='podman\/.*'\ --exclude='server\/seccomp\/.*\.go.*$'\ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 87efdeb8f..8b7544ba0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -350,6 +350,9 @@ and [PRs](https://github.com/containers/libpod/pulls) tracking system. +There is also a [mailing list](https://lists.podman.io/archives/) at `lists.podman.io`. +You can subscribe by sending a message to `podman@lists.podman.io` with the subject `subscribe`. + [owners]: https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md#owners diff --git a/Dockerfile b/Dockerfile index d729c00dc..214fbeb34 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,7 +56,7 @@ RUN set -x \ && rm -rf "$GOPATH" # Install conmon -ENV CONMON_COMMIT 59952292a3b07ac125575024ae21956efe0ecdfb +ENV CONMON_COMMIT 8455ce1ef385120deb827d0f0588c04357bad4c4 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/containers/conmon.git "$GOPATH/src/github.com/containers/conmon.git" \ @@ -90,12 +90,6 @@ RUN set -x \ && export GOPATH=/go \ && go get github.com/onsi/gomega/... -# Install easyjson -RUN set -x \ - && export GOPATH=/go \ - && go get -u github.com/mailru/easyjson/... \ - && install -D -m 755 "$GOPATH"/bin/easyjson /usr/bin/ - # Install latest stable criu version RUN set -x \ && cd /tmp \ diff --git a/Dockerfile.centos b/Dockerfile.centos index c1d93d5d3..72b926bff 100644 --- a/Dockerfile.centos +++ b/Dockerfile.centos @@ -49,14 +49,8 @@ RUN set -x \ && export GOPATH=/go \ && go get github.com/onsi/gomega/... -# Install easyjson -RUN set -x \ - && export GOPATH=/go \ - && go get -u github.com/mailru/easyjson/... \ - && install -D -m 755 "$GOPATH"/bin/easyjson /usr/bin/ - # Install conmon -ENV CONMON_COMMIT 59952292a3b07ac125575024ae21956efe0ecdfb +ENV CONMON_COMMIT 8455ce1ef385120deb827d0f0588c04357bad4c4 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/containers/conmon.git "$GOPATH/src/github.com/containers/conmon.git" \ diff --git a/Dockerfile.fedora b/Dockerfile.fedora index d7c2d07e1..c34d4bb16 100644 --- a/Dockerfile.fedora +++ b/Dockerfile.fedora @@ -53,14 +53,8 @@ RUN set -x \ && export GOPATH=/go \ && go get github.com/onsi/gomega/... -# Install easyjson -RUN set -x \ - && export GOPATH=/go \ - && go get -u github.com/mailru/easyjson/... \ - && install -D -m 755 "$GOPATH"/bin/easyjson /usr/bin/ - # Install conmon -ENV CONMON_COMMIT 59952292a3b07ac125575024ae21956efe0ecdfb +ENV CONMON_COMMIT 8455ce1ef385120deb827d0f0588c04357bad4c4 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/containers/conmon.git "$GOPATH/src/github.com/containers/conmon.git" \ @@ -5,7 +5,7 @@ Libpod provides a library for applications looking to use the Container Pod concept, popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`. Podman manages pods, containers, container images, and container volumes. -* [Latest Version: 1.3.1](https://github.com/containers/libpod/releases/latest) +* [Latest Version: 1.4.0](https://github.com/containers/libpod/releases/latest) * [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master) ## Overview and scope diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index e36757edc..fbb6a78b0 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -22,6 +22,7 @@ - Fixed a bug where `podman exec` would fail on older kernels ([#2968](https://github.com/containers/libpod/issues/2968)) ### Misc +- The `podman inspect` command on containers now uses the `Id` key (instead of `ID`) for the container's ID, for better compatability with the output of `docker inspect` - The `podman commit` command is now usable with the Podman remote client - The `--signature-policy` flag (used with several image-related commands) has been deprecated - The `podman unshare` command now defines two environment variables in the spawned shell: `CONTAINERS_RUNROOT` and `CONTAINERS_GRAPHROOT`, pointing to temporary and permanent storage for rootless containers diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index 8c2ccd4b0..d755fd1aa 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -35,7 +35,7 @@ # People want conmon packaged with the copr rpm %global import_path_conmon github.com/containers/conmon %global git_conmon https://%{import_path_conmon} -%global commit_conmon 59952292a3b07ac125575024ae21956efe0ecdfb +%global commit_conmon 8455ce1ef385120deb827d0f0588c04357bad4c4 %global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7}) Name: podman diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md index 88f8fe8c7..a4eebef4c 100644 --- a/docs/podman-create.1.md +++ b/docs/podman-create.1.md @@ -458,6 +458,7 @@ Current supported mount TYPES are bind, and tmpfs. Options specific to bind: · bind-propagation: shared, slave, private, rshared, rslave, or rprivate(default). See also mount(2). + . bind-nonrecursive: do not setup a recursive bind mount. By default it is recursive. Options specific to tmpfs: diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md index 5bf7aeee8..8d7deb99f 100644 --- a/docs/podman-run.1.md +++ b/docs/podman-run.1.md @@ -471,6 +471,7 @@ Current supported mount TYPES are bind, and tmpfs. Options specific to bind: · bind-propagation: Z, z, shared, slave, private, rshared, rslave, or rprivate(default). See also mount(2). + . bind-nonrecursive: do not setup a recursive bind mount. By default it is recursive. Options specific to tmpfs: diff --git a/libpod/container.go b/libpod/container.go index c8ab42fc3..68c4cd6b0 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -135,7 +135,6 @@ const ( // assume that their callers handled this requirement. Generally speaking, if a // function takes the container lock and accesses any part of state, it should // syncContainer() immediately after locking. -// ffjson: skip type Container struct { config *ContainerConfig @@ -161,7 +160,6 @@ type Container struct { // ContainerState contains the current state of the container // It is stored on disk in a tmpfs and recreated on reboot -// easyjson:json type ContainerState struct { // The current state of the running container State ContainerStatus `json:"state"` @@ -222,7 +220,6 @@ type ContainerState struct { } // ExecSession contains information on an active exec session -// easyjson:json type ExecSession struct { ID string `json:"id"` Command []string `json:"command"` @@ -232,7 +229,6 @@ type ExecSession struct { // ContainerConfig contains all information that was used to create the // container. It may not be changed once created. // It is stored, read-only, on disk -// easyjson:json type ContainerConfig struct { Spec *spec.Spec `json:"spec"` ID string `json:"id"` diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 8e34e7088..0a62ceb7c 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -1,12 +1,11 @@ package libpod import ( - "strings" "time" "github.com/containers/libpod/libpod/driver" "github.com/cri-o/ocicni/pkg/ocicni" - specs "github.com/opencontainers/runtime-spec/specs-go" + spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -29,6 +28,7 @@ type InspectContainerData struct { HostnamePath string `json:"HostnamePath"` HostsPath string `json:"HostsPath"` StaticDir string `json:"StaticDir"` + OCIConfigPath string `json:"OCIConfigPath,omitempty"` LogPath string `json:"LogPath"` ConmonPidFile string `json:"ConmonPidFile"` Name string `json:"Name"` @@ -43,7 +43,7 @@ type InspectContainerData struct { GraphDriver *driver.Data `json:"GraphDriver"` SizeRw int64 `json:"SizeRw,omitempty"` SizeRootFs int64 `json:"SizeRootFs,omitempty"` - Mounts []specs.Mount `json:"Mounts"` + Mounts []*InspectMount `json:"Mounts"` Dependencies []string `json:"Dependencies"` NetworkSettings *InspectNetworkSettings `json:"NetworkSettings"` //TODO ExitCommand []string `json:"ExitCommand"` @@ -51,6 +51,35 @@ type InspectContainerData struct { IsInfra bool `json:"IsInfra"` } +// InspectMount provides a record of a single mount in a container. It contains +// fields for both named and normal volumes. Only user-specified volumes will be +// included, and tmpfs volumes are not included even if the user specified them. +type InspectMount struct { + // Whether the mount is a volume or bind mount. Allowed values are + // "volume" and "bind". + Type string `json:"Type"` + // The name of the volume. Empty for bind mounts. + Name string `json:"Name,omptempty"` + // The source directory for the volume. + Src string `json:"Source"` + // The destination directory for the volume. Specified as a path within + // the container, as it would be passed into the OCI runtime. + Dst string `json:"Destination"` + // The driver used for the named volume. Empty for bind mounts. + Driver string `json:"Driver"` + // Contains SELinux :z/:Z mount options. Unclear what, if anything, else + // goes in here. + Mode string `json:"Mode"` + // All remaining mount options. Additional data, not present in the + // original output. + Options []string `json:"Options"` + // Whether the volume is read-write + RW bool `json:"RW"` + // Mount propagation for the mount. Can be empty if not specified, but + // is always printed - no omitempty. + Propagation string `json:"Propagation"` +} + // InspectContainerState provides a detailed record of a container's current // state. It is returned as part of InspectContainerData. // As with InspectContainerData, many portions of this struct are matched to @@ -148,34 +177,24 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data) execIDs = append(execIDs, id) } - if c.state.BindMounts == nil { - c.state.BindMounts = make(map[string]string) - } - resolvPath := "" - if getPath, ok := c.state.BindMounts["/etc/resolv.conf"]; ok { - resolvPath = getPath - } - hostsPath := "" - if getPath, ok := c.state.BindMounts["/etc/hosts"]; ok { - hostsPath = getPath - } - hostnamePath := "" - if getPath, ok := c.state.BindMounts["/etc/hostname"]; ok { - hostnamePath = getPath + if c.state.BindMounts != nil { + if getPath, ok := c.state.BindMounts["/etc/resolv.conf"]; ok { + resolvPath = getPath + } + if getPath, ok := c.state.BindMounts["/etc/hosts"]; ok { + hostsPath = getPath + } + if getPath, ok := c.state.BindMounts["/etc/hostname"]; ok { + hostnamePath = getPath + } } - var mounts []specs.Mount - for i, mnt := range spec.Mounts { - mounts = append(mounts, mnt) - // We only want to show the name of the named volume in the inspect - // output, so split the path and get the name out of it. - if strings.Contains(mnt.Source, c.runtime.config.VolumePath) { - split := strings.Split(mnt.Source[len(c.runtime.config.VolumePath)+1:], "/") - mounts[i].Source = split[0] - } + mounts, err := c.getInspectMounts() + if err != nil { + return nil, err } data := &InspectContainerData{ @@ -242,8 +261,12 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data) IsInfra: c.IsInfra(), } + if c.state.ConfigPath != "" { + data.OCIConfigPath = c.state.ConfigPath + } + if c.config.HealthCheckConfig != nil { - // This container has a healthcheck defined in it; we need to add it's state + // This container has a healthcheck defined in it; we need to add it's state healthCheckState, err := c.GetHealthCheckLog() if err != nil { // An error here is not considered fatal; no health state will be displayed @@ -275,3 +298,106 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data) } return data, nil } + +// Get inspect-formatted mounts list. +// Only includes user-specified mounts. Only includes bind mounts and named +// volumes, not tmpfs volumes. +func (c *Container) getInspectMounts() ([]*InspectMount, error) { + inspectMounts := []*InspectMount{} + + // No mounts, return early + if len(c.config.UserVolumes) == 0 { + return inspectMounts, nil + } + + // We need to parse all named volumes and mounts into maps, so we don't + // end up with repeated lookups for each user volume. + // Map destination to struct, as destination is what is stored in + // UserVolumes. + namedVolumes := make(map[string]*ContainerNamedVolume) + mounts := make(map[string]spec.Mount) + for _, namedVol := range c.config.NamedVolumes { + namedVolumes[namedVol.Dest] = namedVol + } + for _, mount := range c.config.Spec.Mounts { + mounts[mount.Destination] = mount + } + + for _, vol := range c.config.UserVolumes { + // We need to look up the volumes. + // First: is it a named volume? + if volume, ok := namedVolumes[vol]; ok { + mountStruct := new(InspectMount) + mountStruct.Type = "volume" + mountStruct.Dst = volume.Dest + mountStruct.Name = volume.Name + + // For src and driver, we need to look up the named + // volume. + volFromDB, err := c.runtime.state.Volume(volume.Name) + if err != nil { + return nil, errors.Wrapf(err, "error looking up volume %s in container %s config", volume.Name, c.ID()) + } + mountStruct.Driver = volFromDB.Driver() + mountStruct.Src = volFromDB.MountPoint() + + parseMountOptionsForInspect(volume.Options, mountStruct) + + inspectMounts = append(inspectMounts, mountStruct) + } else if mount, ok := mounts[vol]; ok { + // It's a mount. + // Is it a tmpfs? If so, discard. + if mount.Type == "tmpfs" { + continue + } + + mountStruct := new(InspectMount) + mountStruct.Type = "bind" + mountStruct.Src = mount.Source + mountStruct.Dst = mount.Destination + + parseMountOptionsForInspect(mount.Options, mountStruct) + + inspectMounts = append(inspectMounts, mountStruct) + } + // We couldn't find a mount. Log a warning. + logrus.Warnf("Could not find mount at destination %q when building inspect output for container %s", vol, c.ID()) + } + + return inspectMounts, nil +} + +// Parse mount options so we can populate them in the mount structure. +// The mount passed in will be modified. +func parseMountOptionsForInspect(options []string, mount *InspectMount) { + isRW := true + mountProp := "" + zZ := "" + otherOpts := []string{} + + // Some of these may be overwritten if the user passes us garbage opts + // (for example, [ro,rw]) + // We catch these on the Podman side, so not a problem there, but other + // users of libpod who do not properly validate mount options may see + // this. + // Not really worth dealing with on our end - garbage in, garbage out. + for _, opt := range options { + switch opt { + case "ro": + isRW = false + case "rw": + // Do nothing, silently discard + case "shared", "slave", "private", "rshared", "rslave", "rprivate": + mountProp = opt + case "z", "Z": + zZ = opt + default: + otherOpts = append(otherOpts, opt) + } + } + + mount.RW = isRW + mount.Propagation = mountProp + mount.Mode = zZ + mount.Options = otherOpts +} diff --git a/libpod/options.go b/libpod/options.go index 20aa51981..cdac09654 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1127,6 +1127,8 @@ func WithGroups(groups []string) CtrCreateOption { // These are not added to the container's spec, but will instead be used during // commit to populate the volumes of the new image, and to trigger some OCI // hooks that are only added if volume mounts are present. +// Furthermore, they are used in the output of inspect, to filter volumes - +// only volumes included in this list will be included in the output. // Unless explicitly set, committed images will have no volumes. // The given volumes slice must not be nil. func WithUserVolumes(volumes []string) CtrCreateOption { diff --git a/libpod/pod.go b/libpod/pod.go index 4ce697402..c319c449f 100644 --- a/libpod/pod.go +++ b/libpod/pod.go @@ -18,7 +18,6 @@ import ( // assume their callers handled this requirement. Generally speaking, if a // function takes the pod lock and accesses any part of state, it should // updatePod() immediately after locking. -// ffjson: skip // Pod represents a group of containers that may share namespaces type Pod struct { config *PodConfig @@ -30,7 +29,6 @@ type Pod struct { } // PodConfig represents a pod's static configuration -// easyjson:json type PodConfig struct { ID string `json:"id"` Name string `json:"name"` @@ -66,7 +64,6 @@ type PodConfig struct { } // podState represents a pod's state -// easyjson:json type podState struct { // CgroupPath is the path to the pod's CGroup CgroupPath string `json:"cgroupPath"` @@ -77,7 +74,6 @@ type podState struct { // PodInspect represents the data we want to display for // podman pod inspect -// easyjson:json type PodInspect struct { Config *PodConfig State *PodInspectState @@ -85,14 +81,12 @@ type PodInspect struct { } // PodInspectState contains inspect data on the pod's state -// easyjson:json type PodInspectState struct { CgroupPath string `json:"cgroupPath"` InfraContainerID string `json:"infraContainerID"` } // PodContainerInfo keeps information on a container in a pod -// easyjson:json type PodContainerInfo struct { ID string `json:"id"` State string `json:"state"` diff --git a/libpod/volume.go b/libpod/volume.go index 0b37d44ef..9ed2ff087 100644 --- a/libpod/volume.go +++ b/libpod/volume.go @@ -10,7 +10,6 @@ type Volume struct { } // VolumeConfig holds the volume's config information -//easyjson:json type VolumeConfig struct { // Name of the volume Name string `json:"name"` diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go index e221b5cb5..283585ef8 100644 --- a/pkg/spec/storage.go +++ b/pkg/spec/storage.go @@ -384,7 +384,7 @@ func (config *CreateConfig) getMounts() (map[string]spec.Mount, map[string]*libp } finalNamedVolumes[volume.Dest] = volume default: - return nil, nil, errors.Errorf("invalid fylesystem type %q", kv[1]) + return nil, nil, errors.Errorf("invalid filesystem type %q", kv[1]) } } @@ -403,6 +403,8 @@ func getBindMount(args []string) (spec.Mount, error) { for _, val := range args { kv := strings.Split(val, "=") switch kv[0] { + case "bind-nonrecursive": + newMount.Options = append(newMount.Options, "bind") case "ro", "nosuid", "nodev", "noexec": // TODO: detect duplication of these options. // (Is this necessary?) @@ -574,7 +576,7 @@ func ValidateVolumeCtrDir(ctrDir string) error { // ValidateVolumeOpts validates a volume's options func ValidateVolumeOpts(options []string) error { - var foundRootPropagation, foundRWRO, foundLabelChange int + var foundRootPropagation, foundRWRO, foundLabelChange, bindType int for _, opt := range options { switch opt { case "rw", "ro": @@ -592,6 +594,11 @@ func ValidateVolumeOpts(options []string) error { if foundRootPropagation > 1 { return errors.Errorf("invalid options %q, can only specify 1 '[r]shared', '[r]private' or '[r]slave' option", strings.Join(options, ", ")) } + case "bind", "rbind": + bindType++ + if bindType > 1 { + return errors.Errorf("invalid options %q, can only specify 1 '[r]bind' option", strings.Join(options, ", ")) + } default: return errors.Errorf("invalid option type %q", opt) } diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go index 59459807c..489e7eeef 100644 --- a/pkg/util/mountOpts.go +++ b/pkg/util/mountOpts.go @@ -17,10 +17,19 @@ var ( // sensible and follow convention. func ProcessOptions(options []string) []string { var ( - foundrw, foundro bool - rootProp string + foundbind, foundrw, foundro bool + rootProp string ) - options = append(options, "rbind") + for _, opt := range options { + switch opt { + case "bind", "rbind": + foundbind = true + break + } + } + if !foundbind { + options = append(options, "rbind") + } for _, opt := range options { switch opt { case "rw": diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 31720ea04..3ba3c2bb3 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -659,6 +659,14 @@ USER mail` Expect(isSharedOnly).Should(BeTrue()) }) + It("podman run --mount type=bind,bind-nonrecursive", func() { + SkipIfRootless() + session := podmanTest.Podman([]string{"run", "--mount", "type=bind,bind-nonrecursive,slave,src=/,target=/host", fedoraMinimal, "findmnt", "-nR", "/host"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(Equal(1)) + }) + It("podman run --pod automatically", func() { session := podmanTest.Podman([]string{"run", "--pod", "new:foobar", ALPINE, "ls"}) session.WaitWithDefaultTimeout() |