From 81a95fade593d4fda6c6f340865ae24824ac2ac8 Mon Sep 17 00:00:00 2001 From: Aditya R Date: Wed, 6 Apr 2022 15:59:59 +0530 Subject: run, mount: allow setting driver specific option using volume-opt `--mount` should allow setting driver specific options using `volume-opt` when `type=volume` is set. This ensures parity with docker's `volume-opt`. Signed-off-by: Aditya R --- libpod/runtime_ctr.go | 20 ++++++++++++++++++++ pkg/specgenutil/volumes.go | 2 ++ pkg/util/mountOpts.go | 15 +++++++++++++++ test/e2e/run_volume_test.go | 13 +++++++++++++ 4 files changed, 50 insertions(+) diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 8c3d283a5..f92898b1c 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -475,6 +475,26 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai if isAnonymous { volOptions = append(volOptions, withSetAnon()) } + + // If volume-opts are set parse and add driver opts. + if len(vol.Options) > 0 { + isDriverOpts := false + driverOpts := make(map[string]string) + for _, opts := range vol.Options { + if strings.HasPrefix(opts, "volume-opt") { + isDriverOpts = true + driverOptKey, driverOptValue, err := util.ParseDriverOpts(opts) + if err != nil { + return nil, err + } + driverOpts[driverOptKey] = driverOptValue + } + } + if isDriverOpts { + parsedOptions := []VolumeCreateOption{WithVolumeOptions(driverOpts)} + volOptions = append(volOptions, parsedOptions...) + } + } newVol, err := r.newVolume(ctx, volOptions...) if err != nil { return nil, errors.Wrapf(err, "error creating named volume %q", vol.Name) diff --git a/pkg/specgenutil/volumes.go b/pkg/specgenutil/volumes.go index 8a861077a..aa07de0af 100644 --- a/pkg/specgenutil/volumes.go +++ b/pkg/specgenutil/volumes.go @@ -523,6 +523,8 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) { for _, val := range args { kv := strings.SplitN(val, "=", 2) switch kv[0] { + case "volume-opt": + newVolume.Options = append(newVolume.Options, val) case "ro", "rw": if setRORW { return nil, errors.Wrapf(optionArgError, "cannot pass 'ro' and 'rw' options more than once") diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go index 2a0101791..e37394619 100644 --- a/pkg/util/mountOpts.go +++ b/pkg/util/mountOpts.go @@ -57,6 +57,9 @@ func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string switch splitOpt[0] { case "O": foundOverlay = true + case "volume-opt": + // Volume-opt should be relayed and processed by driver. + newOptions = append(newOptions, opt) case "exec", "noexec": if foundExec { return nil, errors.Wrapf(ErrDupeMntOption, "only one of 'noexec' and 'exec' can be used") @@ -175,3 +178,15 @@ func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string return newOptions, nil } + +func ParseDriverOpts(option string) (string, string, error) { + token := strings.SplitN(option, "=", 2) + if len(token) != 2 { + return "", "", errors.Wrapf(ErrBadMntOption, "cannot parse driver opts") + } + opt := strings.SplitN(token[1], "=", 2) + if len(opt) != 2 { + return "", "", errors.Wrapf(ErrBadMntOption, "cannot parse driver opts") + } + return opt[0], opt[1], nil +} diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 471b3a342..4887197f6 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -797,6 +797,19 @@ VOLUME /test/`, ALPINE) Expect(session.OutputToString()).Should(Equal("888:888")) }) + It("podman run with --mount and named volume with driver-opts", func() { + // anonymous volume mount with driver opts + vol := "type=volume,source=test_vol,dst=/test,volume-opt=type=tmpfs,volume-opt=device=tmpfs,volume-opt=o=nodev" + session := podmanTest.Podman([]string{"run", "--rm", "--mount", vol, ALPINE, "echo", "hello"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + inspectVol := podmanTest.Podman([]string{"volume", "inspect", "test_vol"}) + inspectVol.WaitWithDefaultTimeout() + Expect(inspectVol).Should(Exit(0)) + Expect(inspectVol.OutputToString()).To(ContainSubstring("nodev")) + }) + It("volume permissions after run", func() { imgName := "testimg" dockerfile := fmt.Sprintf(`FROM %s -- cgit v1.2.3-54-g00ecf