diff options
52 files changed, 620 insertions, 557 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 514889969..fe09ea988 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -73,6 +73,7 @@ env: #### Default to NOT operating in any special-case testing mode #### SPECIALMODE: "none" # don't do anything special + TEST_REMOTE_CLIENT: false # don't test remote client by default #### #### Credentials and other secret-sauces, decrypted at runtime when authorized. @@ -122,6 +123,9 @@ gating_task: timeout_in: 20m + networking_script: # Don't bother going further if something is down + - 'while read host port; do nc -zv -w 13 $host $port || exit 1; done < ${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/required_host_ports.txt' + gate_script: # N/B: entrypoint.sh resets $GOSRC (same as make clean) - '/usr/local/bin/entrypoint.sh install.tools |& ${TIMESTAMP}' @@ -266,6 +270,11 @@ testing_task: - "vendor" - "build_each_commit" + env: + matrix: + TEST_REMOTE_CLIENT: true + TEST_REMOTE_CLIENT: false + gce_instance: image_project: "libpod-218412" zone: "us-central1-a" # Required by Cirrus for the time being @@ -292,12 +301,14 @@ testing_task: setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' unit_test_script: '$SCRIPT_BASE/unit_test.sh |& ${TIMESTAMP}' integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}' + ginkgo_node_logs_script: 'cat $CIRRUS_WORKING_DIR/test/e2e/ginkgo-node-*.log || echo "Ginkgo node logs not found"' audit_log_script: 'cat /var/log/audit/audit.log || cat /var/log/kern.log' journalctl_b_script: 'journalctl -b' on_failure: failed_master_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_master_failure.sh' # Job has already failed, don't fail again and miss collecting data + failed_ginkgo_node_logs_script: 'cat $CIRRUS_WORKING_DIR/test/e2e/ginkgo-node-*.log || echo "Ginkgo node logs not found"' failed_audit_log_script: 'cat /var/log/audit/audit.log || cat /var/log/kern.log || echo "Uh oh, cat audit.log failed"' failed_journalctl_b_script: 'journalctl -b || echo "Uh oh, journalctl -b failed"' diff --git a/.copr/Makefile b/.copr/Makefile index 05d9eb592..71142920b 100644 --- a/.copr/Makefile +++ b/.copr/Makefile @@ -16,4 +16,4 @@ build_binary: clean: rm -fr rpms - rm -fr cri-o + rm -fr conmon diff --git a/.copr/prepare.sh b/.copr/prepare.sh index 1ad29da36..a40e2aadb 100644 --- a/.copr/prepare.sh +++ b/.copr/prepare.sh @@ -28,5 +28,5 @@ fi mkdir build/ git archive --prefix "libpod-${COMMIT_SHORT}/" --format "tar.gz" HEAD -o "build/libpod-${COMMIT_SHORT}.tar.gz" -git clone https://github.com/kubernetes-incubator/cri-o -cd cri-o && git checkout 4cd5a7c60349be0678d9f1b0657683324c1a2726 && git archive --prefix "crio/" --format "tar.gz" HEAD -o "../build/crio.tar.gz" +git clone https://github.com/containers/conmon +cd conmon && git checkout f02c053eb37010fc76d1e2966de7f2cb9f969ef2 && git archive --prefix "conmon/" --format "tar.gz" HEAD -o "../build/conmon.tar.gz" diff --git a/Dockerfile b/Dockerfile index 767e64570..f3afd5e25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,13 +56,13 @@ RUN set -x \ && rm -rf "$GOPATH" # Install conmon -ENV CRIO_COMMIT 7a283c391abb7bd25086a8ff91dbb36ebdd24466 +ENV CONMON_COMMIT f02c053eb37010fc76d1e2966de7f2cb9f969ef2 RUN set -x \ && export GOPATH="$(mktemp -d)" \ - && git clone https://github.com/kubernetes-sigs/cri-o.git "$GOPATH/src/github.com/kubernetes-sigs/cri-o.git" \ - && cd "$GOPATH/src/github.com/kubernetes-sigs/cri-o.git" \ + && git clone https://github.com/containers/conmon.git "$GOPATH/src/github.com/containers/conmon.git" \ + && cd "$GOPATH/src/github.com/containers/conmon.git" \ && git fetch origin --tags \ - && git checkout -q "$CRIO_COMMIT" \ + && git checkout -q "$CONMON_COMMIT" \ && make \ && install -D -m 755 bin/conmon /usr/libexec/podman/conmon \ && rm -rf "$GOPATH" diff --git a/Dockerfile.centos b/Dockerfile.centos index 605dc9df4..47f7182b6 100644 --- a/Dockerfile.centos +++ b/Dockerfile.centos @@ -64,15 +64,14 @@ RUN set -x \ && install -D -m 755 "$GOPATH"/bin/easyjson /usr/bin/ # Install conmon -ENV CRIO_COMMIT 7a283c391abb7bd25086a8ff91dbb36ebdd24466 +ENV CONMON_COMMIT f02c053eb37010fc76d1e2966de7f2cb9f969ef2 RUN set -x \ && export GOPATH="$(mktemp -d)" \ - && git clone https://github.com/kubernetes-sigs/cri-o.git "$GOPATH/src/github.com/kubernetes-sigs/cri-o.git" \ - && cd "$GOPATH/src/github.com/kubernetes-sigs/cri-o.git" \ + && git clone https://github.com/containers/conmon.git "$GOPATH/src/github.com/containers/conmon.git" \ + && cd "$GOPATH/src/github.com/containers/conmon.git" \ && git fetch origin --tags \ - && git checkout -q "$CRIO_COMMIT" \ + && git checkout -q "$CONMON_COMMIT" \ && make \ - && make bin/conmon \ && install -D -m 755 bin/conmon /usr/libexec/podman/conmon \ && rm -rf "$GOPATH" diff --git a/Dockerfile.fedora b/Dockerfile.fedora index d4bcc11ea..290fe3f82 100644 --- a/Dockerfile.fedora +++ b/Dockerfile.fedora @@ -68,15 +68,14 @@ RUN set -x \ && install -D -m 755 "$GOPATH"/bin/easyjson /usr/bin/ # Install conmon -ENV CRIO_COMMIT 7a283c391abb7bd25086a8ff91dbb36ebdd24466 +ENV CONMON_COMMIT f02c053eb37010fc76d1e2966de7f2cb9f969ef2 RUN set -x \ && export GOPATH="$(mktemp -d)" \ - && git clone https://github.com/kubernetes-sigs/cri-o.git "$GOPATH/src/github.com/kubernetes-sigs/cri-o.git" \ - && cd "$GOPATH/src/github.com/kubernetes-sigs/cri-o.git" \ + && git clone https://github.com/containers/conmon.git "$GOPATH/src/github.com/containers/conmon.git" \ + && cd "$GOPATH/src/github.com/containers/conmon.git" \ && git fetch origin --tags \ - && git checkout -q "$CRIO_COMMIT" \ + && git checkout -q "$CONMON_COMMIT" \ && make \ - && make bin/conmon \ && install -D -m 755 bin/conmon /usr/libexec/podman/conmon \ && rm -rf "$GOPATH" @@ -1,6 +1,6 @@ GO ?= go DESTDIR ?= / -EPOCH_TEST_COMMIT ?= a9fc570dd844bf1ebd1f106f1b8091882b4a2b29 +EPOCH_TEST_COMMIT ?= 8161802f7df857e0850f842261079c83290f9891 HEAD ?= HEAD CHANGELOG_BASE ?= HEAD~ CHANGELOG_TARGET ?= HEAD @@ -207,12 +207,14 @@ localunit: test/goecho/goecho varlink_generate ./contrib/cirrus/lib.sh.t ginkgo: - ginkgo -v -tags "$(BUILDTAGS)" $(GINKGOTIMEOUT) -cover -flakeAttempts 3 -progress -trace -noColor -nodes 3 test/e2e/. + ginkgo -v -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/. -localintegration: varlink_generate test-binaries ginkgo ginkgo-remote +localintegration: varlink_generate test-binaries ginkgo + +remoteintegration: varlink_generate test-binaries ginkgo-remote localsystem: .install.ginkgo ginkgo -v -noColor test/system/ @@ -262,7 +264,9 @@ install: .gopathok install.bin install.man install.cni install.systemd ## Insta install.bin: install ${SELINUXOPT} -d -m 755 $(BINDIR) install ${SELINUXOPT} -m 755 bin/podman $(BINDIR)/podman + install ${SELINUXOPT} -m 755 bin/podman-remote $(BINDIR)/podman-remote test -z "${SELINUXOPT}" || chcon --verbose --reference=$(BINDIR)/podman bin/podman + test -z "${SELINUXOPT}" || chcon --verbose --reference=$(BINDIR)/podman bin/podman-remote install.man: docs install ${SELINUXOPT} -d -m 755 $(MANDIR)/man1 @@ -5,12 +5,12 @@ Libpod provides a library for applications looking to use the Container Pod concept, popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`. Podman manages pods, containers, container images, and container volumes. -* [Latest Version: 1.2.0](https://github.com/containers/libpod/releases/latest) +* [Latest Version: 1.3.1](https://github.com/containers/libpod/releases/latest) * [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master) ## Overview and scope -At a high level, the scope of libpod and podman is the following: +At a high level, the scope of libpod and Podman is the following: * Support multiple image formats including the OCI and Docker image formats. * Support for multiple means to download images including trust & image verification. @@ -44,7 +44,7 @@ Any recent Podman release should be able to run rootless without any additional * Specializing in signing and pushing images to various storage backends. See [Skopeo](https://github.com/containers/skopeo/) for those tasks. * Container runtimes daemons for working with the Kubernetes CRI interface. - [CRI-O](https://github.com/kubernetes-sigs/cri-o) specializes in that. + [CRI-O](https://github.com/cri-o/cri-o) specializes in that. * Supporting `docker-compose`. We believe that Kubernetes is the defacto standard for composing Pods and for orchestrating containers, making Kubernetes YAML a defacto standard file format. Hence, Podman allows the @@ -67,7 +67,7 @@ The plan is to use OCI projects and best of breed libraries for different aspect - Storage: Container and image storage is managed by [containers/storage](https://github.com/containers/storage) - Networking: Networking support through use of [CNI](https://github.com/containernetworking/cni) - Builds: Builds are supported via [Buildah](https://github.com/containers/buildah). -- Conmon: [Conmon](https://github.com/kubernetes-sigs/cri-o) is a tool for monitoring OCI runtimes. It is part of the CRI-O package +- Conmon: [Conmon](https://github.com/containers/conmon) is a tool for monitoring OCI runtimes. ## Podman Information for Developers diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 499f46317..5eb85d0bc 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,8 +1,29 @@ # Release Notes +## 1.3.1 +### Features +- The `podman cp` command can now read input redirected to `STDIN`, and output to `STDOUT` instead of a file, using `-` instead of an argument. +- The Podman remote client now displays version information from both the client and server in `podman version` +- The `podman unshare` command has been added, allowing easy entry into the user namespace set up by rootless Podman (allowing the removal of files created by rootless Podman, among other things) + +### Bugfixes +- Fixed a bug where Podman containers with the `--rm` flag were removing created volumes when they were automatically removed ([#3071](https://github.com/containers/libpod/issues/3071)) +- Fixed a bug where container and pod locks were incorrectly marked as released after a system reboot, causing errors on container and pod removal ([#2900](https://github.com/containers/libpod/issues/2900)) +- Fixed a bug where Podman pods could not be removed if any container in the pod encountered an error during removal ([#3088](https://github.com/containers/libpod/issues/3088)) +- Fixed a bug where Podman pods run with the `cgroupfs` CGroup driver would encounter a race condition during removal, potentially failing to remove the pod CGroup +- Fixed a bug where the `podman container checkpoint` and `podman container restore` commands were not visible in the remote client +- Fixed a bug where `podman remote ps --ns` would not print the container's namespaces ([#2938](https://github.com/containers/libpod/issues/2938)) +- Fixed a bug where removing stopped containers with healthchecks could cause an error +- Fixed a bug where the default `libpod.conf` file was causing parsing errors ([#3095](https://github.com/containers/libpod/issues/3095)) +- Fixed a bug where pod locks were not being freed when pods were removed, potentially leading to lock exhaustion +- Fixed a bug where 'podman run' with SD_NOTIFY set could, on short-running containers, create an inconsistent state rendering the container unusable + +### Misc +- The remote Podman client now uses the Varlink bridge to establish remote connections by default + ## 1.3.0 ### Features -- Podman now supports container restart policies! The `--restart-policy` flag on `podman create` and `podman run` allows containers to be restarted after they exit. Please note that Podman cannot restart containers after a system reboot - for that, see our next feature +- Podman now supports container restart policies! The `--restart` flag on `podman create` and `podman run` allows containers to be restarted after they exit. Please note that Podman cannot restart containers after a system reboot - for that, see our next feature - Podman `podman generate systemd` command was added to generate systemd unit files for managing Podman containers - The `podman runlabel` command now allows a `$GLOBAL_OPTS` variable, which will be populated by global options passed to the `podman runlabel` command, allowing custom storage configurations to be passed into containers run with `runlabel` ([#2399](https://github.com/containers/libpod/issues/2399)) - The `podman play kube` command now allows `File` and `FileOrCreate` volumes diff --git a/changelog.txt b/changelog.txt index c72117d7f..ec0a62f26 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,48 @@ +- Changelog for v1.3.1 (2019-05-16) + * More release notes + * Add unshare to podman + * Release notes for 1.3.1 + * Kill os.Exit() in tests, replace with asserts + * Minor capitalization fix in Readme + * Add debug mode to Ginkgo, collect debug logs in Cirrus + * set default event logger based on build tags + * Add VarlinkCall.RequiresUpgrade() type and method + * Ensure that start() in StartAndAttach() is locked + * When removing pods, free their locks + * network: raise a clearer error when using CNI + * Fix libpod.conf option ordering + * split remote tests from distro tests + * varlink: fix usage message, URI is now optional + * Update containerd/cgroups to 4994991857f9b0ae + * healthcheck benign error + * Add `systemd` build tag + * podman: fix events help string + * When removing a pod with CGroupfs, set pids limit to 0 + * Add fix for an issue breaking our CI + * Use standard remove functions for removing pod ctrs + * implement cp reads tar file from stdin/stdout + * Add information when running podman version on client + * add varlink bridge + * Add negative command-line test + * Preserve errors returned by removing pods + * Improve robustness of pod removal + * enable integration tests for remote-client + * fix podman-remote ps --ns + * podman-run|create man updates + * Update installation instructions + * remote-podman checkpoint and restore add to container submenu + * Remove tests for deprecated podman-refresh command + * When refreshing after a reboot, force lock allocation + * Do not remove volumes when --rm removes a container + * add unit tests for generate systemd + * Bump gitvalidation epoch + * Bump to v1.3.1-dev + * Upgrade to latest criu and selinux-policy + * Only run checkpoint/restore tests on Fedora >= 29 + * Fix API.md + * Cirrus: Add missing task dependencies + * Cirrus: Add check for make varlink_api_generate + - Changelog for v1.3.0 (2019-05-06) * Update release notes for 1.3.0 release * Bump to Buildah v1.8.2 diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index 3a409f503..2ac465b9d 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -20,6 +20,7 @@ func getMainCommands() []*cobra.Command { _refreshCommand, _searchCommand, _statsCommand, + _unshareCommand, } if len(_varlinkCommand.Use) > 0 { diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go index b533dc056..b8d77602d 100644 --- a/cmd/podman/libpodruntime/runtime.go +++ b/cmd/podman/libpodruntime/runtime.go @@ -107,7 +107,11 @@ func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber bool, if c.Flags().Changed("cgroup-manager") { options = append(options, libpod.WithCgroupManager(c.GlobalFlags.CGroupManager)) } else { - if rootless.IsRootless() { + unified, err := util.IsCgroup2UnifiedMode() + if err != nil { + return nil, err + } + if rootless.IsRootless() && !unified { options = append(options, libpod.WithCgroupManager("cgroupfs")) } } diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go index c426817de..e87b88992 100644 --- a/cmd/podman/runlabel.go +++ b/cmd/podman/runlabel.go @@ -152,7 +152,7 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error { return err } if !c.Quiet { - fmt.Printf("command: %s\n", strings.Join(cmd, " ")) + fmt.Printf("command: %s\n", strings.Join(append([]string{os.Args[0]}, cmd[1:]...), " ")) if c.Display { return nil } diff --git a/cmd/podman/shared/create_cli.go b/cmd/podman/shared/create_cli.go index f731e8db5..7f158b09a 100644 --- a/cmd/podman/shared/create_cli.go +++ b/cmd/podman/shared/create_cli.go @@ -7,6 +7,7 @@ import ( "github.com/containers/libpod/cmd/podman/shared/parse" cc "github.com/containers/libpod/pkg/spec" "github.com/containers/libpod/pkg/sysinfo" + "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -76,6 +77,12 @@ func addWarning(warnings []string, msg string) []string { func verifyContainerResources(config *cc.CreateConfig, update bool) ([]string, error) { warnings := []string{} + + cgroup2, err := util.IsCgroup2UnifiedMode() + if err != nil || cgroup2 { + return warnings, err + } + sysInfo := sysinfo.New(true) // memory subsystem checks and adjustments diff --git a/cmd/podman/unshare.go b/cmd/podman/unshare.go new file mode 100644 index 000000000..1db647dba --- /dev/null +++ b/cmd/podman/unshare.go @@ -0,0 +1,54 @@ +// +build linux + +package main + +import ( + "os" + "os/exec" + + "github.com/containers/buildah/pkg/unshare" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + unshareDescription = "Runs a command in a modified user namespace." + _unshareCommand = &cobra.Command{ + Use: "unshare [flags] [COMMAND [ARG]]", + Short: "Run a command in a modified user namespace", + Long: unshareDescription, + RunE: unshareCmd, + Example: `podman unshare id + podman unshare cat /proc/self/uid_map, + podman unshare podman-script.sh`, + } +) + +func init() { + _unshareCommand.SetUsageTemplate(UsageTemplate()) + flags := _unshareCommand.Flags() + flags.SetInterspersed(false) +} + +// unshareCmd execs whatever using the ID mappings that we want to use for ourselves +func unshareCmd(c *cobra.Command, args []string) error { + if isRootless := unshare.IsRootless(); !isRootless { + return errors.Errorf("please use unshare with rootless") + } + // exec the specified command, if there is one + if len(args) < 1 { + // try to exec the shell, if one's set + shell, shellSet := os.LookupEnv("SHELL") + if !shellSet { + return errors.Errorf("no command specified and no $SHELL specified") + } + args = []string{shell} + } + cmd := exec.Command(args[0], args[1:]...) + cmd.Env = unshare.RootlessEnv() + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + unshare.ExecRunnable(cmd) + return nil +} diff --git a/cmd/podman/version.go b/cmd/podman/version.go index 439a1cca6..52a518db8 100644 --- a/cmd/podman/version.go +++ b/cmd/podman/version.go @@ -70,7 +70,7 @@ func versionCmd(c *cliconfig.VersionValues) error { if remote { fmt.Fprintf(w, "\nService:\n") - runtime, err := adapter.GetRuntime(getContext(), nil) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/commands.md b/commands.md index e6c211254..d3ceca9dc 100644 --- a/commands.md +++ b/commands.md @@ -4,85 +4,86 @@ ## Podman Commands -Command | Description | Demo | Script -:----------------------------------------------------------------------- | :------------------------------------------------------------------------- | :-------------------------------------------------------------------------- | :-------------------------------------------------------------------------- -[podman(1)](/docs/podman.1.md) | Simple management tool for pods and images | -[podman-attach(1)](/docs/podman-attach.1.md) | Attach to a running container | -[podman-build(1)](/docs/podman-build.1.md) | Build an image using instructions from Dockerfiles | -[podman-commit(1)](/docs/podman-commit.1.md) | Create new image based on the changed container | -[podman-container(1)](/docs/podman-container.1.md) | Manage Containers | -[podman-container-checkpoint(1)](/docs/podman-container-checkpoint.1.md) | Checkpoints one or more running containers | -[podman-container-cleanup(1)](/docs/podman-container-cleanup.1.md) | Cleanup Container storage and networks | -[podman-container-exists(1)](/docs/podman-container-exists.1.md) | Check if an container exists in local storage | -[podman-container-prune(1)](/docs/podman-container-prune.1.md) | Remove all stopped containers | -[podman-container-refresh(1)](/docs/podman-container-refresh.1.md) | Refresh all containers state in database | -[podman-container-restore(1)](/docs/podman-container-restore.1.md) | Restores one or more running containers | -[podman-container-runlabel(1)](/docs/podman-container-runlabel.1.md) | Execute Image Label Method | -[podman-cp(1)](/docs/podman-cp.1.md) | Copy files/folders between a container and the local filesystem | -[podman-create(1)](/docs/podman-create.1.md) | Create a new container | -[podman-diff(1)](/docs/podman-diff.1.md) | Inspect changes on a container or image's filesystem | -[podman-events(1)](/docs/podman-events.1.md) | Monitor Podman events | -[podman-exec(1)](/docs/podman-exec.1.md) | Execute a command in a running container | -[podman-export(1)](/docs/podman-export.1.md) | Export container's filesystem contents as a tar archive | -[podman-generate(1)](/docs/podman-generate.1.md) | Generate structured output based on Podman containers and pods | -[podman-generate-kube(1)](/docs/podman-generate-kube.1.md) | Generate Kubernetes YAML based on a container or Pod | -[podman-generate-systemd(1)](/docs/podman-generate-systemd.1.md) | Generate a Systemd unit file for a container | -[podman-history(1)](/docs/podman-history.1.md) | Shows the history of an image | -[podman-image(1)](/docs/podman-image.1.md) | Manage Images | -[podman-image-exists(1)](/docs/podman-image-exists.1.md) | Check if an image exists in local storage | -[podman-image-prune(1)](/docs/podman-image-prune.1.md) | Remove all unused images | -[podman-image-sign(1)](/docs/podman-image-sign.1.md) | Create a signature for an image | -[podman-image-trust(1)](/docs/podman-image-trust.1.md) | Manage container registry image trust policy | -[podman-images(1)](/docs/podman-images.1.md) | List images in local storage | [![...](/docs/play.png)](https://podman.io/asciinema/podman/images/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_images.sh) -[podman-import(1)](/docs/podman-import.1.md) | Import a tarball and save it as a filesystem image | -[podman-info(1)](/docs/podman-info.1.md) | Display system information | -[podman-init(1)](/docs/podman-init.1.md) | Initialize a container | -[podman-inspect(1)](/docs/podman-inspect.1.md) | Display the configuration of a container or image | [![...](/docs/play.png)](https://asciinema.org/a/133418) -[podman-kill(1)](/docs/podman-kill.1.md) | Kill the main process in one or more running containers | -[podman-load(1)](/docs/podman-load.1.md) | Load an image from a container image archive | -[podman-login(1)](/docs/podman-login.1.md) | Login to a container registry | -[podman-logout(1)](/docs/podman-logout.1.md) | Logout of a container registry | -[podman-logs(1)](/docs/podman-logs.1.md) | Display the logs of a container | -[podman-mount(1)](/docs/podman-mount.1.md) | Mount a working container's root filesystem | -[podman-pause(1)](/docs/podman-pause.1.md) | Pause one or more running containers | [![...](/docs/play.png)](https://asciinema.org/a/141292) -[podman-play(1)](/docs/podman-play.1.md) | Play pods and containers based on a structured input file | -[podman-pod(1)](/docs/podman-pod.1.md) | Simple management tool for groups of containers, called pods | -[podman-pod-create(1)](/docs/podman-pod-create.1.md) | Create a new pod | -[podman-pod-inspect(1)](/docs/podman-pod-inspect.1.md) | Inspect a pod | -[podman-pod-kill(1)](podman-pod-kill.1.md) | Kill the main process of each container in pod. | -[podman-pod-ps(1)](/docs/podman-pod-ps.1.md) | List the pods on the system | -[podman-pod-pause(1)](podman-pod-pause.1.md) | Pause one or more pods. | -[podman-pod-restart](/docs/podman-pod-restart.1.md) | Restart one or more pods | -[podman-pod-rm(1)](/docs/podman-pod-rm.1.md) | Remove one or more pods | -[podman-pod-start(1)](/docs/podman-pod-start.1.md) | Start one or more pods | -[podman-pod-stats(1)](/docs/podman-pod-stats.1.md) | Display a live stream of one or more pods' resource usage statistics | | | -[podman-pod-stop(1)](/docs/podman-pod-stop.1.md) | Stop one or more pods | -[podman-pod-top(1)](/docs/podman-pod-top.1.md) | Display the running processes of a pod | -[podman-pod-unpause(1)](podman-pod-unpause.1.md) | Unpause one or more pods. | -[podman-port(1)](/docs/podman-port.1.md) | List port mappings for running containers | -[podman-ps(1)](/docs/podman-ps.1.md) | Prints out information about containers | -[podman-pull(1)](/docs/podman-pull.1.md) | Pull an image from a registry | -[podman-push(1)](/docs/podman-push.1.md) | Push an image to a specified destination | [![...](/docs/play.png)](https://asciinema.org/a/133276) -[podman-restart](/docs/podman-restart.1.md) | Restarts one or more containers | [![...](/docs/play.png)](https://asciinema.org/a/jiqxJAxcVXw604xdzMLTkQvHM) -[podman-rm(1)](/docs/podman-rm.1.md) | Removes one or more containers | -[podman-rmi(1)](/docs/podman-rmi.1.md) | Removes one or more images | -[podman-run(1)](/docs/podman-run.1.md) | Run a command in a container | -[podman-save(1)](/docs/podman-save.1.md) | Saves an image to an archive | -[podman-search(1)](/docs/podman-search.1.md) | Search a registry for an image | -[podman-start(1)](/docs/podman-start.1.md) | Starts one or more containers | -[podman-stats(1)](/docs/podman-stats.1.md) | Display a live stream of one or more containers' resource usage statistics | -[podman-stop(1)](/docs/podman-stop.1.md) | Stops one or more running containers | -[podman-system(1)](/docs/podman-system.1.md) | Manage podman | -[podman-tag(1)](/docs/podman-tag.1.md) | Add an additional name to a local image | [![...](/docs/play.png)](https://asciinema.org/a/133803) -[podman-top(1)](/docs/podman-top.1.md) | Display the running processes of a container | -[podman-umount(1)](/docs/podman-umount.1.md) | Unmount a working container's root filesystem | -[podman-unpause(1)](/docs/podman-unpause.1.md) | Unpause one or more running containers | [![...](/docs/play.png)](https://asciinema.org/a/141292) -[podman-varlink(1)](/docs/podman-varlink.1.md) | Run the varlink backend | -[podman-version(1)](/docs/podman-version.1.md) | Display the version information | -[podman-volume(1)](/docs/podman-volume.1.md) | Manage Volumes | -[podman-volume-create(1)](/docs/podman-volume-create.1.md) | Create a volume | -[podman-volume-inspect(1)](/docs/podman-volume-inspect.1.md) | Get detailed information on one or more volumes | -[podman-volume-ls(1)](/docs/podman-volume-ls.1.md) | List all the available volumes | -[podman-volume-rm(1)](/docs/podman-volume-rm.1.md) | Remove one or more volumes | -[podman-volume-prune(1)](/docs/podman-volume-prune.1.md) | Remove all unused volumes | -[podman-wait(1)](/docs/podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes +| Command | Description | Demo | Script | +| :----------------------------------------------------------------------- | :------------------------------------------------------------------------- | :-------------------------------------------------------------------------- | :---------------------------------------------------------------------------------- | +| [podman(1)](/docs/podman.1.md) | Simple management tool for pods and images | +| [podman-attach(1)](/docs/podman-attach.1.md) | Attach to a running container | +| [podman-build(1)](/docs/podman-build.1.md) | Build an image using instructions from Dockerfiles | +| [podman-commit(1)](/docs/podman-commit.1.md) | Create new image based on the changed container | +| [podman-container(1)](/docs/podman-container.1.md) | Manage Containers | +| [podman-container-checkpoint(1)](/docs/podman-container-checkpoint.1.md) | Checkpoints one or more running containers | +| [podman-container-cleanup(1)](/docs/podman-container-cleanup.1.md) | Cleanup Container storage and networks | +| [podman-container-exists(1)](/docs/podman-container-exists.1.md) | Check if an container exists in local storage | +| [podman-container-prune(1)](/docs/podman-container-prune.1.md) | Remove all stopped containers | +| [podman-container-refresh(1)](/docs/podman-container-refresh.1.md) | Refresh all containers state in database | +| [podman-container-restore(1)](/docs/podman-container-restore.1.md) | Restores one or more running containers | +| [podman-container-runlabel(1)](/docs/podman-container-runlabel.1.md) | Execute Image Label Method | +| [podman-cp(1)](/docs/podman-cp.1.md) | Copy files/folders between a container and the local filesystem | +| [podman-create(1)](/docs/podman-create.1.md) | Create a new container | +| [podman-diff(1)](/docs/podman-diff.1.md) | Inspect changes on a container or image's filesystem | +| [podman-events(1)](/docs/podman-events.1.md) | Monitor Podman events | +| [podman-exec(1)](/docs/podman-exec.1.md) | Execute a command in a running container | +| [podman-export(1)](/docs/podman-export.1.md) | Export container's filesystem contents as a tar archive | +| [podman-generate(1)](/docs/podman-generate.1.md) | Generate structured output based on Podman containers and pods | +| [podman-generate-kube(1)](/docs/podman-generate-kube.1.md) | Generate Kubernetes YAML based on a container or Pod | +| [podman-generate-systemd(1)](/docs/podman-generate-systemd.1.md) | Generate a Systemd unit file for a container | +| [podman-history(1)](/docs/podman-history.1.md) | Shows the history of an image | +| [podman-image(1)](/docs/podman-image.1.md) | Manage Images | +| [podman-image-exists(1)](/docs/podman-image-exists.1.md) | Check if an image exists in local storage | +| [podman-image-prune(1)](/docs/podman-image-prune.1.md) | Remove all unused images | +| [podman-image-sign(1)](/docs/podman-image-sign.1.md) | Create a signature for an image | +| [podman-image-trust(1)](/docs/podman-image-trust.1.md) | Manage container registry image trust policy | +| [podman-images(1)](/docs/podman-images.1.md) | List images in local storage | [![...](/docs/play.png)](https://podman.io/asciinema/podman/images/) | [Here](https://github.com/containers/Demos/blob/master/podman_cli/podman_images.sh) | +| [podman-import(1)](/docs/podman-import.1.md) | Import a tarball and save it as a filesystem image | +| [podman-info(1)](/docs/podman-info.1.md) | Display system information | +| [podman-init(1)](/docs/podman-init.1.md) | Initialize a container | +| [podman-inspect(1)](/docs/podman-inspect.1.md) | Display the configuration of a container or image | [![...](/docs/play.png)](https://asciinema.org/a/133418) | +| [podman-kill(1)](/docs/podman-kill.1.md) | Kill the main process in one or more running containers | +| [podman-load(1)](/docs/podman-load.1.md) | Load an image from a container image archive | +| [podman-login(1)](/docs/podman-login.1.md) | Login to a container registry | +| [podman-logout(1)](/docs/podman-logout.1.md) | Logout of a container registry | +| [podman-logs(1)](/docs/podman-logs.1.md) | Display the logs of a container | +| [podman-mount(1)](/docs/podman-mount.1.md) | Mount a working container's root filesystem | +| [podman-pause(1)](/docs/podman-pause.1.md) | Pause one or more running containers | [![...](/docs/play.png)](https://asciinema.org/a/141292) | +| [podman-play(1)](/docs/podman-play.1.md) | Play pods and containers based on a structured input file | +| [podman-pod(1)](/docs/podman-pod.1.md) | Simple management tool for groups of containers, called pods | +| [podman-pod-create(1)](/docs/podman-pod-create.1.md) | Create a new pod | +| [podman-pod-inspect(1)](/docs/podman-pod-inspect.1.md) | Inspect a pod | +| [podman-pod-kill(1)](podman-pod-kill.1.md) | Kill the main process of each container in pod. | +| [podman-pod-ps(1)](/docs/podman-pod-ps.1.md) | List the pods on the system | +| [podman-pod-pause(1)](podman-pod-pause.1.md) | Pause one or more pods. | +| [podman-pod-restart](/docs/podman-pod-restart.1.md) | Restart one or more pods | +| [podman-pod-rm(1)](/docs/podman-pod-rm.1.md) | Remove one or more pods | +| [podman-pod-start(1)](/docs/podman-pod-start.1.md) | Start one or more pods | +| [podman-pod-stats(1)](/docs/podman-pod-stats.1.md) | Display a live stream of one or more pods' resource usage statistics | | | +| [podman-pod-stop(1)](/docs/podman-pod-stop.1.md) | Stop one or more pods | +| [podman-pod-top(1)](/docs/podman-pod-top.1.md) | Display the running processes of a pod | +| [podman-pod-unpause(1)](podman-pod-unpause.1.md) | Unpause one or more pods. | +| [podman-port(1)](/docs/podman-port.1.md) | List port mappings for running containers | +| [podman-ps(1)](/docs/podman-ps.1.md) | Prints out information about containers | +| [podman-pull(1)](/docs/podman-pull.1.md) | Pull an image from a registry | +| [podman-push(1)](/docs/podman-push.1.md) | Push an image to a specified destination | [![...](/docs/play.png)](https://asciinema.org/a/133276) | +| [podman-restart](/docs/podman-restart.1.md) | Restarts one or more containers | [![...](/docs/play.png)](https://asciinema.org/a/jiqxJAxcVXw604xdzMLTkQvHM) | +| [podman-rm(1)](/docs/podman-rm.1.md) | Removes one or more containers | +| [podman-rmi(1)](/docs/podman-rmi.1.md) | Removes one or more images | +| [podman-run(1)](/docs/podman-run.1.md) | Run a command in a container | +| [podman-save(1)](/docs/podman-save.1.md) | Saves an image to an archive | +| [podman-search(1)](/docs/podman-search.1.md) | Search a registry for an image | +| [podman-start(1)](/docs/podman-start.1.md) | Starts one or more containers | +| [podman-stats(1)](/docs/podman-stats.1.md) | Display a live stream of one or more containers' resource usage statistics | +| [podman-stop(1)](/docs/podman-stop.1.md) | Stops one or more running containers | +| [podman-system(1)](/docs/podman-system.1.md) | Manage podman | +| [podman-tag(1)](/docs/podman-tag.1.md) | Add an additional name to a local image | [![...](/docs/play.png)](https://asciinema.org/a/133803) | +| [podman-top(1)](/docs/podman-top.1.md) | Display the running processes of a container | +| [podman-umount(1)](/docs/podman-umount.1.md) | Unmount a working container's root filesystem | +| [podman-unpause(1)](/docs/podman-unpause.1.md) | Unpause one or more running containers | [![...](/docs/play.png)](https://asciinema.org/a/141292) | +| [podman-unshare(1)](/docs/podman-unshare.1.md) | Run a command inside of a modified user namespace. | +| [podman-varlink(1)](/docs/podman-varlink.1.md) | Run the varlink backend | +| [podman-version(1)](/docs/podman-version.1.md) | Display the version information | +| [podman-volume(1)](/docs/podman-volume.1.md) | Manage Volumes | +| [podman-volume-create(1)](/docs/podman-volume-create.1.md) | Create a volume | +| [podman-volume-inspect(1)](/docs/podman-volume-inspect.1.md) | Get detailed information on one or more volumes | +| [podman-volume-ls(1)](/docs/podman-volume-ls.1.md) | List all the available volumes | +| [podman-volume-rm(1)](/docs/podman-volume-rm.1.md) | Remove one or more volumes | +| [podman-volume-prune(1)](/docs/podman-volume-prune.1.md) | Remove all unused volumes | +| [podman-wait(1)](/docs/podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes | diff --git a/contrib/cirrus/integration_test.sh b/contrib/cirrus/integration_test.sh index 5b73f0c6c..c7d381318 100755 --- a/contrib/cirrus/integration_test.sh +++ b/contrib/cirrus/integration_test.sh @@ -36,6 +36,7 @@ else make make install PREFIX=/usr ETCDIR=/etc make test-binaries + make install.tools clean_env case "${OS_RELEASE_ID}-${OS_RELEASE_VER}" in @@ -49,6 +50,11 @@ else ;; *) bad_os_id_ver ;; esac - make localintegration + if [[ "$TEST_REMOTE_CLIENT" == "true" ]] + then + make remoteintegration + else + make localintegration + fi exit $? fi diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index f422fe935..a285b133b 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -283,16 +283,16 @@ install_buildah() { ooe.sh sudo make install } -# Requires $GOPATH and $CRIO_COMMIT to be set +# Requires $GOPATH and $CONMON_COMMIT to be set install_conmon(){ - echo "Installing conmon from commit $CRIO_COMMIT" - req_env_var GOPATH CRIO_COMMIT - DEST="$GOPATH/src/github.com/kubernetes-sigs/cri-o.git" + echo "Installing conmon from commit $CONMON_COMMIT" + req_env_var GOPATH CONMON_COMMIT + DEST="$GOPATH/src/github.com/containers/conmon.git" rm -rf "$DEST" - ooe.sh git clone https://github.com/kubernetes-sigs/cri-o.git "$DEST" + ooe.sh git clone https://github.com/containers/conmon.git "$DEST" cd "$DEST" ooe.sh git fetch origin --tags - ooe.sh git checkout -q "$CRIO_COMMIT" + ooe.sh git checkout -q "$CONMON_COMMIT" ooe.sh make sudo install -D -m 755 bin/conmon /usr/libexec/podman/conmon } diff --git a/contrib/cirrus/required_host_ports.txt b/contrib/cirrus/required_host_ports.txt new file mode 100644 index 000000000..9248e497a --- /dev/null +++ b/contrib/cirrus/required_host_ports.txt @@ -0,0 +1,4 @@ +github.com 22 +docker.io 443 +quay.io 443 +registry.fedoraproject.org 443 diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index 98276b70c..4dbd56ed9 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -36,6 +36,7 @@ then "export OS_RELEASE_ID=\"$(os_release_id)\"" \ "export OS_RELEASE_VER=\"$(os_release_ver)\"" \ "export OS_REL_VER=\"$(os_release_id)-$(os_release_ver)\"" \ + "export TEST_REMOTE_CLIENT=\"$TEST_REMOTE_CLIENT\"" \ "export BUILT_IMAGE_SUFFIX=\"-$CIRRUS_REPO_NAME-${CIRRUS_CHANGE_IN_REPO:0:8}\"" \ "export GOPATH=\"/var/tmp/go\"" \ 'export PATH="$HOME/bin:$GOPATH/bin:/usr/local/bin:$PATH"' \ diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index d69b673e0..228f65b50 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -33,19 +33,19 @@ %global shortcommit0 %(c=%{commit0}; echo ${c:0:8}) # People want conmon packaged with the copr rpm -%global import_path_conmon github.com/kubernetes-sigs/cri-o +%global import_path_conmon github.com/containers/conmon %global git_conmon https://%{import_path_conmon} -%global commit_conmon 4cd5a7c60349be0678d9f1b0657683324c1a2726 +%global commit_conmon f02c053eb37010fc76d1e2966de7f2cb9f969ef2 %global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7}) Name: podman -Version: 1.3.1 +Version: 1.3.2 Release: #COMMITDATE#.git%{shortcommit0}%{?dist} Summary: Manage Pods, Containers and Container Images License: ASL 2.0 URL: %{git_podman} Source0: %{git0}/archive/%{commit0}/%{repo}-%{shortcommit0}.tar.gz -Source1: crio.tar.gz +Source1: conmon.tar.gz # e.g. el6 has ppc64 arch without gcc-go, so EA tag is required #ExclusiveArch: %%{?go_arches:%%{go_arches}}%%{!?go_arches:%%{ix86} x86_64 aarch64 %%{arm}} ExclusiveArch: aarch64 %{arm} ppc64le s390x x86_64 @@ -185,6 +185,14 @@ Provides: bundled(golang(k8s.io/utils)) = 258e2a2fa64568210fbd6267cf1d8fd87c3cb8 %{repo} provides a library for applications looking to use the Container Pod concept popularized by Kubernetes. +%package remote +Summary: Remote Podman client + +%description -n podman-remote +%{summary} +This package provides the Podman remote client which +can be used to access Podman running on a server. + %if 0%{?with_devel} %package devel Summary: Library for applications looking to use Container Pods @@ -363,18 +371,16 @@ GOPATH=$GOPATH go generate ./cmd/podman/varlink/... BUILDTAGS=$BUILDTAGS make binaries docs # build conmon -pushd crio +pushd conmon mkdir _output pushd _output -mkdir -p src/%{provider}.%{provider_tld}/{kubernetes-sigs,opencontainers} +mkdir -p src/%{provider}.%{provider_tld}/{containers,opencontainers} ln -s $(dirs +1 -l) src/%{import_path_conmon} popd -ln -s vendor src -export GOPATH=$(pwd)/_output:$(pwd):%{gopath} export BUILDTAGS="selinux seccomp $(hack/btrfs_installed_tag.sh) $(hack/btrfs_tag.sh) containers_image_ostree_stub" -BUILDTAGS=$BUILDTAGS make -C conmon +BUILDTAGS=$BUILDTAGS make popd %install @@ -394,7 +400,7 @@ install -p -m 644 %{repo}.conf %{buildroot}%{_datadir}/containers # install conmon install -dp %{buildroot}%{_libexecdir}/%{name} -install -p -m 755 crio/bin/conmon %{buildroot}%{_libexecdir}/%{name} +install -p -m 755 conmon/bin/conmon %{buildroot}%{_libexecdir}/%{name} # source codes for building projects %if 0%{?with_devel} @@ -491,6 +497,11 @@ export GOPATH=%{buildroot}/%{gopath}:$(pwd)/vendor:%{gopath} %doc README.md CONTRIBUTING.md pkg/hooks/README-hooks.md install.md code-of-conduct.md transfer.md %endif +%files -n podman-remote +%license LICENSE +%doc README.md CONTRIBUTING.md pkg/hooks/README-hooks.md install.md code-of-conduct.md transfer.md +%{_bindir}/%{name}-remote + %changelog * Sat Aug 4 2018 Dan Walsh <dwalsh@redhat.com> - 0.8.1-1.git6b4ab2a - Bump to v0.8.1 diff --git a/docs/libpod.conf.5.md b/docs/libpod.conf.5.md index 2f0b3f303..cb08f0eb0 100644 --- a/docs/libpod.conf.5.md +++ b/docs/libpod.conf.5.md @@ -34,7 +34,7 @@ libpod to manage containers. Each `*.json` file in the path configures a hook for Podman containers. For more details on the syntax of the JSON files and the semantics of hook injection, see `oci-hooks(5)`. Podman and libpod currently support both the 1.0.0 and 0.1.0 hook schemas, although the 0.1.0 schema is deprecated. - Paths listed later in the array higher precedence (`oci-hooks(5)` discusses directory precedence). + Paths listed later in the array have higher precedence (`oci-hooks(5)` discusses directory precedence). For the annotation conditions, libpod uses any annotations set in the generated OCI configuration. diff --git a/docs/podman-unshare.1.md b/docs/podman-unshare.1.md new file mode 100644 index 000000000..a7f018ce1 --- /dev/null +++ b/docs/podman-unshare.1.md @@ -0,0 +1,37 @@ +% podman-unshare "1" + +## NAME +podman\-unshare - Run a command inside of a modified user namespace. + +## SYNOPSIS +**podman unshare** [*options*] [**--**] [*command*] + +## DESCRIPTION +Launches a process (by default, *$SHELL*) in a new user namespace. The user +namespace is configured so that the invoking user's UID and primary GID appear +to be UID 0 and GID 0, respectively. Any ranges which match that user and +group in /etc/subuid and /etc/subgid are also mapped in as themselves with the +help of the *newuidmap(1)* and *newgidmap(1)* helpers. + +podman unshare is useful for troubleshooting unprivileged operations and for +manually clearing storage and other data related to images and containers. + +It is also useful if you want to use the `podman mount` command. If an unprivileged users wants to mount and work with a container, then they need to execute +podman unshare. Executing `podman mount` fails for unprivileged users unless the user is running inside a `podman unshare` session. + +## EXAMPLE + +``` +$ podman unshare id +uid=0(root) gid=0(root) groups=0(root),65534(nobody) + +$ podman unshare cat /proc/self/uid_map /proc/self/gid_map + 0 1000 1 + 1 10000 65536 + 0 1000 1 + 1 10000 65536 +``` + + +## SEE ALSO +podman(1), podman-mount(1), namespaces(7), newuidmap(1), newgidmap(1), user\_namespaces(7)
\ No newline at end of file diff --git a/docs/podman.1.md b/docs/podman.1.md index ef12cf1cc..ff942a3c4 100644 --- a/docs/podman.1.md +++ b/docs/podman.1.md @@ -128,58 +128,59 @@ the exit codes follow the `chroot` standard, see below: ## COMMANDS -| Command | Description | -| ----------------------------------------- | ------------------------------------------------------------------------------ | -| [podman-attach(1)](podman-attach.1.md) | Attach to a running container. | -| [podman-build(1)](podman-build.1.md) | Build a container image using a Dockerfile. | -| [podman-commit(1)](podman-commit.1.md) | Create new image based on the changed container. | -| [podman-container(1)](podman-container.1.md) | Manage containers. | -| [podman-cp(1)](podman-cp.1.md) | Copy files/folders between a container and the local filesystem. | -| [podman-create(1)](podman-create.1.md) | Create a new container. | -| [podman-diff(1)](podman-diff.1.md) | Inspect changes on a container or image's filesystem. | -| [podman-events(1)](podman-events.1.md) | Monitor Podman events | -| [podman-exec(1)](podman-exec.1.md) | Execute a command in a running container. | -| [podman-export(1)](podman-export.1.md) | Export a container's filesystem contents as a tar archive. | -| [podman-generate(1)](podman-generate.1.md)| Generate structured data based for a containers and pods. | -| [podman-healthcheck(1)](podman-healthcheck.1.md)| Manage healthchecks for containers | -| [podman-history(1)](podman-history.1.md) | Show the history of an image. | -| [podman-image(1)](podman-image.1.md) | Manage images. | -| [podman-images(1)](podman-images.1.md) | List images in local storage. | -| [podman-import(1)](podman-import.1.md) | Import a tarball and save it as a filesystem image. | -| [podman-info(1)](podman-info.1.md) | Displays Podman related system information. | -| [podman-init(1)](podman-init.1.md) | Initialize a container | -| [podman-inspect(1)](podman-inspect.1.md) | Display a container or image's configuration. | -| [podman-kill(1)](podman-kill.1.md) | Kill the main process in one or more containers. | -| [podman-load(1)](podman-load.1.md) | Load an image from a container image archive into container storage. | -| [podman-login(1)](podman-login.1.md) | Login to a container registry. | -| [podman-logout(1)](podman-logout.1.md) | Logout of a container registry. | -| [podman-logs(1)](podman-logs.1.md) | Display the logs of a container. | -| [podman-mount(1)](podman-mount.1.md) | Mount a working container's root filesystem. | -| [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. | -| [podman-play(1)](podman-play.1.md) | Play pods and containers based on a structured input file. | -| [podman-pod(1)](podman-pod.1.md) | Management tool for groups of containers, called pods. | -| [podman-port(1)](podman-port.1.md) | List port mappings for a container. | -| [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. | -| [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. | -| [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. | -| [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. | -| [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. | -| [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. | -| [podman-run(1)](podman-run.1.md) | Run a command in a new container. | -| [podman-save(1)](podman-save.1.md) | Save an image to a container archive. | -| [podman-search(1)](podman-search.1.md) | Search a registry for an image. | -| [podman-start(1)](podman-start.1.md) | Start one or more containers. | -| [podman-stats(1)](podman-stats.1.md) | Display a live stream of one or more container's resource usage statistics. | -| [podman-stop(1)](podman-stop.1.md) | Stop one or more running containers. | -| [podman-system(1)](podman-system.1.md) | Manage podman. | -| [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. | -| [podman-top(1)](podman-top.1.md) | Display the running processes of a container. | -| [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem. | -| [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. | -| [podman-version(1)](podman-varlink.1.md) | Runs the varlink backend interface. | -| [podman-varlink(1)](podman-version.1.md) | Display the Podman version information. | -| [podman-volume(1)](podman-volume.1.md) | Manage Volumes. | -| [podman-wait(1)](podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes. | +| Command | Description | +| ------------------------------------------------ | --------------------------------------------------------------------------- | +| [podman-attach(1)](podman-attach.1.md) | Attach to a running container. | +| [podman-build(1)](podman-build.1.md) | Build a container image using a Dockerfile. | +| [podman-commit(1)](podman-commit.1.md) | Create new image based on the changed container. | +| [podman-container(1)](podman-container.1.md) | Manage containers. | +| [podman-cp(1)](podman-cp.1.md) | Copy files/folders between a container and the local filesystem. | +| [podman-create(1)](podman-create.1.md) | Create a new container. | +| [podman-diff(1)](podman-diff.1.md) | Inspect changes on a container or image's filesystem. | +| [podman-events(1)](podman-events.1.md) | Monitor Podman events | +| [podman-exec(1)](podman-exec.1.md) | Execute a command in a running container. | +| [podman-export(1)](podman-export.1.md) | Export a container's filesystem contents as a tar archive. | +| [podman-generate(1)](podman-generate.1.md) | Generate structured data based for a containers and pods. | +| [podman-healthcheck(1)](podman-healthcheck.1.md) | Manage healthchecks for containers | +| [podman-history(1)](podman-history.1.md) | Show the history of an image. | +| [podman-image(1)](podman-image.1.md) | Manage images. | +| [podman-images(1)](podman-images.1.md) | List images in local storage. | +| [podman-import(1)](podman-import.1.md) | Import a tarball and save it as a filesystem image. | +| [podman-info(1)](podman-info.1.md) | Displays Podman related system information. | +| [podman-init(1)](podman-init.1.md) | Initialize a container | +| [podman-inspect(1)](podman-inspect.1.md) | Display a container or image's configuration. | +| [podman-kill(1)](podman-kill.1.md) | Kill the main process in one or more containers. | +| [podman-load(1)](podman-load.1.md) | Load an image from a container image archive into container storage. | +| [podman-login(1)](podman-login.1.md) | Login to a container registry. | +| [podman-logout(1)](podman-logout.1.md) | Logout of a container registry. | +| [podman-logs(1)](podman-logs.1.md) | Display the logs of a container. | +| [podman-mount(1)](podman-mount.1.md) | Mount a working container's root filesystem. | +| [podman-pause(1)](podman-pause.1.md) | Pause one or more containers. | +| [podman-play(1)](podman-play.1.md) | Play pods and containers based on a structured input file. | +| [podman-pod(1)](podman-pod.1.md) | Management tool for groups of containers, called pods. | +| [podman-port(1)](podman-port.1.md) | List port mappings for a container. | +| [podman-ps(1)](podman-ps.1.md) | Prints out information about containers. | +| [podman-pull(1)](podman-pull.1.md) | Pull an image from a registry. | +| [podman-push(1)](podman-push.1.md) | Push an image from local storage to elsewhere. | +| [podman-restart(1)](podman-restart.1.md) | Restart one or more containers. | +| [podman-rm(1)](podman-rm.1.md) | Remove one or more containers. | +| [podman-rmi(1)](podman-rmi.1.md) | Removes one or more locally stored images. | +| [podman-run(1)](podman-run.1.md) | Run a command in a new container. | +| [podman-save(1)](podman-save.1.md) | Save an image to a container archive. | +| [podman-search(1)](podman-search.1.md) | Search a registry for an image. | +| [podman-start(1)](podman-start.1.md) | Start one or more containers. | +| [podman-stats(1)](podman-stats.1.md) | Display a live stream of one or more container's resource usage statistics. | +| [podman-stop(1)](podman-stop.1.md) | Stop one or more running containers. | +| [podman-system(1)](podman-system.1.md) | Manage podman. | +| [podman-tag(1)](podman-tag.1.md) | Add an additional name to a local image. | +| [podman-top(1)](podman-top.1.md) | Display the running processes of a container. | +| [podman-umount(1)](podman-umount.1.md) | Unmount a working container's root filesystem. | +| [podman-unpause(1)](podman-unpause.1.md) | Unpause one or more containers. | +| [podman-unshare(1)](podman-unshare.1.md) | Run a command inside of a modified user namespace. | +| [podman-version(1)](podman-varlink.1.md) | Runs the varlink backend interface. | +| [podman-varlink(1)](podman-version.1.md) | Display the Podman version information. | +| [podman-volume(1)](podman-volume.1.md) | Manage Volumes. | +| [podman-wait(1)](podman-wait.1.md) | Wait on one or more containers to stop and print their exit codes. | ## FILES diff --git a/install.md b/install.md index 82dd4c36a..a278cb4ba 100644 --- a/install.md +++ b/install.md @@ -188,13 +188,12 @@ export PATH=$GOPATH/bin:$PATH #### conmon The latest version of `conmon` is expected to be installed on the system. Conmon is used to monitor OCI Runtimes. -To build from source, use the following (if not already executed above, run `export GOPATH=~/go && mkdir -p $GOPATH`): +To build from source, use the following: ```bash -git clone https://github.com/cri-o/cri-o $GOPATH/src/github.com/cri-o/cri-o -cd $GOPATH/src/github.com/cri-o/cri-o -mkdir bin -make bin/conmon +git clone https://github.com/containers/conmon +cd conmon +make sudo install -D -m 755 bin/conmon /usr/libexec/podman/conmon ``` diff --git a/libpod/container_api.go b/libpod/container_api.go index 5bb610aab..06a31da11 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "strconv" + "sync" "time" "github.com/containers/libpod/libpod/driver" @@ -119,13 +120,20 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams, attachChan := make(chan error) + // We need to ensure that we don't return until start() fired in attach. + // Use a WaitGroup to sync this. + wg := new(sync.WaitGroup) + wg.Add(1) + // Attach to the container before starting it go func() { - if err := c.attach(streams, keys, resize, true); err != nil { + if err := c.attach(streams, keys, resize, true, wg); err != nil { attachChan <- err } close(attachChan) }() + + wg.Wait() c.newContainerEvent(events.Attach) return attachChan, nil } @@ -398,7 +406,7 @@ func (c *Container) Attach(streams *AttachStreams, keys string, resize <-chan re return errors.Wrapf(ErrCtrStateInvalid, "can only attach to created or running containers") } defer c.newContainerEvent(events.Attach) - return c.attach(streams, keys, resize, false) + return c.attach(streams, keys, resize, false, nil) } // Mount mounts a container's filesystem on the host diff --git a/libpod/container_attach_linux.go b/libpod/container_attach_linux.go index 3ff6ddc76..7e9b7697b 100644 --- a/libpod/container_attach_linux.go +++ b/libpod/container_attach_linux.go @@ -8,6 +8,7 @@ import ( "net" "os" "path/filepath" + "sync" "github.com/containers/libpod/pkg/kubeutils" "github.com/containers/libpod/utils" @@ -31,7 +32,7 @@ const ( // Attach to the given container // Does not check if state is appropriate -func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool) error { +func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, wg *sync.WaitGroup) error { if !streams.AttachOutput && !streams.AttachError && !streams.AttachInput { return errors.Wrapf(ErrInvalidArg, "must provide at least one stream to attach to") } @@ -48,12 +49,17 @@ func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan re logrus.Debugf("Attaching to container %s", c.ID()) - return c.attachContainerSocket(resize, detachKeys, streams, startContainer) + return c.attachContainerSocket(resize, detachKeys, streams, startContainer, wg) } -// attachContainerSocket connects to the container's attach socket and deals with the IO +// attachContainerSocket connects to the container's attach socket and deals with the IO. +// wg is only required if startContainer is true // TODO add a channel to allow interrupting -func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSize, detachKeys []byte, streams *AttachStreams, startContainer bool) error { +func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSize, detachKeys []byte, streams *AttachStreams, startContainer bool, wg *sync.WaitGroup) error { + if startContainer && wg == nil { + return errors.Wrapf(ErrInternal, "wait group not passed when startContainer set") + } + kubeutils.HandleResizing(resize, func(size remotecommand.TerminalSize) { controlPath := filepath.Join(c.bundlePath(), "ctl") controlFile, err := os.OpenFile(controlPath, unix.O_WRONLY, 0) @@ -84,10 +90,13 @@ func (c *Container) attachContainerSocket(resize <-chan remotecommand.TerminalSi } defer conn.Close() + // If starting was requested, start the container and notify when that's + // done. if startContainer { if err := c.start(); err != nil { return err } + wg.Done() } receiveStdoutError := make(chan error) diff --git a/libpod/container_attach_unsupported.go b/libpod/container_attach_unsupported.go index 068652b29..9e8badeaf 100644 --- a/libpod/container_attach_unsupported.go +++ b/libpod/container_attach_unsupported.go @@ -3,9 +3,11 @@ package libpod import ( + "sync" + "k8s.io/client-go/tools/remotecommand" ) -func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool) error { +func (c *Container) attach(streams *AttachStreams, keys string, resize <-chan remotecommand.TerminalSize, startContainer bool, wg *sync.WaitGroup) error { return ErrNotImplemented } diff --git a/libpod/container_commit.go b/libpod/container_commit.go index ae04f67bb..739fcd80e 100644 --- a/libpod/container_commit.go +++ b/libpod/container_commit.go @@ -99,7 +99,7 @@ func (c *Container) Commit(ctx context.Context, destImage string, options Contai // Should we store the ENV we actually want in the spec separately? if c.config.Spec.Process != nil { for _, e := range c.config.Spec.Process.Env { - splitEnv := strings.Split(e, "=") + splitEnv := strings.SplitN(e, "=", 2) importBuilder.SetEnv(splitEnv[0], splitEnv[1]) } } diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go index 264c84f89..78a630e9a 100644 --- a/libpod/events/journal_linux.go +++ b/libpod/events/journal_linux.go @@ -12,6 +12,9 @@ import ( "github.com/sirupsen/logrus" ) +// DefaultEventerType is journald when systemd is available +const DefaultEventerType = Journald + // EventJournalD is the journald implementation of an eventer type EventJournalD struct { options EventerOptions diff --git a/libpod/events/journal_unsupported.go b/libpod/events/journal_unsupported.go index c91d81f12..004efdab2 100644 --- a/libpod/events/journal_unsupported.go +++ b/libpod/events/journal_unsupported.go @@ -2,6 +2,9 @@ package events +// DefaultEventerType is logfile when systemd is not present +const DefaultEventerType = LogFile + // newEventJournalD always returns an error if libsystemd not found func newEventJournalD(options EventerOptions) (Eventer, error) { return nil, ErrNoJournaldLogging diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 2450bd6b1..b8a916de3 100644 --- a/libpod/networking_linux.go +++ b/libpod/networking_linux.go @@ -19,6 +19,7 @@ import ( "github.com/containers/libpod/pkg/firewall" "github.com/containers/libpod/pkg/inspect" "github.com/containers/libpod/pkg/netns" + "github.com/containers/libpod/pkg/rootless" "github.com/cri-o/ocicni/pkg/ocicni" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -100,6 +101,9 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re // Create and configure a new network namespace for a container func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q []*cnitypes.Result, err error) { + if rootless.IsRootless() { + return nil, nil, errors.New("cannot configure a new network namespace in rootless mode, only --network=slirp4netns is supported") + } ctrNS, err := netns.NewNS() if err != nil { return nil, nil, errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID()) diff --git a/libpod/runtime.go b/libpod/runtime.go index e6b84014e..18e9dfeb3 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -304,7 +304,7 @@ func defaultRuntimeConfig() (RuntimeConfig, error) { EnablePortReservation: true, EnableLabeling: true, NumLocks: 2048, - EventsLogger: "journald", + EventsLogger: events.DefaultEventerType.String(), }, nil } diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 456ad365f..124d0daf8 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -308,5 +308,15 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) // Mark pod invalid p.valid = false p.newPodEvent(events.Remove) + + // Deallocate the pod lock + if err := p.lock.Free(); err != nil { + if removalErr == nil { + removalErr = errors.Wrapf(err, "error freeing pod %s lock", p.ID()) + } else { + logrus.Errorf("Error freeing pod %s lock: %v", p.ID(), err) + } + } + return removalErr } diff --git a/pkg/hooks/0.1.0/hook.go b/pkg/hooks/0.1.0/hook.go index 49d833aa8..ba68b0f10 100644 --- a/pkg/hooks/0.1.0/hook.go +++ b/pkg/hooks/0.1.0/hook.go @@ -19,7 +19,7 @@ type Hook struct { Hook *string `json:"hook"` Arguments []string `json:"arguments,omitempty"` - // https://github.com/kubernetes-sigs/cri-o/pull/1235 + // https://github.com/cri-o/cri-o/pull/1235 Stages []string `json:"stages"` Stage []string `json:"stage"` diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index 20c649f9a..df303db6d 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -7,6 +7,7 @@ import ( "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/rootless" + "github.com/containers/libpod/pkg/util" pmount "github.com/containers/storage/pkg/mount" "github.com/docker/docker/oci/caps" "github.com/docker/go-units" @@ -267,7 +268,9 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM // SECURITY OPTS g.SetProcessNoNewPrivileges(config.NoNewPrivs) - g.SetProcessApparmorProfile(config.ApparmorProfile) + if !config.Privileged { + g.SetProcessApparmorProfile(config.ApparmorProfile) + } blockAccessToKernelFilesystems(config, &g) @@ -347,10 +350,13 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM } if rootless.IsRootless() { - if addedResources { - return nil, errors.New("invalid configuration, cannot set resources with rootless containers") + cgroup2, err := util.IsCgroup2UnifiedMode() + if err != nil { + return nil, err + } + if addedResources && !cgroup2 { + return nil, errors.New("invalid configuration, cannot set resources with rootless containers not using cgroups v2 unified mode") } - configSpec.Linux.Resources = &spec.LinuxResources{} } // Make sure that the bind mounts keep options like nosuid, noexec, nodev. diff --git a/pkg/util/utils_supported.go b/pkg/util/utils_supported.go index af5e67fc1..8b98658c2 100644 --- a/pkg/util/utils_supported.go +++ b/pkg/util/utils_supported.go @@ -11,9 +11,33 @@ import ( "github.com/pkg/errors" "os" "path/filepath" + "sync" "syscall" ) +const ( + _cgroup2SuperMagic = 0x63677270 +) + +var ( + isUnifiedOnce sync.Once + isUnified bool + isUnifiedErr error +) + +// IsCgroup2UnifiedMode returns whether we are running in cgroup 2 unified mode. +func IsCgroup2UnifiedMode() (bool, error) { + isUnifiedOnce.Do(func() { + var st syscall.Statfs_t + if err := syscall.Statfs("/sys/fs/cgroup", &st); err != nil { + isUnified, isUnifiedErr = false, err + } else { + isUnified, isUnifiedErr = st.Type == _cgroup2SuperMagic, nil + } + }) + return isUnified, isUnifiedErr +} + // GetRootlessRuntimeDir returns the runtime directory when running as non root func GetRootlessRuntimeDir() (string, error) { var rootlessRuntimeDirError error diff --git a/pkg/util/utils_windows.go b/pkg/util/utils_windows.go index 1e9ccea90..b33733da9 100644 --- a/pkg/util/utils_windows.go +++ b/pkg/util/utils_windows.go @@ -10,3 +10,8 @@ import ( func GetRootlessRuntimeDir() (string, error) { return "", errors.New("this function is not implemented for windows") } + +// IsCgroup2UnifiedMode returns whether we are running in cgroup 2 unified mode. +func IsCgroup2UnifiedMode() (bool, error) { + return false, errors.New("this function is not implemented for windows") +} diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go index 3ece4887e..bf20ac999 100644 --- a/test/e2e/commit_test.go +++ b/test/e2e/commit_test.go @@ -194,4 +194,24 @@ var _ = Describe("Podman commit", func() { Expect(r.ExitCode()).To(Equal(0)) }) + It("podman commit container check env variables", func() { + s := podmanTest.Podman([]string{"run", "--name", "test1", "-e", "TEST=1=1-01=9.01", "-it", "alpine", "true"}) + s.WaitWithDefaultTimeout() + Expect(s.ExitCode()).To(Equal(0)) + + c := podmanTest.Podman([]string{"commit", "test1", "newimage"}) + c.WaitWithDefaultTimeout() + Expect(c.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", "newimage"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + image := inspect.InspectImageJSON() + + envMap := make(map[string]bool) + for _, v := range image[0].Config.Env { + envMap[v] = true + } + Expect(envMap["TEST=1=1-01=9.01"]).To(BeTrue()) + }) }) diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go index 273668f35..1dfa8f50d 100644 --- a/test/e2e/cp_test.go +++ b/test/e2e/cp_test.go @@ -40,15 +40,11 @@ var _ = Describe("Podman cp", func() { It("podman cp file", func() { path, err := os.Getwd() - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) filePath := filepath.Join(path, "cp_test.txt") fromHostToContainer := []byte("copy from host to container") err = ioutil.WriteFile(filePath, fromHostToContainer, 0644) - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) session := podmanTest.Podman([]string{"create", ALPINE, "cat", "foo"}) session.WaitWithDefaultTimeout() @@ -69,15 +65,12 @@ var _ = Describe("Podman cp", func() { It("podman cp file to dir", func() { path, err := os.Getwd() - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) filePath := filepath.Join(path, "cp_test.txt") fromHostToContainer := []byte("copy from host to container directory") err = ioutil.WriteFile(filePath, fromHostToContainer, 0644) - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) + session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foodir/"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -97,14 +90,10 @@ var _ = Describe("Podman cp", func() { It("podman cp dir to dir", func() { path, err := os.Getwd() - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) testDirPath := filepath.Join(path, "TestDir") err = os.Mkdir(testDirPath, 0777) - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) session := podmanTest.Podman([]string{"create", ALPINE, "ls", "/foodir"}) session.WaitWithDefaultTimeout() @@ -124,19 +113,13 @@ var _ = Describe("Podman cp", func() { It("podman cp stdin/stdout", func() { path, err := os.Getwd() - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) testDirPath := filepath.Join(path, "TestDir") err = os.Mkdir(testDirPath, 0777) - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) cmd := exec.Command("tar", "-zcvf", "file.tar.gz", testDirPath) _, err = cmd.Output() - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foo"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/info_test.go b/test/e2e/info_test.go index ca4012dde..c960fb311 100644 --- a/test/e2e/info_test.go +++ b/test/e2e/info_test.go @@ -24,7 +24,6 @@ var _ = Describe("Podman Info", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.DelayForVarlink() }) AfterEach(func() { diff --git a/test/e2e/libpod_suite_remoteclient_test.go b/test/e2e/libpod_suite_remoteclient_test.go index 05c355711..b7fd8537d 100644 --- a/test/e2e/libpod_suite_remoteclient_test.go +++ b/test/e2e/libpod_suite_remoteclient_test.go @@ -77,6 +77,7 @@ func (p *PodmanTestIntegration) StartVarlink() { command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} p.VarlinkCommand = command p.VarlinkSession = command.Process + p.DelayForVarlink() } func (p *PodmanTestIntegration) StopVarlink() { diff --git a/test/e2e/rootless_test.go b/test/e2e/rootless_test.go deleted file mode 100644 index 51544ff8b..000000000 --- a/test/e2e/rootless_test.go +++ /dev/null @@ -1,312 +0,0 @@ -// +build !remoteclient - -package integration - -import ( - "fmt" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "runtime" - "strings" - "syscall" - - . "github.com/containers/libpod/test/utils" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func canExec() bool { - const nsGetParent = 0xb702 - - u, err := os.Open("/proc/self/ns/user") - if err != nil { - return false - } - defer u.Close() - - _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, u.Fd(), uintptr(nsGetParent), 0) - return errno != syscall.ENOTTY -} - -var _ = Describe("Podman rootless", func() { - var ( - tempdir string - err error - podmanTest *PodmanTestIntegration - ) - - BeforeEach(func() { - SkipIfRootless() - tempdir, err = CreateTempDirInTempDir() - if err != nil { - os.Exit(1) - } - podmanTest = PodmanTestCreate(tempdir) - podmanTest.CgroupManager = "cgroupfs" - podmanTest.StorageOptions = ROOTLESS_STORAGE_OPTIONS - podmanTest.Setup() - podmanTest.RestoreAllArtifacts() - }) - - AfterEach(func() { - podmanTest.Cleanup() - f := CurrentGinkgoTestDescription() - processTestResult(f) - - }) - - It("podman rootless help|version", func() { - commands := []string{"help", "version"} - for _, v := range commands { - env := os.Environ() - env = append(env, "USER=foo") - cmd := podmanTest.PodmanAsUser([]string{v}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - } - }) - - chownFunc := func(p string, info os.FileInfo, err error) error { - if err != nil { - return err - } - return os.Lchown(p, 1000, 1000) - } - - type rootlessCB func(test *PodmanTestIntegration, xdgRuntimeDir string, home string, mountPath string) - - runInRootlessContext := func(cb rootlessCB) { - // Check if we can create an user namespace - err := exec.Command("unshare", "-r", "echo", "hello").Run() - if err != nil { - Skip("User namespaces not supported.") - } - setup := podmanTest.Podman([]string{"create", ALPINE, "ls"}) - setup.WaitWithDefaultTimeout() - Expect(setup.ExitCode()).To(Equal(0)) - cid := setup.OutputToString() - - mount := podmanTest.Podman([]string{"mount", cid}) - mount.WaitWithDefaultTimeout() - Expect(mount.ExitCode()).To(Equal(0)) - mountPath := mount.OutputToString() - - err = filepath.Walk(tempdir, chownFunc) - Expect(err).To(BeNil()) - - tempdir, err := CreateTempDirInTempDir() - Expect(err).To(BeNil()) - rootlessTest := PodmanTestCreate(tempdir) - rootlessTest.CgroupManager = "cgroupfs" - rootlessTest.StorageOptions = ROOTLESS_STORAGE_OPTIONS - err = filepath.Walk(tempdir, chownFunc) - Expect(err).To(BeNil()) - - xdgRuntimeDir, err := ioutil.TempDir("/run", "") - Expect(err).To(BeNil()) - defer os.RemoveAll(xdgRuntimeDir) - err = filepath.Walk(xdgRuntimeDir, chownFunc) - Expect(err).To(BeNil()) - - home, err := CreateTempDirInTempDir() - Expect(err).To(BeNil()) - err = filepath.Walk(home, chownFunc) - Expect(err).To(BeNil()) - - cb(rootlessTest, xdgRuntimeDir, home, mountPath) - - umount := podmanTest.Podman([]string{"umount", cid}) - umount.WaitWithDefaultTimeout() - Expect(umount.ExitCode()).To(Equal(0)) - } - - It("podman rootless pod", func() { - f := func(rootlessTest *PodmanTestIntegration, xdgRuntimeDir string, home string, mountPath string) { - env := os.Environ() - env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", xdgRuntimeDir)) - env = append(env, fmt.Sprintf("HOME=%s", home)) - env = append(env, "USER=foo") - - cmd := rootlessTest.PodmanAsUser([]string{"pod", "create", "--infra=false"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - podId := cmd.OutputToString() - - args := []string{"run", "--pod", podId, "--rootfs", mountPath, "echo", "hello"} - cmd = rootlessTest.PodmanAsUser(args, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - Expect(cmd.LineInOutputContains("hello")).To(BeTrue()) - - args = []string{"pod", "top", podId} - cmd = rootlessTest.PodmanAsUser(args, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Not(Equal(0))) - - args = []string{"run", "--pod", podId, "-d", "--rootfs", mountPath, "sleep", "100"} - cmd = rootlessTest.PodmanAsUser(args, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - args = []string{"pod", "top", podId} - cmd = rootlessTest.PodmanAsUser(args, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - } - runInRootlessContext(f) - }) - - It("podman rootless search", func() { - xdgRuntimeDir, err := ioutil.TempDir("/run", "") - Expect(err).To(BeNil()) - defer os.RemoveAll(xdgRuntimeDir) - err = filepath.Walk(xdgRuntimeDir, chownFunc) - Expect(err).To(BeNil()) - - home, err := CreateTempDirInTempDir() - Expect(err).To(BeNil()) - err = filepath.Walk(home, chownFunc) - Expect(err).To(BeNil()) - - env := os.Environ() - env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", xdgRuntimeDir)) - env = append(env, fmt.Sprintf("HOME=%s", home)) - env = append(env, "USER=foo") - cmd := podmanTest.PodmanAsUser([]string{"search", "docker.io/busybox"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - }) - - runRootlessHelper := func(args []string) { - f := func(rootlessTest *PodmanTestIntegration, xdgRuntimeDir string, home string, mountPath string) { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - env := os.Environ() - env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", xdgRuntimeDir)) - env = append(env, fmt.Sprintf("HOME=%s", home)) - env = append(env, "USER=foo") - - allArgs := append([]string{"run"}, args...) - allArgs = append(allArgs, "--rootfs", mountPath, "echo", "hello") - cmd := rootlessTest.PodmanAsUser(allArgs, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - Expect(cmd.LineInOutputContains("hello")).To(BeTrue()) - - cmd = rootlessTest.PodmanAsUser([]string{"rm", "-l", "-f"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - allArgs = append([]string{"run", "-d"}, args...) - allArgs = append(allArgs, "--security-opt", "seccomp=unconfined", "--rootfs", mountPath, "top") - cmd = rootlessTest.PodmanAsUser(allArgs, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - cmd = rootlessTest.PodmanAsUser([]string{"restart", "-l", "-t", "0"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - canUseExec := canExec() - - if canUseExec { - cmd = rootlessTest.PodmanAsUser([]string{"top", "-l"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - } - - cmd = rootlessTest.PodmanAsUser([]string{"rm", "-l", "-f"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - allArgs = append([]string{"run", "-d"}, args...) - allArgs = append(allArgs, "--security-opt", "seccomp=unconfined", "--rootfs", mountPath, "unshare", "-r", "unshare", "-r", "top") - cmd = rootlessTest.PodmanAsUser(allArgs, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - cmd = rootlessTest.PodmanAsUser([]string{"stop", "-l", "-t", "0"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - cmd = rootlessTest.PodmanAsUser([]string{"inspect", "-l", "--type", "container", "--format", "{{ .State.Status }}"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.LineInOutputContains("exited")).To(BeTrue()) - - cmd = rootlessTest.PodmanAsUser([]string{"start", "-l"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - cmd = rootlessTest.PodmanAsUser([]string{"stop", "-l", "-t", "0"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - cmd = rootlessTest.PodmanAsUser([]string{"start", "-l"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - if len(args) == 0 { - cmd = rootlessTest.PodmanAsUser([]string{"inspect", "-l"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - data := cmd.InspectContainerToJSON() - Expect(data[0].HostConfig.NetworkMode).To(ContainSubstring("slirp4netns")) - } - - if !canUseExec { - Skip("ioctl(NS_GET_PARENT) not supported.") - } - - cmd = rootlessTest.PodmanAsUser([]string{"exec", "-l", "echo", "hello"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - Expect(cmd.LineInOutputContains("hello")).To(BeTrue()) - - cmd = rootlessTest.PodmanAsUser([]string{"ps", "-l", "-q"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - cid := cmd.OutputToString() - - cmd = rootlessTest.PodmanAsUser([]string{"exec", "-l", "sh", "-c", "echo SeCreTMessage > /file"}, 1000, 1000, "", env) - cmd.WaitWithDefaultTimeout() - Expect(cmd.ExitCode()).To(Equal(0)) - - cmd = rootlessTest.PodmanAsUser([]string{"export", "-o", "export.tar", cid}, 1000, 1000, home, env) - cmd.WaitWithDefaultTimeout() - content, err := ioutil.ReadFile(filepath.Join(home, "export.tar")) - Expect(err).To(BeNil()) - Expect(strings.Contains(string(content), "SeCreTMessage")).To(BeTrue()) - } - runInRootlessContext(f) - } - - It("podman rootless rootfs", func() { - runRootlessHelper([]string{}) - }) - - It("podman rootless rootfs --net host", func() { - runRootlessHelper([]string{"--net", "host"}) - }) - - It("podman rootless rootfs --pid host", func() { - runRootlessHelper([]string{"--pid", "host"}) - }) - - It("podman rootless rootfs --privileged", func() { - runRootlessHelper([]string{"--privileged"}) - }) - - It("podman rootless rootfs --net host --privileged", func() { - runRootlessHelper([]string{"--net", "host", "--privileged"}) - }) - - It("podman rootless rootfs --uts host", func() { - runRootlessHelper([]string{"--uts", "host"}) - }) - - It("podman rootless rootfs --ipc host", func() { - runRootlessHelper([]string{"--ipc", "host"}) - }) -}) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 0e1f0d865..f908fe154 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -12,6 +12,7 @@ import ( "time" . "github.com/containers/libpod/test/utils" + "github.com/containers/storage/pkg/stringid" "github.com/mrunalp/fileutils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -106,6 +107,46 @@ var _ = Describe("Podman run", func() { Expect(session.ExitCode()).To(Equal(0)) }) + It("podman run a container with a --rootfs", func() { + rootfs := filepath.Join(tempdir, "rootfs") + uls := filepath.Join("/", "usr", "local", "share") + uniqueString := stringid.GenerateNonCryptoID() + testFilePath := filepath.Join(uls, uniqueString) + tarball := filepath.Join(tempdir, "rootfs.tar") + + err := os.Mkdir(rootfs, 0770) + Expect(err).Should(BeNil()) + + // Change image in predictable way to validate export + csession := podmanTest.Podman([]string{"run", "--name", uniqueString, ALPINE, + "/bin/sh", "-c", fmt.Sprintf("echo %s > %s", uniqueString, testFilePath)}) + csession.WaitWithDefaultTimeout() + Expect(csession.ExitCode()).To(Equal(0)) + + // Export from working container image guarantees working root + esession := podmanTest.Podman([]string{"export", "--output", tarball, uniqueString}) + esession.WaitWithDefaultTimeout() + Expect(esession.ExitCode()).To(Equal(0)) + Expect(tarball).Should(BeARegularFile()) + + // N/B: This will loose any extended attributes like SELinux types + fmt.Fprintf(os.Stderr, "Extracting container root tarball\n") + tarsession := SystemExec("tar", []string{"xf", tarball, "-C", rootfs}) + Expect(tarsession.ExitCode()).To(Equal(0)) + Expect(filepath.Join(rootfs, uls)).Should(BeADirectory()) + + // Other tests confirm SELinux types, just confirm --rootfs is working. + session := podmanTest.Podman([]string{"run", "-i", "--security-opt", "label=disable", + "--rootfs", rootfs, "cat", testFilePath}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + // Validate changes made in original container and export + stdoutLines := session.OutputToStringArray() + Expect(stdoutLines).Should(HaveLen(1)) + Expect(stdoutLines[0]).Should(Equal(uniqueString)) + }) + It("podman run a container with --init", func() { session := podmanTest.Podman([]string{"run", "--init", ALPINE, "ls"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/unshare_test.go b/test/e2e/unshare_test.go new file mode 100644 index 000000000..1e3f06a62 --- /dev/null +++ b/test/e2e/unshare_test.go @@ -0,0 +1,52 @@ +package integration + +import ( + "os" + + . "github.com/containers/libpod/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman unshare", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + BeforeEach(func() { + SkipIfRemote() + if _, err := os.Stat("/proc/self/uid_map"); err != nil { + Skip("User namespaces not supported.") + } + + if os.Geteuid() == 0 { + Skip("Use unshare in rootless only") + } + + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.CgroupManager = "cgroupfs" + podmanTest.StorageOptions = ROOTLESS_STORAGE_OPTIONS + podmanTest.Setup() + podmanTest.RestoreAllArtifacts() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + }) + + It("podman unshare", func() { + userNS, _ := os.Readlink("/proc/self/ns/user") + session := podmanTest.Podman([]string{"unshare", "readlink", "/proc/self/ns/user"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + ok, _ := session.GrepString(userNS) + Expect(ok).To(BeFalse()) + }) +}) diff --git a/transfer.md b/transfer.md index df91cdf21..79b6d3461 100644 --- a/transfer.md +++ b/transfer.md @@ -98,7 +98,7 @@ Those Docker commands currently do not have equivalents in `podman`: | `docker secret` || | `docker service` || | `docker stack` || -| `docker swarm` | podman does not support swarm. We support Kubernetes for orchestration using [CRI-O](https://github.com/kubernetes-sigs/cri-o).| +| `docker swarm` | podman does not support swarm. We support Kubernetes for orchestration using [CRI-O](https://github.com/cri-o/cri-o).| | `docker volume` | podman currently supports file volumes. Future enhancement planned to support Docker Volumes Plugins ## Missing commands in Docker diff --git a/vendor.conf b/vendor.conf index b71e947dc..0b1f13304 100644 --- a/vendor.conf +++ b/vendor.conf @@ -19,7 +19,7 @@ github.com/containers/image v1.5.1 github.com/vbauerster/mpb v3.3.4 github.com/mattn/go-isatty v0.0.4 github.com/VividCortex/ewma v1.1.1 -github.com/containers/storage v1.12.6 +github.com/containers/storage v1.12.7 github.com/containers/psgo v1.2.1 github.com/coreos/go-systemd v14 github.com/coreos/pkg v4 diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go index 7bec0aea6..a35dd476b 100644 --- a/vendor/github.com/containers/storage/layers.go +++ b/vendor/github.com/containers/storage/layers.go @@ -402,12 +402,10 @@ func (r *layerStore) Save() error { if err != nil { return err } + defer r.Touch() if err := ioutils.AtomicWriteFile(rpath, jldata, 0600); err != nil { return err } - if !r.IsReadWrite() { - return nil - } r.mountsLockfile.Lock() defer r.mountsLockfile.Unlock() defer r.mountsLockfile.Touch() diff --git a/vendor/github.com/containers/storage/layers_ffjson.go b/vendor/github.com/containers/storage/layers_ffjson.go index 125b5d8c9..09b5d0f33 100644 --- a/vendor/github.com/containers/storage/layers_ffjson.go +++ b/vendor/github.com/containers/storage/layers_ffjson.go @@ -1,5 +1,5 @@ // Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT. -// source: layers.go +// source: ./layers.go package storage diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go index 27b00f6fe..9b967db6d 100644 --- a/vendor/github.com/containers/storage/store.go +++ b/vendor/github.com/containers/storage/store.go @@ -1197,18 +1197,20 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat } imageID = cimage.ID - createMappedLayer := imageHomeStore == istore + if cimage.TopLayer != "" { + createMappedLayer := imageHomeStore == istore + ilayer, err := s.imageTopLayerForMapping(cimage, imageHomeStore, createMappedLayer, rlstore, lstores, idMappingsOptions) + if err != nil { + return nil, err + } + imageTopLayer = ilayer - ilayer, err := s.imageTopLayerForMapping(cimage, imageHomeStore, createMappedLayer, rlstore, lstores, idMappingsOptions) - if err != nil { - return nil, err - } - imageTopLayer = ilayer - if !options.HostUIDMapping && len(options.UIDMap) == 0 { - uidMap = ilayer.UIDMap - } - if !options.HostGIDMapping && len(options.GIDMap) == 0 { - gidMap = ilayer.GIDMap + if !options.HostUIDMapping && len(options.UIDMap) == 0 { + uidMap = ilayer.UIDMap + } + if !options.HostGIDMapping && len(options.GIDMap) == 0 { + gidMap = ilayer.GIDMap + } } } else { rlstore.Lock() diff --git a/version/version.go b/version/version.go index c63f8b820..a917931b7 100644 --- a/version/version.go +++ b/version/version.go @@ -4,7 +4,7 @@ package version // NOTE: remember to bump the version at the top // of the top-level README.md file when this is // bumped. -const Version = "1.3.1-dev" +const Version = "1.3.2-dev" // RemoteAPIVersion is the version for the remote // client API. It is used to determine compatibility |