summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/main_local.go9
-rw-r--r--cmd/podman/shared/volumes_shared.go62
-rw-r--r--cmd/podman/volume_create.go2
-rw-r--r--libpod/options.go9
-rw-r--r--libpod/runtime.go21
-rw-r--r--pkg/adapter/runtime.go7
-rw-r--r--pkg/spec/spec.go24
-rw-r--r--pkg/spec/storage.go4
-rw-r--r--pkg/varlinkapi/volumes.go6
-rw-r--r--test/e2e/run_volume_test.go7
-rw-r--r--test/e2e/volume_create_test.go20
11 files changed, 152 insertions, 19 deletions
diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go
index bdffb6b1e..202d93b35 100644
--- a/cmd/podman/main_local.go
+++ b/cmd/podman/main_local.go
@@ -174,14 +174,13 @@ func setupRootless(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
-
+ conf, err := runtime.GetConfig()
+ if err != nil {
+ return err
+ }
if !ownsCgroup {
unitName := fmt.Sprintf("podman-%d.scope", os.Getpid())
if err := utils.RunUnderSystemdScope(os.Getpid(), "user.slice", unitName); err != nil {
- conf, err2 := runtime.GetConfig()
- if err2 != nil {
- return err2
- }
if conf.CgroupManager == libpod.SystemdCgroupsManager {
logrus.Warnf("Failed to add podman to systemd sandbox cgroup: %v", err)
} else {
diff --git a/cmd/podman/shared/volumes_shared.go b/cmd/podman/shared/volumes_shared.go
index 912615cad..74c0ce011 100644
--- a/cmd/podman/shared/volumes_shared.go
+++ b/cmd/podman/shared/volumes_shared.go
@@ -2,8 +2,13 @@ package shared
import (
"context"
+ "strconv"
+ "strings"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// Remove given set of volumes
@@ -45,3 +50,60 @@ func SharedRemoveVolumes(ctx context.Context, runtime *libpod.Runtime, vols []st
return success, failed, nil
}
+
+// Handle volume options from CLI.
+// Parse "o" option to find UID, GID.
+func ParseVolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error) {
+ libpodOptions := []libpod.VolumeCreateOption{}
+ volumeOptions := make(map[string]string)
+
+ for key, value := range opts {
+ switch key {
+ case "o":
+ // o has special handling to parse out UID, GID.
+ // These are separate Libpod options.
+ splitVal := strings.Split(value, ",")
+ finalVal := []string{}
+ for _, o := range splitVal {
+ // Options will be formatted as either "opt" or
+ // "opt=value"
+ splitO := strings.SplitN(o, "=", 2)
+ switch strings.ToLower(splitO[0]) {
+ case "uid":
+ if len(splitO) != 2 {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "uid option must provide a UID")
+ }
+ intUID, err := strconv.Atoi(splitO[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot convert UID %s to integer", splitO[1])
+ }
+ logrus.Debugf("Removing uid= from options and adding WithVolumeUID for UID %d", intUID)
+ libpodOptions = append(libpodOptions, libpod.WithVolumeUID(intUID))
+ case "gid":
+ if len(splitO) != 2 {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "gid option must provide a GID")
+ }
+ intGID, err := strconv.Atoi(splitO[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot convert GID %s to integer", splitO[1])
+ }
+ logrus.Debugf("Removing gid= from options and adding WithVolumeGID for GID %d", intGID)
+ libpodOptions = append(libpodOptions, libpod.WithVolumeGID(intGID))
+ default:
+ finalVal = append(finalVal, o)
+ }
+ }
+ if len(finalVal) > 0 {
+ volumeOptions[key] = strings.Join(finalVal, ",")
+ }
+ default:
+ volumeOptions[key] = value
+ }
+ }
+
+ if len(volumeOptions) > 0 {
+ libpodOptions = append(libpodOptions, libpod.WithVolumeOptions(volumeOptions))
+ }
+
+ return libpodOptions, nil
+}
diff --git a/cmd/podman/volume_create.go b/cmd/podman/volume_create.go
index 617f701a4..e5a576749 100644
--- a/cmd/podman/volume_create.go
+++ b/cmd/podman/volume_create.go
@@ -37,7 +37,7 @@ func init() {
flags := volumeCreateCommand.Flags()
flags.StringVar(&volumeCreateCommand.Driver, "driver", "", "Specify volume driver name (default local)")
flags.StringSliceVarP(&volumeCreateCommand.Label, "label", "l", []string{}, "Set metadata for a volume (default [])")
- flags.StringSliceVarP(&volumeCreateCommand.Opt, "opt", "o", []string{}, "Set driver specific options (default [])")
+ flags.StringArrayVarP(&volumeCreateCommand.Opt, "opt", "o", []string{}, "Set driver specific options (default [])")
}
func volumeCreateCmd(c *cliconfig.VolumeCreateValues) error {
diff --git a/libpod/options.go b/libpod/options.go
index ddc5993af..17a075d2d 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1487,6 +1487,8 @@ func WithVolumeLabels(labels map[string]string) VolumeCreateOption {
}
// WithVolumeOptions sets the options of the volume.
+// If the "local" driver has been selected, options will be validated. There are
+// currently 3 valid options for the "local" driver - o, type, and device.
func WithVolumeOptions(options map[string]string) VolumeCreateOption {
return func(volume *Volume) error {
if volume.valid {
@@ -1495,6 +1497,13 @@ func WithVolumeOptions(options map[string]string) VolumeCreateOption {
volume.config.Options = make(map[string]string)
for key, value := range options {
+ switch key {
+ case "type", "device", "o":
+ volume.config.Options[key] = value
+ default:
+ return errors.Wrapf(define.ErrInvalidArg, "unrecognized volume option %q is not supported with local driver", key)
+ }
+
volume.config.Options[key] = value
}
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 8f145a809..a06b2bb51 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -1474,6 +1474,25 @@ func (r *Runtime) GetOCIRuntimePath() string {
// TODO Once runc has support for cgroups, this function should be removed.
func cgroupV2Check(configPath string, tmpConfig *RuntimeConfig) error {
if !tmpConfig.CgroupCheck && rootless.IsRootless() {
+ if tmpConfig.CgroupManager == SystemdCgroupsManager {
+ // If we are running rootless and the systemd manager is requested, be sure that dbus is accessible
+ session := os.Getenv("DBUS_SESSION_BUS_ADDRESS")
+ hasSession := session != ""
+ if hasSession && strings.HasPrefix(session, "unix:path=") {
+ _, err := os.Stat(strings.TrimPrefix(session, "unix:path="))
+ hasSession = err == nil
+ }
+
+ if !hasSession {
+ logrus.Warningf("The cgroups manager is set to systemd but there is no systemd user session available")
+ logrus.Warningf("For using systemd, you may need to login using an user session")
+ logrus.Warningf("Alternatively, you can enable lingering with: `loginctl enable-linger %d` (possibily as root)", rootless.GetRootlessUID())
+ logrus.Warningf("Falling back to --cgroup-manager=cgroupfs")
+
+ tmpConfig.CgroupManager = CgroupfsCgroupsManager
+ }
+
+ }
cgroupsV2, err := cgroups.IsCgroup2UnifiedMode()
if err != nil {
return err
@@ -1487,7 +1506,7 @@ func cgroupV2Check(configPath string, tmpConfig *RuntimeConfig) error {
}
tmpConfig.CgroupCheck = true
tmpConfig.OCIRuntime = path
- file, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE, 0666)
+ file, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return errors.Wrapf(err, "cannot open file %s", configPath)
}
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index 0706d4b6a..84d43c337 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -186,7 +186,12 @@ func (r *LocalRuntime) CreateVolume(ctx context.Context, c *cliconfig.VolumeCrea
}
if len(opts) != 0 {
- options = append(options, libpod.WithVolumeOptions(opts))
+ // We need to process -o for uid, gid
+ parsedOptions, err := shared.ParseVolumeOptions(opts)
+ if err != nil {
+ return "", err
+ }
+ options = append(options, parsedOptions...)
}
newVolume, err := r.NewVolume(ctx, options...)
if err != nil {
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 8f00d3270..da5c14948 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -300,6 +300,15 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
blockAccessToKernelFilesystems(config, &g)
+ var runtimeConfig *libpod.RuntimeConfig
+
+ if runtime != nil {
+ runtimeConfig, err = runtime.GetConfig()
+ if err != nil {
+ return nil, err
+ }
+ }
+
// RESOURCES - PIDS
if config.Resources.PidsLimit > 0 {
// if running on rootless on a cgroupv1 machine or using the cgroupfs manager, pids
@@ -312,11 +321,7 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
if err != nil {
return nil, err
}
- runtimeConfig, err := runtime.GetConfig()
- if err != nil {
- return nil, err
- }
- if (!cgroup2 || runtimeConfig.CgroupManager != libpod.SystemdCgroupsManager) && config.Resources.PidsLimit == sysinfo.GetDefaultPidsLimit() {
+ if (!cgroup2 || (runtimeConfig != nil && runtimeConfig.CgroupManager != libpod.SystemdCgroupsManager)) && config.Resources.PidsLimit == sysinfo.GetDefaultPidsLimit() {
setPidLimit = false
}
}
@@ -411,10 +416,13 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
if !addedResources {
configSpec.Linux.Resources = &spec.LinuxResources{}
}
- if addedResources && !cgroup2 {
- return nil, errors.New("invalid configuration, cannot set resources with rootless containers not using cgroups v2 unified mode")
+
+ canUseResources := cgroup2 && runtimeConfig != nil && (runtimeConfig.CgroupManager == libpod.SystemdCgroupsManager)
+
+ if addedResources && !canUseResources {
+ return nil, errors.New("invalid configuration, cannot specify resource limits without cgroups v2 and --cgroup-manager=systemd")
}
- if !cgroup2 {
+ if !canUseResources {
// Force the resources block to be empty instead of having default values.
configSpec.Linux.Resources = &spec.LinuxResources{}
}
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index a394a19ae..095534589 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -738,13 +738,13 @@ func (config *CreateConfig) getImageVolumes() (map[string]spec.Mount, map[string
Destination: cleanDest,
Source: TypeTmpfs,
Type: TypeTmpfs,
- Options: []string{"rprivate", "rw", "nodev"},
+ Options: []string{"rprivate", "rw", "nodev", "exec"},
}
mounts[vol] = mount
} else {
// Anonymous volumes have no name.
namedVolume := new(libpod.ContainerNamedVolume)
- namedVolume.Options = []string{"rprivate", "rw", "nodev"}
+ namedVolume.Options = []string{"rprivate", "rw", "nodev", "exec"}
namedVolume.Dest = cleanDest
volumes[vol] = namedVolume
}
diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go
index 0ba76902e..2dddd3008 100644
--- a/pkg/varlinkapi/volumes.go
+++ b/pkg/varlinkapi/volumes.go
@@ -24,7 +24,11 @@ func (i *LibpodAPI) VolumeCreate(call iopodman.VarlinkCall, options iopodman.Vol
volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(options.Labels))
}
if len(options.Options) > 0 {
- volumeOptions = append(volumeOptions, libpod.WithVolumeOptions(options.Options))
+ parsedOptions, err := shared.ParseVolumeOptions(options.Options)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ volumeOptions = append(volumeOptions, parsedOptions...)
}
newVolume, err := i.Runtime.NewVolume(getContext(), volumeOptions...)
if err != nil {
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index d04eb07b3..c96059787 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -357,4 +357,11 @@ var _ = Describe("Podman run with volumes", func() {
Expect(len(arr2)).To(Equal(1))
Expect(arr2[0]).To(Equal(volName))
})
+
+ It("podman run image volume is not noexec", func() {
+ session := podmanTest.Podman([]string{"run", "--rm", redis, "grep", "/data", "/proc/self/mountinfo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(Not(ContainSubstring("noexec")))
+ })
})
diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go
index 41107b5ba..71023f9e2 100644
--- a/test/e2e/volume_create_test.go
+++ b/test/e2e/volume_create_test.go
@@ -1,6 +1,7 @@
package integration
import (
+ "fmt"
"os"
. "github.com/containers/libpod/test/utils"
@@ -63,4 +64,23 @@ var _ = Describe("Podman volume create", func() {
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
})
+
+ It("podman create volume with o=uid,gid", func() {
+ volName := "testVol"
+ uid := "3000"
+ gid := "4000"
+ session := podmanTest.Podman([]string{"volume", "create", "--opt", fmt.Sprintf("o=uid=%s,gid=%s", uid, gid), volName})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ inspectUID := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .UID }}", volName})
+ inspectUID.WaitWithDefaultTimeout()
+ Expect(inspectUID.ExitCode()).To(Equal(0))
+ Expect(inspectUID.OutputToString()).To(Equal(uid))
+
+ inspectGID := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .GID }}", volName})
+ inspectGID.WaitWithDefaultTimeout()
+ Expect(inspectGID.ExitCode()).To(Equal(0))
+ Expect(inspectGID.OutputToString()).To(Equal(gid))
+ })
})