summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/cirrus/git_authors_to_irc_nicks.csv8
-rw-r--r--contrib/cirrus/lib.sh5
-rwxr-xr-xcontrib/cirrus/success.sh48
-rw-r--r--docs/tutorials/rootless_tutorial.md30
-rw-r--r--pkg/spec/config_linux.go75
-rw-r--r--test/e2e/run_device_test.go16
-rw-r--r--troubleshooting.md19
7 files changed, 180 insertions, 21 deletions
diff --git a/contrib/cirrus/git_authors_to_irc_nicks.csv b/contrib/cirrus/git_authors_to_irc_nicks.csv
new file mode 100644
index 000000000..4334b5cd2
--- /dev/null
+++ b/contrib/cirrus/git_authors_to_irc_nicks.csv
@@ -0,0 +1,8 @@
+# Comma separated mapping of author e-mail, to Freenode IRC nick.
+# When no match is found here, the username portion of the e-mail is used.
+# Sorting is done at runtime - first-found e-mail match wins.
+# Comments (like this) and blank lines are ignored.
+
+rothberg@redhat.com,vrothberg
+santiago@redhat.com,edsantiago
+gscrivan@redhat.com,giuseppe
diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh
index f66e63140..cd8b2ef61 100644
--- a/contrib/cirrus/lib.sh
+++ b/contrib/cirrus/lib.sh
@@ -28,11 +28,12 @@ CIRRUS_WORKING_DIR="${CIRRUS_WORKING_DIR:-$GOPATH/src/github.com/containers/libp
export GOSRC="${GOSRC:-$CIRRUS_WORKING_DIR}"
export PATH="$HOME/bin:$GOPATH/bin:/usr/local/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}"
-TIMESTAMPS_FILEPATH="${TIMESTAMPS_FILEPATH:-/var/tmp/timestamps}"
-SETUP_MARKER_FILEPATH="${SETUP_MARKER_FILEPATH:-/var/tmp/.setup_environment_sh_complete}"
# Saves typing / in case location ever moves
SCRIPT_BASE=${SCRIPT_BASE:-./contrib/cirrus}
PACKER_BASE=${PACKER_BASE:-./contrib/cirrus/packer}
+# Important filepaths
+SETUP_MARKER_FILEPATH="${SETUP_MARKER_FILEPATH:-/var/tmp/.setup_environment_sh_complete}"
+AUTHOR_NICKS_FILEPATH="${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/git_authors_to_irc_nicks.csv"
cd $GOSRC
if type -P git &> /dev/null
diff --git a/contrib/cirrus/success.sh b/contrib/cirrus/success.sh
index c4e150514..f2c9fbc7f 100755
--- a/contrib/cirrus/success.sh
+++ b/contrib/cirrus/success.sh
@@ -4,14 +4,52 @@ set -e
source $(dirname $0)/lib.sh
-req_env_var CIRRUS_BRANCH CIRRUS_BUILD_ID
+req_env_var CIRRUS_BRANCH CIRRUS_BUILD_ID CIRRUS_REPO_FULL_NAME
-REF=$(basename $CIRRUS_BRANCH) # PR number or branch named
-URL="https://cirrus-ci.com/build/$CIRRUS_BUILD_ID"
+cd $CIRRUS_WORKING_DIR
if [[ "$CIRRUS_BRANCH" =~ "pull" ]]
then
- ircmsg "Cirrus-CI testing successful for PR #$REF: $URL"
+ echo "Finding commit authors for PR $CIRRUS_PR"
+ unset NICKS
+ if [[ -r "$AUTHOR_NICKS_FILEPATH" ]]
+ then
+ SHARANGE="${CIRRUS_BASE_SHA}..${CIRRUS_CHANGE_IN_REPO}"
+ EXCLUDE_RE='merge-robot'
+ AUTHOR_NICKS=$(egrep -v '(^[[:space:]]*$)|(^[[:space:]]*#)' "$AUTHOR_NICKS_FILEPATH" | sort -u)
+ # Depending on branch-state, it's possible SHARANGE could be _WAY_ too big
+ MAX_NICKS=10
+ # newline separated
+ COMMIT_AUTHORS=$(git log --format='%ae' $SHARANGE | \
+ sort -u | \
+ egrep -v "$EXCLUDE_RE" | \
+ tail -$MAX_NICKS)
+
+ for c_email in $COMMIT_AUTHORS
+ do
+ echo -e "\tExamining $c_email"
+ NICK=$(echo "$AUTHOR_NICKS" | grep -m 1 "$c_email" | \
+ awk --field-separator ',' '{print $2}' | tr -d '[[:blank:]]')
+ if [[ -n "$NICK" ]]
+ then
+ echo -e "\t\tFound $c_email -> $NICK in $(basename $AUTHOR_NICKS_FILEPATH)"
+ else
+ echo -e "\t\tNot found in $(basename $AUTHOR_NICKS_FILEPATH), using e-mail username."
+ NICK=$(echo "$c_email" | cut -d '@' -f 1)
+ fi
+ echo -e "\tUsing nick $NICK"
+ NICKS="${NICKS:+$NICKS, }$NICK"
+ done
+ fi
+
+ unset MENTION_PREFIX
+ [[ -z "$NICKS" ]] || \
+ MENTION_PREFIX="$NICKS: "
+
+ URL="https://github.com/$CIRRUS_REPO_FULL_NAME/pull/$CIRRUS_PR"
+ PR_SUBJECT=$(echo "$CIRRUS_CHANGE_MESSAGE" | head -1)
+ ircmsg "${MENTION_PREFIX}Cirrus-CI testing successful for PR '$PR_SUBJECT': $URL"
else
- ircmsg "Cirrus-CI testing branch $REF successful: $URL"
+ URL="https://cirrus-ci.com/github/containers/libpod/$CIRRUS_BRANCH"
+ ircmsg "Cirrus-CI testing branch $(basename $CIRRUS_BRANCH) successful: $URL"
fi
diff --git a/docs/tutorials/rootless_tutorial.md b/docs/tutorials/rootless_tutorial.md
index 92595dd02..91962fead 100644
--- a/docs/tutorials/rootless_tutorial.md
+++ b/docs/tutorials/rootless_tutorial.md
@@ -80,6 +80,36 @@ The Podman configuration files for root reside in /usr/share/containers with ove
The default authorization file used by the `podman login` and `podman logout` commands reside in ${XDG\_RUNTIME\_DIR}/containers/auth.json.
+## Systemd unit for rootless container
+
+```
+[Unit]
+Description=nginx
+Requires=user@1001.service
+After=user@1001.service
+
+[Service]
+Type=simple
+KillMode=none
+MemoryMax=200M
+ExecStartPre=-/usr/bin/podman rm -f nginx
+ExecStartPre=/usr/bin/podman pull nginx
+ExecStart=/usr/bin/podman run --name=nginx -p 8080:80 -v /home/nginx/html:/usr/share/nginx/html:Z nginx
+ExecStop=/usr/bin/podman stop nginx
+Restart=always
+User=nginx
+Group=nginx
+
+[Install]
+WantedBy=multi-user.target
+```
+
+This example unit will launch a nginx container using the existing user nginx with id 1001, serving static content from /home/nginx/html and limited to 200MB of RAM.
+
+You can use all the usual systemd flags to control the process, including capabilities and cgroup directives to limit memory or CPU.
+
+See #3866 for more details.
+
## More information
If you are still experiencing problems running Podman in a rootless environment, please refer to the [Shortcomings of Rootless Podman](https://github.com/containers/libpod/blob/master/rootless.md) page which lists known issues and solutions to known issues in this environment.
diff --git a/pkg/spec/config_linux.go b/pkg/spec/config_linux.go
index 60d31d78e..32d8cb4de 100644
--- a/pkg/spec/config_linux.go
+++ b/pkg/spec/config_linux.go
@@ -4,6 +4,7 @@ package createconfig
import (
"fmt"
+ "io/ioutil"
"os"
"path/filepath"
"strings"
@@ -98,6 +99,26 @@ func addDevice(g *generate.Generator, device string) error {
if err != nil {
return errors.Wrapf(err, "%s is not a valid device", src)
}
+ if rootless.IsRootless() {
+ if _, err := os.Stat(src); err != nil {
+ if os.IsNotExist(err) {
+ return errors.Wrapf(err, "the specified device %s doesn't exist", src)
+ }
+ return errors.Wrapf(err, "stat device %s exist", src)
+ }
+ perm := "ro"
+ if strings.Contains(permissions, "w") {
+ perm = "rw"
+ }
+ devMnt := spec.Mount{
+ Destination: dst,
+ Type: TypeBind,
+ Source: src,
+ Options: []string{"slave", "nosuid", "noexec", perm, "rbind"},
+ }
+ g.Config.Mounts = append(g.Config.Mounts, devMnt)
+ return nil
+ }
dev.Path = dst
linuxdev := spec.LinuxDevice{
Path: dev.Path,
@@ -113,8 +134,53 @@ func addDevice(g *generate.Generator, device string) error {
return nil
}
+// based on getDevices from runc (libcontainer/devices/devices.go)
+func getDevices(path string) ([]*configs.Device, error) {
+ files, err := ioutil.ReadDir(path)
+ if err != nil {
+ if rootless.IsRootless() && os.IsPermission(err) {
+ return nil, nil
+ }
+ return nil, err
+ }
+ out := []*configs.Device{}
+ for _, f := range files {
+ switch {
+ case f.IsDir():
+ switch f.Name() {
+ // ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
+ case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts":
+ continue
+ default:
+ sub, err := getDevices(filepath.Join(path, f.Name()))
+ if err != nil {
+ return nil, err
+ }
+ if sub != nil {
+ out = append(out, sub...)
+ }
+ continue
+ }
+ case f.Name() == "console":
+ continue
+ }
+ device, err := devices.DeviceFromPath(filepath.Join(path, f.Name()), "rwm")
+ if err != nil {
+ if err == devices.ErrNotADevice {
+ continue
+ }
+ if os.IsNotExist(err) {
+ continue
+ }
+ return nil, err
+ }
+ out = append(out, device)
+ }
+ return out, nil
+}
+
func (c *CreateConfig) addPrivilegedDevices(g *generate.Generator) error {
- hostDevices, err := devices.HostDevices()
+ hostDevices, err := getDevices("/dev")
if err != nil {
return err
}
@@ -153,15 +219,16 @@ func (c *CreateConfig) addPrivilegedDevices(g *generate.Generator) error {
newMounts = append(newMounts, devMnt)
}
g.Config.Mounts = append(newMounts, g.Config.Mounts...)
+ g.Config.Linux.Resources.Devices = nil
} else {
for _, d := range hostDevices {
g.AddDevice(Device(d))
}
+ // Add resources device - need to clear the existing one first.
+ g.Config.Linux.Resources.Devices = nil
+ g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm")
}
- // Add resources device - need to clear the existing one first.
- g.Config.Linux.Resources.Devices = nil
- g.AddLinuxResourcesDevice(true, "", nil, nil, "rwm")
return nil
}
diff --git a/test/e2e/run_device_test.go b/test/e2e/run_device_test.go
index cf7ce9cdf..d3b4b0e32 100644
--- a/test/e2e/run_device_test.go
+++ b/test/e2e/run_device_test.go
@@ -35,44 +35,40 @@ var _ = Describe("Podman run device", func() {
})
It("podman run bad device test", func() {
- session := podmanTest.Podman([]string{"run", "-q", "--device", "/dev/baddevice", ALPINE, "ls", "/dev/kmsg"})
+ session := podmanTest.Podman([]string{"run", "-q", "--device", "/dev/baddevice", ALPINE, "true"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
})
It("podman run device test", func() {
- SkipIfRootless()
- session := podmanTest.Podman([]string{"run", "-q", "--device", "/dev/kmsg", ALPINE, "ls", "--color=never", "/dev/kmsg"})
+ session := podmanTest.Podman([]string{"run", "-q", "--security-opt", "label=disable", "--device", "/dev/kmsg", ALPINE, "ls", "--color=never", "/dev/kmsg"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal("/dev/kmsg"))
})
It("podman run device rename test", func() {
- SkipIfRootless()
- session := podmanTest.Podman([]string{"run", "-q", "--device", "/dev/kmsg:/dev/kmsg1", ALPINE, "ls", "--color=never", "/dev/kmsg1"})
+ session := podmanTest.Podman([]string{"run", "-q", "--security-opt", "label=disable", "--device", "/dev/kmsg:/dev/kmsg1", ALPINE, "ls", "--color=never", "/dev/kmsg1"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal("/dev/kmsg1"))
})
It("podman run device permission test", func() {
- SkipIfRootless()
- session := podmanTest.Podman([]string{"run", "-q", "--device", "/dev/kmsg:r", ALPINE, "ls", "--color=never", "/dev/kmsg"})
+ session := podmanTest.Podman([]string{"run", "-q", "--security-opt", "label=disable", "--device", "/dev/kmsg:r", ALPINE, "ls", "--color=never", "/dev/kmsg"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal("/dev/kmsg"))
})
It("podman run device rename and permission test", func() {
- SkipIfRootless()
- session := podmanTest.Podman([]string{"run", "-q", "--device", "/dev/kmsg:/dev/kmsg1:r", ALPINE, "ls", "--color=never", "/dev/kmsg1"})
+ session := podmanTest.Podman([]string{"run", "-q", "--security-opt", "label=disable", "--device", "/dev/kmsg:/dev/kmsg1:r", ALPINE, "ls", "--color=never", "/dev/kmsg1"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal("/dev/kmsg1"))
})
It("podman run device rename and bad permission test", func() {
- session := podmanTest.Podman([]string{"run", "-q", "--device", "/dev/kmsg:/dev/kmsg1:rd", ALPINE, "ls", "--color=never", "/dev/kmsg1"})
+ session := podmanTest.Podman([]string{"run", "-q", "--security-opt", "label=disable", "--device", "/dev/kmsg:/dev/kmsg1:rd", ALPINE, "ls", "--color=never", "/dev/kmsg1"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
})
diff --git a/troubleshooting.md b/troubleshooting.md
index b88940dc8..9a5b38e01 100644
--- a/troubleshooting.md
+++ b/troubleshooting.md
@@ -391,3 +391,22 @@ Choose one of the following:
* Install and configure fuse-overlayfs.
* Install the fuse-overlayfs package for your Linux Distribution.
* Add `mount_program = "/usr/bin/fuse-overlayfs` under `[storage.options]` in your `~/.config/containers/storage.conf` file.
+
+### 16) rhel7-init based images don't work with cgroups v2
+
+The systemd version shipped in rhel7-init doesn't have support for cgroups v2. You'll need at least systemd 230.
+
+#### Symptom
+```console
+
+sh# podman run --name test -d registry.access.redhat.com/rhel7-init:latest && sleep 10 && podman exec test systemctl status
+c8567461948439bce72fad3076a91ececfb7b14d469bfa5fbc32c6403185beff
+Failed to get D-Bus connection: Operation not permitted
+Error: non zero exit code: 1: OCI runtime error
+```
+
+#### Solution
+You'll need to either:
+
+* configure the host to use cgroups v1
+* update the image to use an updated version of systemd.