diff options
-rw-r--r-- | Makefile | 9 | ||||
-rwxr-xr-x | contrib/build_rpm.sh | 1 | ||||
-rw-r--r-- | docs/source/markdown/podman-build.1.md | 4 | ||||
-rw-r--r-- | docs/source/markdown/podman-create.1.md | 4 | ||||
-rw-r--r-- | docs/source/markdown/podman-info.1.md | 27 | ||||
-rw-r--r-- | docs/source/markdown/podman-run.1.md | 4 | ||||
-rwxr-xr-x | hack/systemd_tag.sh | 7 | ||||
-rw-r--r-- | install.md | 6 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 98 | ||||
-rw-r--r-- | libpod/diff.go | 44 | ||||
-rw-r--r-- | libpod/runtime.go | 20 | ||||
-rw-r--r-- | pkg/adapter/checkpoint_restore.go | 1 | ||||
-rw-r--r-- | pkg/registries/registries.go | 7 | ||||
-rw-r--r-- | test/e2e/checkpoint_test.go | 20 | ||||
-rw-r--r-- | test/e2e/e2e.coverprofile | 11 | ||||
-rw-r--r-- | test/system/010-images.bats | 39 | ||||
-rw-r--r-- | test/system/helpers.bash | 2 | ||||
-rw-r--r-- | troubleshooting.md | 18 |
18 files changed, 213 insertions, 109 deletions
@@ -45,7 +45,7 @@ endif ifeq (,$(findstring systemd,$(BUILDTAGS))) $(warning \ Podman is being compiled without the systemd build tag.\ - Install libsystemd for journald support) + Install libsystemd on Ubuntu or systemd-devel on rpm based distro for journald support) endif BUILDTAGS_CROSS ?= containers_image_openpgp exclude_graphdriver_btrfs exclude_graphdriver_devicemapper exclude_graphdriver_overlay @@ -241,6 +241,7 @@ testunit: libpodimage ## Run unittest on the built image localunit: test/goecho/goecho varlink_generate ginkgo \ -r \ + $(TESTFLAGS) \ --skipPackage test/e2e,pkg/apparmor,test/endpoint \ --cover \ --covermode atomic \ @@ -248,13 +249,13 @@ localunit: test/goecho/goecho varlink_generate --succinct ginkgo: - ginkgo -v -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -nodes 3 -debug test/e2e/. + ginkgo -v $(TESTFLAGS) -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -nodes 3 -debug test/e2e/. ginkgo-remote: - ginkgo -v -tags "$(BUILDTAGS) remoteclient" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/. + ginkgo -v $(TESTFLAGS) -tags "$(BUILDTAGS) remoteclient" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/. endpoint: - ginkgo -v -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -debug test/endpoint/. + ginkgo -v $(TESTFLAGS) -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -debug test/endpoint/. localintegration: varlink_generate test-binaries ginkgo diff --git a/contrib/build_rpm.sh b/contrib/build_rpm.sh index e41763fa7..088d8b7a5 100755 --- a/contrib/build_rpm.sh +++ b/contrib/build_rpm.sh @@ -26,6 +26,7 @@ declare -a PKGS=(device-mapper-devel \ make \ rpm-build \ go-compilers-golang-compiler \ + systemd-devel \ ) if [[ $pkg_manager == *dnf ]]; then diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md index 6c8f239a6..fac8296ad 100644 --- a/docs/source/markdown/podman-build.1.md +++ b/docs/source/markdown/podman-build.1.md @@ -176,6 +176,10 @@ value can be entered. The password is entered without echo. Add a host device to the container. The format is `<device-on-host>[:<device-on-container>][:<permissions>]` (e.g. --device=/dev/sdc:/dev/xvdc:rwm) +Note: if the user only has access rights via a group then accessing the device +from inside a rootless container will fail. The `crun` runtime offers a +workaround for this by adding the option `--annotation io.crun.keep_original_groups=1`. + **--disable-compression, -D** Don't compress filesystem layers when building the image unless it is required diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index 82d2e8f6a..85aa81553 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -204,6 +204,10 @@ Specify the key sequence for detaching a container. Format is a single character Add a host device to the container. The format is `<device-on-host>[:<device-on-container>][:<permissions>]` (e.g. --device=/dev/sdc:/dev/xvdc:rwm) +Note: if the user only has access rights via a group then accessing the device +from inside a rootless container will fail. The `crun` runtime offers a +workaround for this by adding the option `--annotation io.crun.keep_original_groups=1`. + **--device-read-bps**=*path* Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb) diff --git a/docs/source/markdown/podman-info.1.md b/docs/source/markdown/podman-info.1.md index 9721755ef..b539f1d3c 100644 --- a/docs/source/markdown/podman-info.1.md +++ b/docs/source/markdown/podman-info.1.md @@ -53,13 +53,26 @@ host: os: linux uptime: 218h 49m 33.66s (Approximately 9.08 days) registries: - blocked: null - insecure: null - search: - - quay.io - - registry.fedoraproject.org - - docker.io - - registry.redhat.io + docker.io: + Blocked: true + Insecure: true + Location: docker.io + MirrorByDigestOnly: false + Mirrors: + - Insecure: true + Location: example2.io/example/ubi8-minimal + Prefix: docker.io + redhat.com: + Blocked: false + Insecure: false + Location: registry.access.redhat.com/ubi8 + MirrorByDigestOnly: true + Mirrors: + - Insecure: false + Location: example.io/example/ubi8-minimal + - Insecure: true + Location: example3.io/example/ubi8-minimal + Prefix: redhat.com store: ConfigFile: /etc/containers/storage.conf ContainerStore: diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index e1177cb34..e8744de35 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -210,6 +210,10 @@ Specify the key sequence for detaching a container. Format is a single character Add a host device to the container. The format is `<device-on-host>[:<device-on-container>][:<permissions>]` (e.g. --device=/dev/sdc:/dev/xvdc:rwm) +Note: if the user only has access rights via a group then accessing the device +from inside a rootless container will fail. The `crun` runtime offers a +workaround for this by adding the option `--annotation io.crun.keep_original_groups=1`. + **--device-read-bps**=*path* Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb) diff --git a/hack/systemd_tag.sh b/hack/systemd_tag.sh index c59cad559..19a7bf6a6 100755 --- a/hack/systemd_tag.sh +++ b/hack/systemd_tag.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash -if pkg-config --exists libsystemd; then - echo systemd +cc -E - > /dev/null 2> /dev/null << EOF +#include <systemd/sd-daemon.h> +EOF +if test $? -eq 0 ; then + echo systemd fi diff --git a/install.md b/install.md index 218994587..5771fff45 100644 --- a/install.md +++ b/install.md @@ -149,6 +149,12 @@ sudo apt-get install \ uidmap ``` +On openSUSE Leap 15.x and Tumbleweed: + +```bash +sudo zypper -n in libseccomp-devel libgpgme-devel +``` + On Manjaro (and maybe other Linux distributions): Make sure that the Linux kernel supports user namespaces: diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 1b0570998..6ec06943f 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -593,22 +593,68 @@ func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) (err error) // Get root file-system changes included in the checkpoint archive rootfsDiffPath := filepath.Join(c.bundlePath(), "rootfs-diff.tar") + deleteFilesList := filepath.Join(c.bundlePath(), "deleted.files") if !ignoreRootfs { - rootfsDiffFile, err := os.Create(rootfsDiffPath) - if err != nil { - return errors.Wrapf(err, "error creating root file-system diff file %q", rootfsDiffPath) - } - tarStream, err := c.runtime.GetDiffTarStream("", c.ID()) + // To correctly track deleted files, let's go through the output of 'podman diff' + tarFiles, err := c.runtime.GetDiff("", c.ID()) if err != nil { return errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath) } - _, err = io.Copy(rootfsDiffFile, tarStream) - if err != nil { - return errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath) + var rootfsIncludeFiles []string + var deletedFiles []string + + for _, file := range tarFiles { + if file.Kind == archive.ChangeAdd { + rootfsIncludeFiles = append(rootfsIncludeFiles, file.Path) + continue + } + if file.Kind == archive.ChangeDelete { + deletedFiles = append(deletedFiles, file.Path) + continue + } + fileName, err := os.Stat(file.Path) + if err != nil { + continue + } + if !fileName.IsDir() && file.Kind == archive.ChangeModify { + rootfsIncludeFiles = append(rootfsIncludeFiles, file.Path) + continue + } + } + + if len(rootfsIncludeFiles) > 0 { + rootfsTar, err := archive.TarWithOptions(c.state.Mountpoint, &archive.TarOptions{ + Compression: archive.Uncompressed, + IncludeSourceDir: true, + IncludeFiles: rootfsIncludeFiles, + }) + if err != nil { + return errors.Wrapf(err, "error exporting root file-system diff to %q", rootfsDiffPath) + } + rootfsDiffFile, err := os.Create(rootfsDiffPath) + if err != nil { + return errors.Wrapf(err, "error creating root file-system diff file %q", rootfsDiffPath) + } + defer rootfsDiffFile.Close() + _, err = io.Copy(rootfsDiffFile, rootfsTar) + if err != nil { + return err + } + + includeFiles = append(includeFiles, "rootfs-diff.tar") + } + + if len(deletedFiles) > 0 { + formatJSON, err := json.MarshalIndent(deletedFiles, "", " ") + if err != nil { + return errors.Wrapf(err, "error creating delete files list file %q", deleteFilesList) + } + if err := ioutil.WriteFile(deleteFilesList, formatJSON, 0600); err != nil { + return errors.Wrapf(err, "error creating delete files list file %q", deleteFilesList) + } + + includeFiles = append(includeFiles, "deleted.files") } - tarStream.Close() - rootfsDiffFile.Close() - includeFiles = append(includeFiles, "rootfs-diff.tar") } input, err := archive.TarWithOptions(c.bundlePath(), &archive.TarOptions{ @@ -637,6 +683,7 @@ func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) (err error) } os.Remove(rootfsDiffPath) + os.Remove(deleteFilesList) return nil } @@ -941,10 +988,35 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti if err != nil { return errors.Wrapf(err, "Failed to open root file-system diff file %s", rootfsDiffPath) } + defer rootfsDiffFile.Close() if err := c.runtime.ApplyDiffTarStream(c.ID(), rootfsDiffFile); err != nil { return errors.Wrapf(err, "Failed to apply root file-system diff file %s", rootfsDiffPath) } - rootfsDiffFile.Close() + } + deletedFilesPath := filepath.Join(c.bundlePath(), "deleted.files") + if _, err := os.Stat(deletedFilesPath); err == nil { + deletedFilesFile, err := os.Open(deletedFilesPath) + if err != nil { + return errors.Wrapf(err, "Failed to open deleted files file %s", deletedFilesPath) + } + defer deletedFilesFile.Close() + + var deletedFiles []string + deletedFilesJSON, err := ioutil.ReadAll(deletedFilesFile) + if err != nil { + return errors.Wrapf(err, "Failed to read deleted files file %s", deletedFilesPath) + } + if err := json.Unmarshal(deletedFilesJSON, &deletedFiles); err != nil { + return errors.Wrapf(err, "Failed to read deleted files file %s", deletedFilesPath) + } + for _, deleteFile := range deletedFiles { + // Using RemoveAll as deletedFiles, which is generated from 'podman diff' + // lists completely deleted directories as a single entry: 'D /root'. + err = os.RemoveAll(filepath.Join(c.state.Mountpoint, deleteFile)) + if err != nil { + return errors.Wrapf(err, "Failed to delete file %s from container %s during restore", deletedFilesPath, c.ID()) + } + } } } @@ -965,7 +1037,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti if err != nil { logrus.Debugf("Non-fatal: removal of checkpoint directory (%s) failed: %v", c.CheckpointPath(), err) } - cleanup := [...]string{"restore.log", "dump.log", "stats-dump", "stats-restore", "network.status", "rootfs-diff.tar"} + cleanup := [...]string{"restore.log", "dump.log", "stats-dump", "stats-restore", "network.status", "rootfs-diff.tar", "deleted.files"} for _, del := range cleanup { file := filepath.Join(c.bundlePath(), del) err = os.Remove(file) diff --git a/libpod/diff.go b/libpod/diff.go index 925bda927..baa4d6ad7 100644 --- a/libpod/diff.go +++ b/libpod/diff.go @@ -1,7 +1,6 @@ package libpod import ( - "archive/tar" "io" "github.com/containers/libpod/libpod/layers" @@ -47,49 +46,6 @@ func (r *Runtime) GetDiff(from, to string) ([]archive.Change, error) { return rchanges, err } -// skipFileInTarAchive is an archive.TarModifierFunc function -// which tells archive.ReplaceFileTarWrapper to skip files -// from the tarstream -func skipFileInTarAchive(path string, header *tar.Header, content io.Reader) (*tar.Header, []byte, error) { - return nil, nil, nil -} - -// GetDiffTarStream returns the differences between the two images, layers, or containers. -// It is the same functionality as GetDiff() except that it returns a tarstream -func (r *Runtime) GetDiffTarStream(from, to string) (io.ReadCloser, error) { - toLayer, err := r.getLayerID(to) - if err != nil { - return nil, err - } - fromLayer := "" - if from != "" { - fromLayer, err = r.getLayerID(from) - if err != nil { - return nil, err - } - } - rc, err := r.store.Diff(fromLayer, toLayer, nil) - if err != nil { - return nil, err - } - - // Skip files in the tar archive which are listed - // in containerMounts map. Just as in the GetDiff() - // function from above - filterMap := make(map[string]archive.TarModifierFunc) - for key := range containerMounts { - filterMap[key[1:]] = skipFileInTarAchive - // In the tarstream directories always include a trailing '/'. - // For simplicity this duplicates every entry from - // containerMounts with a trailing '/', as containerMounts - // does not use trailing '/' for directories. - filterMap[key[1:]+"/"] = skipFileInTarAchive - } - - filteredTarStream := archive.ReplaceFileTarWrapper(rc, filterMap) - return filteredTarStream, nil -} - // ApplyDiffTarStream applies the changes stored in 'diff' to the layer 'to' func (r *Runtime) ApplyDiffTarStream(to string, diff io.Reader) error { toLayer, err := r.getLayerID(to) diff --git a/libpod/runtime.go b/libpod/runtime.go index 3873079ce..001d850b0 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -691,24 +691,22 @@ func (r *Runtime) Info() ([]define.InfoData, error) { } info = append(info, define.InfoData{Type: "store", Data: storeInfo}) - reg, err := sysreg.GetRegistries() - if err != nil { - return nil, errors.Wrapf(err, "error getting registries") - } registries := make(map[string]interface{}) - registries["search"] = reg - - ireg, err := sysreg.GetInsecureRegistries() + data, err := sysreg.GetRegistriesData() if err != nil { return nil, errors.Wrapf(err, "error getting registries") } - registries["insecure"] = ireg - - breg, err := sysreg.GetBlockedRegistries() + for _, reg := range data { + registries[reg.Prefix] = reg + } + regs, err := sysreg.GetRegistries() if err != nil { return nil, errors.Wrapf(err, "error getting registries") } - registries["blocked"] = breg + if len(regs) > 0 { + registries["search"] = regs + } + info = append(info, define.InfoData{Type: "registries", Data: registries}) return info, nil } diff --git a/pkg/adapter/checkpoint_restore.go b/pkg/adapter/checkpoint_restore.go index 15f9e8105..7f80b782a 100644 --- a/pkg/adapter/checkpoint_restore.go +++ b/pkg/adapter/checkpoint_restore.go @@ -60,6 +60,7 @@ func crImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, input stri "ctr.log", "rootfs-diff.tar", "network.status", + "deleted.files", }, } dir, err := ioutil.TempDir("", "checkpoint") diff --git a/pkg/registries/registries.go b/pkg/registries/registries.go index 9643c947f..ba7de7cf9 100644 --- a/pkg/registries/registries.go +++ b/pkg/registries/registries.go @@ -34,7 +34,8 @@ func SystemRegistriesConfPath() string { return "" } -func getRegistries() ([]sysregistriesv2.Registry, error) { +// GetRegistriesData obtains the list of registries +func GetRegistriesData() ([]sysregistriesv2.Registry, error) { registries, err := sysregistriesv2.GetRegistries(&types.SystemContext{SystemRegistriesConfPath: SystemRegistriesConfPath()}) if err != nil { return nil, errors.Wrapf(err, "unable to parse the registries.conf file") @@ -50,7 +51,7 @@ func GetRegistries() ([]string, error) { // GetBlockedRegistries obtains the list of blocked registries defined in the global registries file. func GetBlockedRegistries() ([]string, error) { var blockedRegistries []string - registries, err := getRegistries() + registries, err := GetRegistriesData() if err != nil { return nil, err } @@ -65,7 +66,7 @@ func GetBlockedRegistries() ([]string, error) { // GetInsecureRegistries obtains the list of insecure registries from the global registration file. func GetInsecureRegistries() ([]string, error) { var insecureRegistries []string - registries, err := getRegistries() + registries, err := GetRegistriesData() if err != nil { return nil, err } diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index f208a4cf0..237223283 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -439,6 +439,18 @@ var _ = Describe("Podman checkpoint", func() { result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) + result = podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "rm /etc/motd"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + + result = podmanTest.Podman([]string{"diff", "-l"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(result.OutputToString()).To(ContainSubstring("C /etc")) + Expect(result.OutputToString()).To(ContainSubstring("A /test.output")) + Expect(result.OutputToString()).To(ContainSubstring("D /etc/motd")) + Expect(len(result.OutputToStringArray())).To(Equal(3)) + // Checkpoint the container result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName}) result.WaitWithDefaultTimeout() @@ -462,6 +474,14 @@ var _ = Describe("Podman checkpoint", func() { Expect(result.ExitCode()).To(Equal(0)) Expect(result.OutputToString()).To(ContainSubstring("test" + cid + "test")) + result = podmanTest.Podman([]string{"diff", "-l"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(result.OutputToString()).To(ContainSubstring("C /etc")) + Expect(result.OutputToString()).To(ContainSubstring("A /test.output")) + Expect(result.OutputToString()).To(ContainSubstring("D /etc/motd")) + Expect(len(result.OutputToStringArray())).To(Equal(3)) + // Remove exported checkpoint os.Remove(fileName) }) diff --git a/test/e2e/e2e.coverprofile b/test/e2e/e2e.coverprofile deleted file mode 100644 index d413679ea..000000000 --- a/test/e2e/e2e.coverprofile +++ /dev/null @@ -1,11 +0,0 @@ -mode: atomic -github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:14.46,21.20 2 3 -github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:32.2,32.19 1 3 -github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:39.2,39.53 1 3 -github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:66.2,66.52 1 3 -github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:21.20,23.17 2 6 -github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:26.3,29.36 4 6 -github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:23.17,25.4 1 0 -github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:32.19,37.3 3 6 -github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:39.53,64.3 20 3 -github.com/containers/libpod/test/e2e/pod_pod_namespaces.go:66.52,91.3 20 3
\ No newline at end of file diff --git a/test/system/010-images.bats b/test/system/010-images.bats index 543876509..66ef53590 100644 --- a/test/system/010-images.bats +++ b/test/system/010-images.bats @@ -45,18 +45,33 @@ size | [0-9]\\\+ } @test "podman images - history output" { - run_podman images --format json - actual=$(echo $output | jq -r '.[0].history | length') - is "$actual" "0" - - run_podman tag $PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG test-image - run_podman images --format json - actual=$(echo $output | jq -r '.[1].history | length') - is "$actual" "0" - actual=$(echo $output | jq -r '.[0].history | length') - is "$actual" "1" - actual=$(echo $output | jq -r '.[0].history[0]') - is "$actual" "$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG" + # podman history is persistent: it permanently alters our base image. + # Create a dummy image here so we leave our setup as we found it. + run_podman run --name my-container $IMAGE true + run_podman commit my-container my-test-image + + run_podman images my-test-image --format '{{ .History }}' + is "$output" "" "Image has empty history to begin with" + + # Generate two randomish tags; 'tr' because they must be all lower-case + rand_name1="test-image-history-$(random_string 10 | tr A-Z a-z)" + rand_name2="test-image-history-$(random_string 10 | tr A-Z a-z)" + + # Tag once, rmi, and make sure the tag name appears in history + run_podman tag my-test-image $rand_name1 + run_podman rmi $rand_name1 + run_podman images my-test-image --format '{{ .History }}' + is "$output" "localhost/${rand_name1}:latest" "image history after one tag" + + # Repeat with second tag. Now both tags should be in history + run_podman tag my-test-image $rand_name2 + run_podman rmi $rand_name2 + run_podman images my-test-image --format '{{ .History }}' + is "$output" "localhost/${rand_name2}:latest, localhost/${rand_name1}:latest" \ + "image history after two tags" + + run_podman rmi my-test-image + run_podman rm my-container } # vim: filetype=sh diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 8c061d2c9..940f3f426 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -36,7 +36,7 @@ function basic_setup() { if [ "$1" == "$PODMAN_TEST_IMAGE_FQN" ]; then found_needed_image=1 else - echo "# setup(): removing stray images" >&3 + echo "# setup(): removing stray images $1 $2" >&3 run_podman rmi --force "$1" >/dev/null 2>&1 || true run_podman rmi --force "$2" >/dev/null 2>&1 || true fi diff --git a/troubleshooting.md b/troubleshooting.md index 432c0e32b..d122983d7 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -468,4 +468,20 @@ $ podman unshare cat /proc/self/uid_map 1 100000 65536 ``` -Reference [subuid](http://man7.org/linux/man-pages/man5/subuid.5.html) and [subgid](http://man7.org/linux/man-pages/man5/subgid.5.html) man pages for more detail.
\ No newline at end of file +Reference [subuid](http://man7.org/linux/man-pages/man5/subuid.5.html) and [subgid](http://man7.org/linux/man-pages/man5/subgid.5.html) man pages for more detail. + +### 20) Passed-in device can't be accessed in rootless container + +As a non-root user you have group access rights to a device that you want to +pass into a rootless container with `--device=...`. + +#### Symptom + +Any access inside the container is rejected with "Permission denied". + +#### Solution + +The runtime uses `setgroups(2)` hence the process looses all additional groups +the non-root user has. If you use the `crun` runtime, 0.10.4 or newer, +then you can enable a workaround by adding `--annotation io.crun.keep_original_groups=1` +to the `podman` command line. |