summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile16
-rw-r--r--cmd/podman/cliconfig/config.go4
-rw-r--r--cmd/podman/commands.go1
-rw-r--r--cmd/podman/main_local.go80
-rw-r--r--cmd/podman/trust.go16
-rwxr-xr-xcontrib/cirrus/setup_environment.sh4
-rw-r--r--contrib/msi/podman-logo.icobin0 -> 15086 bytes
-rw-r--r--contrib/msi/podman.bat43
-rw-r--r--contrib/msi/podman.wxs48
-rw-r--r--docs/podman-image-trust.1.md4
-rw-r--r--docs/tutorials/rootless_tutorial.md19
-rw-r--r--libpod/container_internal_linux.go29
-rw-r--r--libpod/oci_internal_linux.go54
-rw-r--r--libpod/runtime_cstorage.go6
-rw-r--r--pkg/cgroups/cgroups_supported.go62
-rw-r--r--pkg/cgroups/cgroups_unsupported.go6
-rw-r--r--rootless.md16
-rw-r--r--utils/utils_supported.go18
18 files changed, 354 insertions, 72 deletions
diff --git a/Makefile b/Makefile
index 840bfced7..482b2d2c2 100644
--- a/Makefile
+++ b/Makefile
@@ -83,7 +83,7 @@ LIBSECCOMP_COMMIT := release-2.3
GINKGOTIMEOUT ?= -timeout=90m
RELEASE_VERSION ?= $(shell hack/get_release_info.sh VERSION)
-RELEASE_NUMBER ?= $(shell hack/get_release_info.sh NUMBER)
+RELEASE_NUMBER ?= $(shell hack/get_release_info.sh NUMBER|sed -e 's/^v\(.*\)/\1/')
RELEASE_DIST ?= $(shell hack/get_release_info.sh DIST)
RELEASE_DIST_VER ?= $(shell hack/get_release_info.sh DIST_VER)
RELEASE_ARCH ?= $(shell hack/get_release_info.sh ARCH)
@@ -164,6 +164,10 @@ podman: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman
podman-remote: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build with podman on remote environment
$(GO_BUILD) $(BUILDFLAGS) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "$(BUILDTAGS) remoteclient" -o bin/$@ $(PROJECT)/cmd/podman
+.PHONY: podman.msi
+podman.msi: podman-remote-windows ## Will always rebuild exe as there is no podman-remote-windows.exe target to verify timestamp
+ wixl -D VERSION=$(RELEASE_NUMBER) -o bin/podman-v$(RELEASE_NUMBER).msi contrib/msi/podman.wxs
+
podman-remote-%: .gopathok $(PODMAN_VARLINK_DEPENDENCIES) ## Build podman for a specific GOOS
$(eval BINSFX := $(shell test "$*" != "windows" || echo ".exe"))
CGO_ENABLED=0 GOOS=$* $(GO_BUILD) -gcflags '$(GCFLAGS)' -asmflags '$(ASMFLAGS)' -ldflags '$(LDFLAGS_PODMAN)' -tags "remoteclient containers_image_openpgp exclude_graphdriver_devicemapper" -o bin/$@$(BINSFX) $(PROJECT)/cmd/podman
@@ -328,9 +332,9 @@ release.txt:
echo -n " $$field"; done >> "$@"
echo "" >> "$@"
-podman-$(RELEASE_NUMBER).tar.gz: binaries docs release.txt
+podman-v$(RELEASE_NUMBER).tar.gz: binaries docs release.txt
$(eval TMPDIR := $(shell mktemp -d -p '' podman_XXXX))
- $(eval SUBDIR := podman-$(RELEASE_NUMBER))
+ $(eval SUBDIR := podman-v$(RELEASE_NUMBER))
mkdir -p "$(TMPDIR)/$(SUBDIR)"
$(MAKE) install.bin install.man install.cni install.systemd "DESTDIR=$(TMPDIR)/$(SUBDIR)" "PREFIX=/usr"
# release.txt location and content depended upon by automated tooling
@@ -339,7 +343,7 @@ podman-$(RELEASE_NUMBER).tar.gz: binaries docs release.txt
-rm -rf "$(TMPDIR)"
# Must call make in-line: Dependency-spec. w/ wild-card also consumes variable value.
-podman-remote-$(RELEASE_NUMBER)-%.zip:
+podman-remote-v$(RELEASE_NUMBER)-%.zip:
$(MAKE) podman-remote-$* install-podman-remote-docs release.txt \
RELEASE_BASENAME=$(shell hack/get_release_info.sh REMOTENAME) \
RELEASE_DIST=$* RELEASE_DIST_VER="-"
@@ -364,12 +368,12 @@ podman-remote-$(RELEASE_NUMBER)-%.zip:
.PHONY: podman-release
podman-release:
rm -f release.txt
- $(MAKE) podman-$(RELEASE_NUMBER).tar.gz
+ $(MAKE) podman-v$(RELEASE_NUMBER).tar.gz
.PHONY: podman-remote-%-release
podman-remote-%-release:
rm -f release.txt
- $(MAKE) podman-remote-$(RELEASE_NUMBER)-$*.zip
+ $(MAKE) podman-remote-v$(RELEASE_NUMBER)-$*.zip
docker-docs: docs
(cd docs; ./dckrman.sh *.1)
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index 812cc1f51..bf88e853b 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -518,6 +518,10 @@ type SearchValues struct {
TlsVerify bool
}
+type TrustValues struct {
+ PodmanCommand
+}
+
type SignValues struct {
PodmanCommand
Directory string
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index 77c76d1b7..31f1b3ba4 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -33,6 +33,7 @@ func getMainCommands() []*cobra.Command {
func getImageSubCommands() []*cobra.Command {
return []*cobra.Command{
_signCommand,
+ _trustCommand,
}
}
diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go
index 0feba609b..cad256615 100644
--- a/cmd/podman/main_local.go
+++ b/cmd/podman/main_local.go
@@ -5,9 +5,12 @@ package main
import (
"context"
+ "fmt"
+ "io/ioutil"
"log/syslog"
"os"
"runtime/pprof"
+ "strconv"
"strings"
"syscall"
@@ -18,6 +21,7 @@ import (
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/tracing"
"github.com/containers/libpod/pkg/util"
+ "github.com/containers/libpod/utils"
"github.com/opentracing/opentracing-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -119,7 +123,29 @@ func profileOff(cmd *cobra.Command) error {
return nil
}
+func movePauseProcessToScope() error {
+ pausePidPath, err := util.GetRootlessPauseProcessPidPath()
+ if err != nil {
+ return errors.Wrapf(err, "could not get pause process pid file path")
+ }
+
+ data, err := ioutil.ReadFile(pausePidPath)
+ if err != nil {
+ return errors.Wrapf(err, "cannot read pause pid file")
+ }
+ pid, err := strconv.ParseUint(string(data), 10, 0)
+ if err != nil {
+ return errors.Wrapf(err, "cannot parse pid file %s", pausePidPath)
+ }
+
+ return utils.RunUnderSystemdScope(int(pid), "user.slice", "podman-pause.scope")
+}
+
func setupRootless(cmd *cobra.Command, args []string) error {
+ if !rootless.IsRootless() {
+ return nil
+ }
+
matches, err := rootless.ConfigurationMatches()
if err != nil {
return err
@@ -128,9 +154,6 @@ func setupRootless(cmd *cobra.Command, args []string) error {
logrus.Warningf("the current user namespace doesn't match the configuration in /etc/subuid or /etc/subgid")
logrus.Warningf("you can use `%s system migrate` to recreate the user namespace and restart the containers", os.Args[0])
}
- if os.Geteuid() == 0 || cmd == _searchCommand || cmd == _versionCommand || cmd == _mountCommand || cmd == _migrateCommand || strings.HasPrefix(cmd.Use, "help") {
- return nil
- }
podmanCmd := cliconfig.PodmanCommand{
Command: cmd,
@@ -139,6 +162,39 @@ func setupRootless(cmd *cobra.Command, args []string) error {
Remote: remoteclient,
}
+ runtime, err := libpodruntime.GetRuntime(getContext(), &podmanCmd)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.DeferredShutdown(false)
+
+ // do it only after podman has already re-execed and running with uid==0.
+ if os.Geteuid() == 0 {
+ ownsCgroup, err := cgroups.UserOwnsCurrentSystemdCgroup()
+ 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, err := runtime.GetConfig()
+ if err != nil {
+ return err
+ }
+ if conf.CgroupManager == libpod.SystemdCgroupsManager {
+ logrus.Warnf("Failed to add podman to systemd sandbox cgroup: %v", err)
+ } else {
+ logrus.Debugf("Failed to add podman to systemd sandbox cgroup: %v", err)
+ }
+ }
+ }
+ }
+
+ if os.Geteuid() == 0 || cmd == _searchCommand || cmd == _versionCommand || cmd == _mountCommand || cmd == _migrateCommand || strings.HasPrefix(cmd.Use, "help") {
+ return nil
+ }
+
pausePidPath, err := util.GetRootlessPauseProcessPidPath()
if err != nil {
return errors.Wrapf(err, "could not get pause process pid file path")
@@ -158,13 +214,6 @@ func setupRootless(cmd *cobra.Command, args []string) error {
}
// if there is no pid file, try to join existing containers, and create a pause process.
-
- runtime, err := libpodruntime.GetRuntime(getContext(), &podmanCmd)
- if err != nil {
- return errors.Wrapf(err, "could not get runtime")
- }
- defer runtime.DeferredShutdown(false)
-
ctrs, err := runtime.GetRunningContainers()
if err != nil {
logrus.Errorf(err.Error())
@@ -177,6 +226,17 @@ func setupRootless(cmd *cobra.Command, args []string) error {
}
became, ret, err := rootless.TryJoinFromFilePaths(pausePidPath, true, paths)
+ if err := movePauseProcessToScope(); err != nil {
+ conf, err := runtime.GetConfig()
+ if err != nil {
+ return err
+ }
+ if conf.CgroupManager == libpod.SystemdCgroupsManager {
+ logrus.Warnf("Failed to add pause process to systemd sandbox cgroup: %v", err)
+ } else {
+ logrus.Debugf("Failed to add pause process to systemd sandbox cgroup: %v", err)
+ }
+ }
if err != nil {
logrus.Errorf(err.Error())
os.Exit(1)
diff --git a/cmd/podman/trust.go b/cmd/podman/trust.go
index 0a79e1570..f13af96bc 100644
--- a/cmd/podman/trust.go
+++ b/cmd/podman/trust.go
@@ -6,22 +6,20 @@ import (
)
var (
+ trustCommand cliconfig.TrustValues
trustDescription = `Manages which registries you trust as a source of container images based on its location.
-
The location is determined by the transport and the registry host of the image. Using this container image docker://docker.io/library/busybox as an example, docker is the transport and docker.io is the registry host.`
- trustCommand = cliconfig.PodmanCommand{
- Command: &cobra.Command{
- Use: "trust",
- Short: "Manage container image trust policy",
- Long: trustDescription,
- RunE: commandRunE(),
- },
+ _trustCommand = &cobra.Command{
+ Use: "trust",
+ Short: "Manage container image trust policy",
+ Long: trustDescription,
+ RunE: commandRunE(),
}
)
func init() {
+ trustCommand.Command = _trustCommand
trustCommand.SetHelpTemplate(HelpTemplate())
trustCommand.SetUsageTemplate(UsageTemplate())
trustCommand.AddCommand(getTrustSubCommands()...)
- imageCommand.AddCommand(trustCommand.Command)
}
diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh
index 7c7659169..c1a01d6ab 100755
--- a/contrib/cirrus/setup_environment.sh
+++ b/contrib/cirrus/setup_environment.sh
@@ -50,9 +50,7 @@ case "${OS_REL_VER}" in
bash "$SCRIPT_BASE/add_second_partition.sh"; fi
;;
centos-7) # Current VM is an image-builder-image no local podman/testing
- echo "No further setup required for VM image building"
- # All SELinux distros need this for systemd-in-a-container
- setsebool container_manage_cgroup true
+ echo "No further setup required for VM image building"
exit 0
;;
*) bad_os_id_ver ;;
diff --git a/contrib/msi/podman-logo.ico b/contrib/msi/podman-logo.ico
new file mode 100644
index 000000000..cb1dab6a7
--- /dev/null
+++ b/contrib/msi/podman-logo.ico
Binary files differ
diff --git a/contrib/msi/podman.bat b/contrib/msi/podman.bat
new file mode 100644
index 000000000..091c1c4c4
--- /dev/null
+++ b/contrib/msi/podman.bat
@@ -0,0 +1,43 @@
+@echo off
+setlocal enableextensions
+
+title Podman
+
+:: If remote-host is given on command line -- use it
+setlocal enabledelayedexpansion
+for %%a in (%*) do (
+ echo "%%a" |find "--remote-host" >NUL
+ if !errorlevel! == 0 (
+ goto run_podman
+ )
+)
+
+:: If PODMAN_VARLINK_BRIDGE is set -- use it
+if defined PODMAN_VARLINK_BRIDGE (
+ goto run_podman
+)
+
+:: If the configuration file exists -- use it
+set config_home=%USERPROFILE%\AppData\podman
+set config_file=%config_home%\podman-remote.conf
+if exist "%config_file%" (
+ goto run_podman
+)
+
+:: Get connection information from user and build configuration file
+md "%config_home%"
+set /p host="Please enter the remote hosts name or IP address: "
+set /p user="Please enter the remote user name: "
+(
+ echo [connections]
+ echo [connections."%host%"]
+ echo destination = "%host%"
+ echo username = "%user%"
+ echo default = true
+) >"%config_file%"
+
+:run_podman
+endlocal
+podman-remote-windows.exe %*
+
+:End
diff --git a/contrib/msi/podman.wxs b/contrib/msi/podman.wxs
new file mode 100644
index 000000000..77c6e2815
--- /dev/null
+++ b/contrib/msi/podman.wxs
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+
+ <?ifndef var.VERSION?>
+ <?error VERSION must be defined via command line argument?>
+ <?endif?>
+
+ <Product Name="Podman $(var.VERSION)" Id="*" UpgradeCode="696BAB5D-CA1F-4B05-B123-320F245B8D6D" Version="$(var.VERSION)" Language="1033" Manufacturer="Red Hat Inc.">
+
+ <Package Id="*" Keywords="Installer" Description="Red Hat's Podman $(var.VERSION) Installer" Comments="Apache 2.0 License" Manufacturer="Red Hat Inc." InstallScope="perMachine" InstallerVersion="100" Compressed="yes"/>
+ <Media Id="1" Cabinet="Podman.cab" EmbedCab="yes"/>
+ <Property Id="DiskPrompt" Value="Red Hat's Podman $(var.VERSION) Installation"/>
+
+ <Directory Id="TARGETDIR" Name="SourceDir">
+
+ <Directory Id="ProgramFilesFolder" Name="PFiles">
+ <Directory Id="RedHatPFiles" Name="RedHat">
+ <Directory Id="INSTALLDIR" Name="Podman">
+ <Component Id="INSTALLDIR_Component" Guid="14B310C4-9B5D-4DA5-ADF9-B9D008E4CD82">
+ <CreateFolder/>
+ </Component>
+ <Component Id="MainExecutable" Guid="73752F94-6589-4C7B-ABED-39D655A19714">
+ <File Id="520C6E17-77A2-4F41-9611-30FA763A0702" Name="podman-remote-windows.exe" Source="bin/podman-remote-windows.exe"/>
+ <File Id="A14218A0-4180-44AC-B109-7C63B3099DCA" Name="podman.bat" Source="podman.bat" KeyPath="yes"/>
+ </Component>
+ </Directory>
+ </Directory>
+ </Directory>
+ </Directory>
+
+ <Property Id="setx" Value="setx.exe"/>
+ <CustomAction Id="ChangePath" ExeCommand='PATH "%PATH%;[INSTALLDIR]"' Property="setx" Execute="deferred" Impersonate="yes" Return="check"/>
+
+ <Feature Id="Complete" Level="1">
+ <ComponentRef Id="INSTALLDIR_Component"/>
+ <ComponentRef Id="MainExecutable"/>
+ </Feature>
+
+ <Icon Id="podman.ico" SourceFile="contrib/msi/podman-logo.ico"/>
+ <Property Id="ARPPRODUCTICON" Value="podman.ico"/>
+
+ <InstallExecuteSequence>
+ <RemoveExistingProducts Before="InstallInitialize"/>
+ <Custom Action="ChangePath" After="InstallServices">NOT Installed</Custom>
+ </InstallExecuteSequence>
+
+ </Product>
+</Wix>
diff --git a/docs/podman-image-trust.1.md b/docs/podman-image-trust.1.md
index b35e883d7..3fe4f7f52 100644
--- a/docs/podman-image-trust.1.md
+++ b/docs/podman-image-trust.1.md
@@ -8,7 +8,9 @@ podman\-image\-trust - Manage container registry image trust policy
**podman image trust** set|show [*options*] *registry[/repository]*
## DESCRIPTION
-Manages which registries you trust as a source of container images based on its location. The location is determined
+Manages which registries you trust as a source of container images based on its location. (Not available for remote commands)
+
+The location is determined
by the transport and the registry host of the image. Using this container image `docker://docker.io/library/busybox`
as an example, `docker` is the transport and `docker.io` is the registry host.
diff --git a/docs/tutorials/rootless_tutorial.md b/docs/tutorials/rootless_tutorial.md
index c98e74c96..ed700485a 100644
--- a/docs/tutorials/rootless_tutorial.md
+++ b/docs/tutorials/rootless_tutorial.md
@@ -4,6 +4,17 @@
Prior to allowing users without root privileges to run Podman, the administrator must install or build Podman and complete the following configurations.
+## cgroup V2 support
+
+The cgroup V2 Linux kernel feature allows the user to limit the amount of resources a rootless container can use. If the Linux distribution that you are running Podman on is enabled with cgroup V2 then you might need to change the default OCI Runtime. The default runtime `runc` does not currently work with cgroup V2 enabled systems, so you have to switch to the alternative OCI runtime `crun`.
+
+The alternative OCI runtime support for cgroup V2 can be turned on at the command line by using the `--runtime` option:
+
+```
+sudo podman --runtime /usr/bin/crun
+```
+or by changing the value for the "Default OCI runtime" in the libpod.conf file either at the system level or at the [#user-configuration-files](user level) from `runtime = "runc"` to `runtime = "crun"`.
+
## Administrator Actions
### Installing Podman
@@ -22,7 +33,7 @@ The [slirp4netns](https://github.com/rootless-containers/slirp4netns) package pr
When using Podman in a rootless environment, it is recommended to use fuse-overlayfs rather than the VFS file system. Installing the fuse3-devel package gives Podman the dependencies it needs to install, build and use fuse-overlayfs in a rootless environment for you. The fuse-overlayfs project is also available from [GitHub](https://github.com/containers/fuse-overlayfs). This especially needs to be checked on Ubuntu distributions as fuse-overlayfs is not generally installed by default.
-If podman is installed before fuse-overlayfs, it may be necessary to change the `driver` option under `[storage]` to `"overlay"`.
+If Podman is installed before fuse-overlayfs, it may be necessary to change the `driver` option under `[storage]` to `"overlay"`.
### Enable user namespaces (on RHEL7 machines)
@@ -48,7 +59,7 @@ The format of this file is USERNAME:UID:RANGE
This means the user johndoe is allocated UIDS 100000-165535 as well as their standard UID in the /etc/passwd file. NOTE: this is not currently supported with network installs. These files must be available locally to the host machine. It is not possible to configure this with LDAP or Active Directory.
-If you update either the /etc/subuid or the /etc/subgid file, you need to stop all the running containers owned by the user and kill the pause process that is running on the system for that user. This can be done automatically by using the [`podman system migrate`](https://github.com/containers/libpod/blob/master/docs/podman-system-migrate.1.md) command which will stop all the containers for the user and will kill the pause process.
+If you update either the /etc/subuid or the /etc/subgid file, you need to stop all the running containers owned by the user and kill the pause process that is running on the system for that user. This can be done automatically by using the `[podman system migrate](https://github.com/containers/libpod/blob/master/docs/podman-system-migrate.1.md)` command which will stop all the containers for the user and will kill the pause process.
Rather than updating the files directly, the usermod program can be used to assign UIDs and GIDs to a user.
@@ -78,7 +89,7 @@ Once the Administrator has completed the setup on the machine and then the confi
### User Configuration Files.
-The Podman configuration files for root reside in /usr/share/containers with overrides in /etc/containers. In the rootless environment they reside in ${XDG\_CONFIG\_HOME}/containers and are owned by each individual user. The user can modify these files as they wish.
+The Podman configuration files for root reside in /usr/share/containers with overrides in /etc/containers. In the rootless environment they reside in ${XDG\_CONFIG\_HOME}/containers and are owned by each individual user. The main files are libpod.conf and storage.conf and the user can modify these files as they wish.
The default authorization file used by the `podman login` and `podman logout` commands reside in ${XDG\_RUNTIME\_DIR}/containers/auth.json.
@@ -89,7 +100,6 @@ The default authorization file used by the `podman login` and `podman logout` co
Description=nginx
Requires=user@1001.service
After=user@1001.service
-
[Service]
Type=simple
KillMode=none
@@ -101,7 +111,6 @@ ExecStop=/usr/bin/podman stop nginx
Restart=always
User=nginx
Group=nginx
-
[Install]
WantedBy=multi-user.target
```
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 9f16389e6..4bbbef5db 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -491,12 +491,29 @@ func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) erro
if unified {
g.RemoveMount("/sys/fs/cgroup")
- sourcePath := filepath.Join("/sys/fs/cgroup")
- systemdMnt := spec.Mount{
- Destination: "/sys/fs/cgroup",
- Type: "bind",
- Source: sourcePath,
- Options: []string{"bind", "private", "rw"},
+ hasCgroupNs := false
+ for _, ns := range c.config.Spec.Linux.Namespaces {
+ if ns.Type == spec.CgroupNamespace {
+ hasCgroupNs = true
+ break
+ }
+ }
+
+ var systemdMnt spec.Mount
+ if hasCgroupNs {
+ systemdMnt = spec.Mount{
+ Destination: "/sys/fs/cgroup",
+ Type: "cgroup",
+ Source: "cgroup",
+ Options: []string{"private", "rw"},
+ }
+ } else {
+ systemdMnt = spec.Mount{
+ Destination: "/sys/fs/cgroup",
+ Type: "bind",
+ Source: "/sys/fs/cgroup",
+ Options: []string{"bind", "private", "rw"},
+ }
}
g.AddMount(systemdMnt)
} else {
diff --git a/libpod/oci_internal_linux.go b/libpod/oci_internal_linux.go
index f9e935d86..4df1e4010 100644
--- a/libpod/oci_internal_linux.go
+++ b/libpod/oci_internal_linux.go
@@ -21,6 +21,7 @@ import (
"github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/libpod/pkg/lookup"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
"github.com/coreos/go-systemd/activation"
@@ -359,35 +360,46 @@ func startCommandGivenSelinux(cmd *exec.Cmd) error {
// moveConmonToCgroupAndSignal gets a container's cgroupParent and moves the conmon process to that cgroup
// it then signals for conmon to start by sending nonse data down the start fd
func (r *OCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec.Cmd, startFd *os.File, uuid string) error {
+ mustCreateCgroup := true
// If cgroup creation is disabled - just signal.
if ctr.config.NoCgroups {
- return writeConmonPipeData(startFd)
+ mustCreateCgroup = false
}
- cgroupParent := ctr.CgroupParent()
- if r.cgroupManager == SystemdCgroupsManager {
- unitName := createUnitName("libpod-conmon", ctr.ID())
-
- realCgroupParent := cgroupParent
- splitParent := strings.Split(cgroupParent, "/")
- if strings.HasSuffix(cgroupParent, ".slice") && len(splitParent) > 1 {
- realCgroupParent = splitParent[len(splitParent)-1]
+ if rootless.IsRootless() {
+ ownsCgroup, err := cgroups.UserOwnsCurrentSystemdCgroup()
+ if err != nil {
+ return err
}
+ mustCreateCgroup = !ownsCgroup
+ }
- logrus.Infof("Running conmon under slice %s and unitName %s", realCgroupParent, unitName)
- if err := utils.RunUnderSystemdScope(cmd.Process.Pid, realCgroupParent, unitName); err != nil {
- logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err)
- }
- } else {
- cgroupPath := filepath.Join(ctr.config.CgroupParent, "conmon")
- control, err := cgroups.New(cgroupPath, &spec.LinuxResources{})
- if err != nil {
- logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
+ if mustCreateCgroup {
+ cgroupParent := ctr.CgroupParent()
+ if r.cgroupManager == SystemdCgroupsManager {
+ unitName := createUnitName("libpod-conmon", ctr.ID())
+
+ realCgroupParent := cgroupParent
+ splitParent := strings.Split(cgroupParent, "/")
+ if strings.HasSuffix(cgroupParent, ".slice") && len(splitParent) > 1 {
+ realCgroupParent = splitParent[len(splitParent)-1]
+ }
+
+ logrus.Infof("Running conmon under slice %s and unitName %s", realCgroupParent, unitName)
+ if err := utils.RunUnderSystemdScope(cmd.Process.Pid, realCgroupParent, unitName); err != nil {
+ logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err)
+ }
} else {
- // we need to remove this defer and delete the cgroup once conmon exits
- // maybe need a conmon monitor?
- if err := control.AddPid(cmd.Process.Pid); err != nil {
+ cgroupPath := filepath.Join(ctr.config.CgroupParent, "conmon")
+ control, err := cgroups.New(cgroupPath, &spec.LinuxResources{})
+ if err != nil {
logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
+ } else {
+ // we need to remove this defer and delete the cgroup once conmon exits
+ // maybe need a conmon monitor?
+ if err := control.AddPid(cmd.Process.Pid); err != nil {
+ logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
+ }
}
}
}
diff --git a/libpod/runtime_cstorage.go b/libpod/runtime_cstorage.go
index 586db5a1e..1e84aef4b 100644
--- a/libpod/runtime_cstorage.go
+++ b/libpod/runtime_cstorage.go
@@ -1,6 +1,8 @@
package libpod
import (
+ "time"
+
"github.com/containers/libpod/libpod/define"
"github.com/containers/storage"
"github.com/pkg/errors"
@@ -12,6 +14,8 @@ import (
type StorageContainer struct {
ID string
Names []string
+ Image string
+ CreateTime time.Time
PresentInLibpod bool
}
@@ -31,6 +35,8 @@ func (r *Runtime) ListStorageContainers() ([]*StorageContainer, error) {
storageCtr := new(StorageContainer)
storageCtr.ID = ctr.ID
storageCtr.Names = ctr.Names
+ storageCtr.Image = ctr.ImageID
+ storageCtr.CreateTime = ctr.Created
// Look up if container is in state
hasCtr, err := r.state.HasContainer(ctr.ID)
diff --git a/pkg/cgroups/cgroups_supported.go b/pkg/cgroups/cgroups_supported.go
index fcd44dfc8..2a36777d4 100644
--- a/pkg/cgroups/cgroups_supported.go
+++ b/pkg/cgroups/cgroups_supported.go
@@ -3,8 +3,15 @@
package cgroups
import (
+ "bufio"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
"sync"
"syscall"
+
+ "github.com/pkg/errors"
)
var (
@@ -25,3 +32,58 @@ func IsCgroup2UnifiedMode() (bool, error) {
})
return isUnified, isUnifiedErr
}
+
+// UserOwnsCurrentSystemdCgroup checks whether the current EUID owns the
+// current cgroup.
+func UserOwnsCurrentSystemdCgroup() (bool, error) {
+ uid := os.Geteuid()
+
+ cgroup2, err := IsCgroup2UnifiedMode()
+ if err != nil {
+ return false, err
+ }
+
+ f, err := os.Open("/proc/self/cgroup")
+ if err != nil {
+ return false, errors.Wrapf(err, "open file /proc/self/cgroup")
+ }
+ defer f.Close()
+
+ scanner := bufio.NewScanner(f)
+ for scanner.Scan() {
+ line := scanner.Text()
+ parts := strings.SplitN(line, ":", 3)
+
+ if len(parts) < 3 {
+ continue
+ }
+
+ var cgroupPath string
+
+ if cgroup2 {
+ cgroupPath = filepath.Join(cgroupRoot, parts[2])
+ } else {
+ if parts[1] != "name=systemd" {
+ continue
+ }
+ cgroupPath = filepath.Join(cgroupRoot, "systemd", parts[2])
+ }
+
+ st, err := os.Stat(cgroupPath)
+ if err != nil {
+ return false, err
+ }
+ s := st.Sys()
+ if s == nil {
+ return false, fmt.Errorf("error stat cgroup path %s", cgroupPath)
+ }
+
+ if int(s.(*syscall.Stat_t).Uid) != uid {
+ return false, nil
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ return false, errors.Wrapf(err, "parsing file /proc/self/cgroup")
+ }
+ return true, nil
+}
diff --git a/pkg/cgroups/cgroups_unsupported.go b/pkg/cgroups/cgroups_unsupported.go
index 9dc196e42..cd140fbf3 100644
--- a/pkg/cgroups/cgroups_unsupported.go
+++ b/pkg/cgroups/cgroups_unsupported.go
@@ -6,3 +6,9 @@ package cgroups
func IsCgroup2UnifiedMode() (bool, error) {
return false, nil
}
+
+// UserOwnsCurrentSystemdCgroup checks whether the current EUID owns the
+// current cgroup.
+func UserOwnsCurrentSystemdCgroup() (bool, error) {
+ return false, nil
+}
diff --git a/rootless.md b/rootless.md
index c5033881b..960430d54 100644
--- a/rootless.md
+++ b/rootless.md
@@ -6,14 +6,14 @@ Contributors are more than welcomed to help with this work. If you decide to ca
* Podman can not create containers that bind to ports < 1024.
* The kernel does not allow processes without CAP_NET_BIND_SERVICE to bind to low ports.
-* Lacking “How To” documentation or documentation in general
-* If /etc/subuid and /etc/subgid not setup for a user, then podman commands
+* “How To” documentation is patchy at best.
+* If /etc/subuid and /etc/subgid are not setup for a user, then podman commands
can easily fail
* This can be a big issue on machines using Network Based Password information (FreeIPA, Active Directory, LDAP)
* We are working to get support for NSSWITCH on the /etc/subuid and /etc/subgid files.
-* No cgroup Support (hopefully fixed when cgroups V2 happens).
- * Cgroups V1 does not safely support cgroup delegation.
- * Cgroups V2 development for container support is ongoing.
+* No cgroup V1 Support
+ * cgroup V1 does not safely support cgroup delegation.
+ * However, cgroup V2 provides cgroup delegation and is available on Fedora starting with version 29 and other Linux distributions.
* Can not share container images with CRI-O or other users
* Difficult to use additional stores for sharing content
* Does not work on NFS or parallel filesystem homedirs (e.g. [GPFS](https://www.ibm.com/support/knowledgecenter/en/SSFKCN/gpfs_welcome.html))
@@ -28,13 +28,13 @@ can easily fail
* No CNI Support
* CNI wants to modify IPTables, plus other network manipulation that requires CAP_SYS_ADMIN.
* There is potential we could probably do some sort of blacklisting of the relevant plugins, and add a new plugin for rootless networking - slirp4netns as one example and there may be others
-* Cannot use ping
+* Cannot use ping out of the box.
* [(Can be fixed by setting sysctl on host)](https://github.com/containers/libpod/blob/master/troubleshooting.md#5-rootless-containers-cannot-ping-hosts)
-* Requires new shadow-utils (not found in older (RHEL7/Centos7 distros) Should be fixed in RHEL7.7 release
+* Requires new shadow-utils (not found in older (RHEL7/Centos7 distros) Should be fixed in RHEL7.7 release)
* A few commands do not work.
* mount/unmount (on fuse-overlay)
* Only works if you enter the mount namespace with a tool like buildah unshare
- * podman stats (Lack of Cgroup support)
+ * podman stats (Without cgroup V2 support)
* Checkpoint and Restore (CRIU requires root)
* Pause and Unpause (no freezer cgroup)
* Issues with higher UIDs can cause builds to fail
diff --git a/utils/utils_supported.go b/utils/utils_supported.go
index 8b0ba4438..8bc232179 100644
--- a/utils/utils_supported.go
+++ b/utils/utils_supported.go
@@ -3,6 +3,8 @@
package utils
import (
+ "github.com/containers/libpod/pkg/cgroups"
+ "github.com/containers/libpod/pkg/rootless"
systemdDbus "github.com/coreos/go-systemd/dbus"
"github.com/godbus/dbus"
)
@@ -10,9 +12,19 @@ import (
// RunUnderSystemdScope adds the specified pid to a systemd scope
func RunUnderSystemdScope(pid int, slice string, unitName string) error {
var properties []systemdDbus.Property
- conn, err := systemdDbus.New()
- if err != nil {
- return err
+ var conn *systemdDbus.Conn
+ var err error
+
+ if rootless.IsRootless() {
+ conn, err = cgroups.GetUserConnection(rootless.GetRootlessUID())
+ if err != nil {
+ return err
+ }
+ } else {
+ conn, err = systemdDbus.New()
+ if err != nil {
+ return err
+ }
}
properties = append(properties, systemdDbus.PropSlice(slice))
properties = append(properties, newProp("PIDs", []uint32{uint32(pid)}))