diff options
author | OpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com> | 2021-09-23 08:32:24 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-23 08:32:24 -0400 |
commit | 3d34d3a186a782e48bdbd1245a7e067db850d9b0 (patch) | |
tree | ed40d4167c5c143519961c48c23ad7935e250135 | |
parent | 5764693613fc6e3e215eb4ddff68dbe657ba46ca (diff) | |
parent | ed3c4a89d61a89673d08825aeee21430957d5185 (diff) | |
download | podman-3d34d3a186a782e48bdbd1245a7e067db850d9b0.tar.gz podman-3d34d3a186a782e48bdbd1245a7e067db850d9b0.tar.bz2 podman-3d34d3a186a782e48bdbd1245a7e067db850d9b0.zip |
Merge pull request #11647 from EduardoVega/11491-U-suffix-mount-option
Add support for :U flag with --mount option
-rw-r--r-- | docs/source/markdown/podman-create.1.md | 7 | ||||
-rw-r--r-- | docs/source/markdown/podman-run.1.md | 8 | ||||
-rw-r--r-- | pkg/specgenutil/volumes.go | 63 | ||||
-rw-r--r-- | test/e2e/run_volume_test.go | 61 |
4 files changed, 135 insertions, 4 deletions
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index c3e2bbfca..f63f5ca9c 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -595,6 +595,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared + type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared,U=true + type=volume,source=vol1,destination=/path/in/container,ro=true type=tmpfs,tmpfs-size=512M,destination=/path/in/container @@ -613,6 +615,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and · ro, readonly: true or false (default). + . 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. + Options specific to image: · rw, readwrite: true or false (default). @@ -627,6 +631,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and . relabel: shared, private. + . 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. + Options specific to tmpfs: · ro, readonly: true or false (default). @@ -639,6 +645,7 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and · notmpcopyup: Disable copying files from the image to the tmpfs. + . 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. #### **--name**=*name* diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index a369ce5ea..6d68fd62b 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -615,6 +615,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared + type=bind,src=/path/on/host,dst=/path/in/container,relabel=shared,U=true + type=volume,source=vol1,destination=/path/in/container,ro=true type=tmpfs,tmpfs-size=512M,destination=/path/in/container @@ -633,6 +635,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and · ro, readonly: true or false (default). + . 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. + Options specific to image: · rw, readwrite: true or false (default). @@ -647,6 +651,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and . relabel: shared, private. + . 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. + Options specific to tmpfs: · ro, readonly: true or false (default). @@ -659,6 +665,8 @@ Current supported mount TYPEs are **bind**, **volume**, **image**, **tmpfs** and · notmpcopyup: Disable copying files from the image to the tmpfs. + . 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. + #### **--name**=*name* Assign a name to the container. diff --git a/pkg/specgenutil/volumes.go b/pkg/specgenutil/volumes.go index 0ed08198f..3ce96164f 100644 --- a/pkg/specgenutil/volumes.go +++ b/pkg/specgenutil/volumes.go @@ -243,7 +243,7 @@ func getBindMount(args []string) (spec.Mount, error) { Type: define.TypeBind, } - var setSource, setDest, setRORW, setSuid, setDev, setExec, setRelabel bool + var setSource, setDest, setRORW, setSuid, setDev, setExec, setRelabel, setOwnership bool for _, val := range args { kv := strings.SplitN(val, "=", 2) @@ -343,6 +343,18 @@ func getBindMount(args []string) (spec.Mount, error) { default: return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0]) } + case "U", "chown": + if setOwnership { + return newMount, errors.Wrapf(optionArgError, "cannot pass 'U' or 'chown' option more than once") + } + ok, err := validChownFlag(val) + if err != nil { + return newMount, err + } + if ok { + newMount.Options = append(newMount.Options, "U") + } + setOwnership = true case "consistency": // Often used on MACs and mistakenly on Linux platforms. // Since Docker ignores this option so shall we. @@ -375,7 +387,7 @@ func getTmpfsMount(args []string) (spec.Mount, error) { Source: define.TypeTmpfs, } - var setDest, setRORW, setSuid, setDev, setExec, setTmpcopyup bool + var setDest, setRORW, setSuid, setDev, setExec, setTmpcopyup, setOwnership bool for _, val := range args { kv := strings.SplitN(val, "=", 2) @@ -431,6 +443,18 @@ func getTmpfsMount(args []string) (spec.Mount, error) { } newMount.Destination = filepath.Clean(kv[1]) setDest = true + case "U", "chown": + if setOwnership { + return newMount, errors.Wrapf(optionArgError, "cannot pass 'U' or 'chown' option more than once") + } + ok, err := validChownFlag(val) + if err != nil { + return newMount, err + } + if ok { + newMount.Options = append(newMount.Options, "U") + } + setOwnership = true case "consistency": // Often used on MACs and mistakenly on Linux platforms. // Since Docker ignores this option so shall we. @@ -486,7 +510,7 @@ func getDevptsMount(args []string) (spec.Mount, error) { func getNamedVolume(args []string) (*specgen.NamedVolume, error) { newVolume := new(specgen.NamedVolume) - var setSource, setDest, setRORW, setSuid, setDev, setExec bool + var setSource, setDest, setRORW, setSuid, setDev, setExec, setOwnership bool for _, val := range args { kv := strings.SplitN(val, "=", 2) @@ -532,6 +556,18 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) { } newVolume.Dest = filepath.Clean(kv[1]) setDest = true + case "U", "chown": + if setOwnership { + return newVolume, errors.Wrapf(optionArgError, "cannot pass 'U' or 'chown' option more than once") + } + ok, err := validChownFlag(val) + if err != nil { + return newVolume, err + } + if ok { + newVolume.Options = append(newVolume.Options, "U") + } + setOwnership = true case "consistency": // Often used on MACs and mistakenly on Linux platforms. // Since Docker ignores this option so shall we. @@ -628,3 +664,24 @@ func getTmpfsMounts(tmpfsFlag []string) (map[string]spec.Mount, error) { } return m, nil } + +// validChownFlag ensures that the U or chown flag is correctly used +func validChownFlag(flag string) (bool, error) { + kv := strings.SplitN(flag, "=", 2) + switch len(kv) { + case 1: + case 2: + // U=[true|false] + switch strings.ToLower(kv[1]) { + case "true": + case "false": + return false, nil + default: + return false, errors.Wrapf(optionArgError, "'U' or 'chown' must be set to true or false, instead received %q", kv[1]) + } + default: + return false, errors.Wrapf(optionArgError, "badly formatted option %q", flag) + } + + return true, nil +} diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 4264e1efe..f1baa7780 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -647,7 +647,7 @@ VOLUME /test/`, ALPINE) Expect(len(session.OutputToStringArray())).To(Equal(2)) }) - It("podman run with U volume flag", func() { + It("podman run with --volume and U flag", func() { SkipIfRemote("Overlay volumes only work locally") u, err := user.Current() @@ -698,6 +698,65 @@ VOLUME /test/`, ALPINE) Expect(found).Should(BeTrue()) }) + It("podman run with --mount and U flag", func() { + u, err := user.Current() + Expect(err).To(BeNil()) + name := u.Username + if name == "root" { + name = "containers" + } + + content, err := ioutil.ReadFile("/etc/subuid") + if err != nil { + Skip("cannot read /etc/subuid") + } + + if !strings.Contains(string(content), name) { + Skip("cannot find mappings for the current user") + } + + mountPath := filepath.Join(podmanTest.TempDir, "foo") + os.Mkdir(mountPath, 0755) + + // false bind mount + vol := "type=bind,src=" + mountPath + ",dst=" + dest + ",U=false" + session := podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).ShouldNot(Equal("888:888")) + + // invalid bind mount + vol = "type=bind,src=" + mountPath + ",dst=" + dest + ",U=invalid" + session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) + + // true bind mount + vol = "type=bind,src=" + mountPath + ",dst=" + dest + ",U=true" + session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).Should(Equal("888:888")) + + // tmpfs mount + vol = "type=tmpfs," + "dst=" + dest + ",chown" + session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).Should(Equal("888:888")) + + // named volume mount + namedVolume := podmanTest.Podman([]string{"volume", "create", "foo"}) + namedVolume.WaitWithDefaultTimeout() + Expect(namedVolume).Should(Exit(0)) + + vol = "type=volume,src=foo,dst=" + dest + ",chown=true" + session = podmanTest.Podman([]string{"run", "--rm", "--user", "888:888", "--mount", vol, ALPINE, "stat", "-c", "%u:%g", dest}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).Should(Equal("888:888")) + }) + It("volume permissions after run", func() { imgName := "testimg" dockerfile := fmt.Sprintf(`FROM %s |