diff options
100 files changed, 917 insertions, 268 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index b1aa1b475..37c9108eb 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -39,7 +39,7 @@ env: UBUNTU_NAME: "ubuntu-20" PRIOR_UBUNTU_NAME: "ubuntu-19" - _BUILT_IMAGE_SUFFIX: "libpod-6508632441356288" + _BUILT_IMAGE_SUFFIX: "podman-5869602141896704" FEDORA_CACHE_IMAGE_NAME: "${FEDORA_NAME}-${_BUILT_IMAGE_SUFFIX}" PRIOR_FEDORA_CACHE_IMAGE_NAME: "${PRIOR_FEDORA_NAME}-${_BUILT_IMAGE_SUFFIX}" UBUNTU_CACHE_IMAGE_NAME: "${UBUNTU_NAME}-${_BUILT_IMAGE_SUFFIX}" @@ -71,7 +71,7 @@ env: # Service-account client_email - needed to build images SERVICE_ACCOUNT: ENCRYPTED[702a8e07e27a6faf7988fcddcc068c2ef2bb182a5aa671f5ccb7fbbfb891c823aa4a7856fb17240766845dbd68bd3f90] # Service account username part of client_email - for ssh'ing into VMs - GCE_SSH_USERNAME: ENCRYPTED[d579f2d3000bb678c9af37c3615e92bcf3726e9afc47748c129cef23ee799faaafd4baba64048329205d162069d90060] + GCE_SSH_USERNAME: 'cirrus-ci' # Default VM to use unless set or modified by task gce_instance: diff --git a/.gitignore b/.gitignore index f0fdf4dc8..434a12759 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ /conmon/ contrib/spec/podman.spec *.coverprofile +coverprofile +/.coverage /docs/*.[158] /docs/*.[158].gz /docs/build/ @@ -2,6 +2,7 @@ export GO111MODULE=off export GOPROXY=https://proxy.golang.org GO ?= go +COVERAGE_PATH ?= .coverage DESTDIR ?= EPOCH_TEST_COMMIT ?= $(shell git merge-base $${DEST_BRANCH:-master} HEAD) HEAD ?= HEAD @@ -308,14 +309,20 @@ testunit: libpodimage ## Run unittest on the built image .PHONY: localunit localunit: test/goecho/goecho varlink_generate hack/check_root.sh make localunit + rm -rf ${COVERAGE_PATH} && mkdir -p ${COVERAGE_PATH} ginkgo \ -r \ $(TESTFLAGS) \ --skipPackage test/e2e,pkg/apparmor,test/endpoint,pkg/bindings,hack \ --cover \ --covermode atomic \ + --coverprofile coverprofile \ + --outputdir ${COVERAGE_PATH} \ --tags "$(BUILDTAGS)" \ --succinct + $(GO) tool cover -html=${COVERAGE_PATH}/coverprofile -o ${COVERAGE_PATH}/coverage.html + $(GO) tool cover -func=${COVERAGE_PATH}/coverprofile > ${COVERAGE_PATH}/functions + cat ${COVERAGE_PATH}/functions | sed -n 's/\(total:\).*\([0-9][0-9].[0-9]\)/\1 \2/p' .PHONY: ginkgo ginkgo: @@ -1,11 +1,11 @@ ![PODMAN logo](logo/podman-logo-source.svg) -# Library and tool for running OCI-based containers in Pods +# Podman: A tool for managing OCI containers and pods -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. +Podman (the POD MANager) is a tool for managing containers and images, volumes mounted into those containers, and pods made from groups of containers. +Podman is based on libpod, a library for container lifecycle management that is also contained in this repository. The libpod library provides APIs for managing containers, pods, container images, and volumes. -* [Latest Version: 2.0.2](https://github.com/containers/libpod/releases/latest) +* [Latest Version: 2.0.3](https://github.com/containers/libpod/releases/latest) * Latest Remote client for Windows * Latest Remote client for MacOs * Latest Static Remote client for Linux @@ -15,26 +15,24 @@ popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)` ## Overview and scope -At a high level, the scope of libpod and Podman is the following: +At a high level, the scope of Podman and libpod 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. -* Container image management (managing image layers, overlay filesystems, etc). -* Full management of container lifecycle. -* Support for pods to manage groups of containers together. +* Support for multiple container image formats, including OCI and Docker images. +* Full management of those images, including pulling from various sources (including trust and verification), creating (built via Containerfile or Dockerfile or committed from a container), and pushing to registries and other storage backends. +* Full management of container lifecycle, including creation (both from an image and from an exploded root filesystem), running, checkpointing and restoring (via CRIU), and removal. +* Support for pods, groups of containers that share resources and are managed together. * Resource isolation of containers and pods. -* Support for a Docker-compatible CLI interface through Podman. +* Support for a Docker-compatible CLI interface. * Support for a REST API providing both a Docker-compatible interface and an improved interface exposing advanced Podman functionality. -* Integration with CRI-O to share containers and backend code. +* In the future, integration with [CRI-O](https://github.com/cri-o/cri-o) to share containers and backend code. Podman presently only supports running containers on Linux. However, we are building a remote client which can run on Windows and OS X and manage Podman containers on a Linux system via the REST API using SSH tunneling. ## Roadmap -1. Complete the Podman REST API and Podman v2, which will be able to connect to remote Podman instances via this API -1. Integrate libpod into CRI-O to replace its existing container management backend -1. Further work on the podman pod command -1. Further improvements on rootless containers +1. Further improvements to the REST API, with a focus on bugfixes and implementing missing functionality +1. Integrate libpod into [CRI-O](https://github.com/cri-o/cri-o) to replace its existing container management backend +1. Improvements on rootless containers, with a focus on improving the user experience and exposing presently-unavailable features when possible ## Communications @@ -67,10 +65,10 @@ A little configuration by an administrator is required before rootless Podman ca ## Out of scope -* Specializing in signing and pushing images to various storage backends. +* Specialized signing and pushing of 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/cri-o/cri-o) specializes in that. +* Support for the Kubernetes CRI interface for container management. + The [CRI-O](https://github.com/cri-o/cri-o) daemon 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 diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 898a09d70..96ee8a02c 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,43 @@ # Release Notes +## 2.0.3 +### Features +- The `podman search` command now allows wildcards in search terms. +- The `podman play kube` command now supports the `IfNotPresent` pull type. + +### Changes +- The `--disable-content-trust` flag has been added to Podman for Docker compatibility. This is a Docker-specific option and has no effect in Podman; it is provided only to ensure command line compatibility for scripts ([#7034](https://github.com/containers/podman/issues/7034)). +- Setting a static IP address or MAC address for rootless containers and pods now causes an error; previously, they were silently ignored. +- The `/sys/dev` folder is now masked in containers to prevent a potential information leak from the host. + +### Bugfixes +- Fixed a bug where rootless Podman would select the wrong cgroup manager on cgroups v1 systems where the user in question had an active systemd user session ([#6982](https://github.com/containers/podman/issues/6982)). +- Fixed a bug where systems with Apparmor could not run privileged containers ([#6933](https://github.com/containers/podman/issues/6933)). +- Fixed a bug where ENTRYPOINT and CMD from images were improperly handled by `podman play kube` ([#6995](https://github.com/containers/podman/issues/6995)). +- Fixed a bug where the `--pids-limit` flag to `podman create` and `podman run` was parsed incorrectly and was unusable ([#6908](https://github.com/containers/podman/issues/6908)). +- Fixed a bug where the `podman system df` command would error if untagged images were present ([#7015](https://github.com/containers/podman/issues/7015)). +- Fixed a bug where the `podman images` command would display incorrect tags if a port number was included in the repository. +- Fixed a bug where Podman did not set a default umask and default rlimits ([#6989](https://github.com/containers/podman/issues/6989)). +- Fixed a bug where protocols in port mappings were not recognized unless they were lower-case ([#6948](https://github.com/containers/podman/issues/6948)). +- Fixed a bug where information on pod infra containers was not included in the output of `podman pod inspect`. +- Fixed a bug where Podman's systemd detection (activated by the enabled-by-default `--systemd=true` flag) would not flag a container for systemd mode if systemd was part of the entrypoint, not the command ([#6920](https://github.com/containers/podman/issues/6920)). +- Fixed a bug where `podman start --attach` was not defaulting `--sig-proxy` to true ([#6928](https://github.com/containers/podman/issues/6928)). +- Fixed a bug where `podman inspect` would show an incorrect command (`podman system service`, the command used to start the server) for containers created by a remote Podman client. +- Fixed a bug where the `podman exec` command with the remote client would not print output if the `-t` or `-i` flags where not provided. +- Fixed a bug where some variations of the `--format {{ json . }}` to `podman info` (involving added or removed whitespace) would not be accepted ([#6927](https://github.com/containers/podman/issues/6927)). +- Fixed a bug where Entrypoint could not be cleared at the command line (if unset via `--entrypoint=""`, it would be reset to the image's entrypoint) ([#6935](https://github.com/containers/podman/issues/6935)). + +### API +- Fixed a bug where the events endpoints (both libpod and compat) could potentially panic on parsing filters. +- Fixed a bug where the compat Create endpoint for containers did not properly handle Entrypoint and Command. +- Fixed a bug where the Logs endpoint for containers (both libpod and compat) would not properly handle client disconnect, resulting in high CPU usage. +- The type of filters on the compat events endpoint has been adjusted to match Docker's implementation ([#6899](https://github.com/containers/podman/issues/6899)). +- The idle connection counter now properly handles hijacked connections. +- All endpoints that hijack will now properly print headers per RFC 7230 standards. + +### Misc +- Updated containers/common to v0.14.6 + ## 2.0.2 ### Changes - The `podman system connection` command has been temporarily disabled, as it was not functioning as expected. diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index a26bbf718..e248e621f 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -155,6 +155,10 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { "device-write-iops", []string{}, "Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)", ) + createFlags.Bool( + "disable-content-trust", false, + "This is a Docker specific option and is a NOOP", + ) createFlags.String("entrypoint", "", "Overwrite the default ENTRYPOINT of the image", ) @@ -401,7 +405,7 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { ) createFlags.StringArrayVar( &cf.SecurityOpt, - "security-opt", containerConfig.SecurityOptions(), + "security-opt", []string{}, "Security Options", ) createFlags.String( @@ -459,6 +463,11 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { "tz", containerConfig.TZ(), "Set timezone in container", ) + createFlags.StringVar( + &cf.Umask, + "umask", containerConfig.Umask(), + "Set umask in container", + ) createFlags.StringSliceVar( &cf.UIDMap, "uidmap", []string{}, diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index a544846aa..2bea8b0b4 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -93,6 +93,7 @@ type ContainerCLIOpts struct { TmpFS []string TTY bool Timezone string + Umask string UIDMap []string Ulimit []string User string diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index 416c6f6ec..e694317cc 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -512,10 +512,8 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string s.ContainerSecurityConfig.SelinuxOpts = append(s.ContainerSecurityConfig.SelinuxOpts, con[1]) s.Annotations[define.InspectAnnotationLabel] = strings.Join(s.ContainerSecurityConfig.SelinuxOpts, ",label=") case "apparmor": - if !c.Privileged { - s.ContainerSecurityConfig.ApparmorProfile = con[1] - s.Annotations[define.InspectAnnotationApparmor] = con[1] - } + s.ContainerSecurityConfig.ApparmorProfile = con[1] + s.Annotations[define.InspectAnnotationApparmor] = con[1] case "seccomp": s.SeccompProfilePath = con[1] s.Annotations[define.InspectAnnotationSeccomp] = con[1] @@ -613,6 +611,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string s.Remove = c.Rm s.StopTimeout = &c.StopTimeout s.Timezone = c.Timezone + s.Umask = c.Umask return nil } diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go index 83bb186df..c10a351d8 100644 --- a/cmd/podman/images/pull.go +++ b/cmd/podman/images/pull.go @@ -82,6 +82,7 @@ func pullFlags(flags *pflag.FlagSet) { flags.StringVar(&pullOptions.CredentialsCLI, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") flags.StringVar(&pullOptions.OverrideArch, "override-arch", "", "Use `ARCH` instead of the architecture of the machine for choosing images") flags.StringVar(&pullOptions.OverrideOS, "override-os", "", "Use `OS` instead of the running OS for choosing images") + flags.Bool("disable-content-trust", false, "This is a Docker specific option and is a NOOP") flags.BoolVarP(&pullOptions.Quiet, "quiet", "q", false, "Suppress output information when pulling images") flags.StringVar(&pullOptions.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") flags.BoolVar(&pullOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") diff --git a/cmd/podman/images/push.go b/cmd/podman/images/push.go index 4eeed13d4..480b5e0f0 100644 --- a/cmd/podman/images/push.go +++ b/cmd/podman/images/push.go @@ -79,6 +79,7 @@ func pushFlags(flags *pflag.FlagSet) { flags.BoolVar(&pushOptions.Compress, "compress", false, "Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)") flags.StringVar(&pushOptions.CredentialsCLI, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") flags.StringVar(&pushOptions.DigestFile, "digestfile", "", "Write the digest of the pushed image to the specified file") + flags.Bool("disable-content-trust", false, "This is a Docker specific option and is a NOOP") flags.StringVarP(&pushOptions.Format, "format", "f", "", "Manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir' transport (default is manifest type of source)") flags.BoolVarP(&pushOptions.Quiet, "quiet", "q", false, "Suppress output information when pushing images") flags.BoolVar(&pushOptions.RemoveSignatures, "remove-signatures", false, "Discard any pre-existing signatures in the image") diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go index a7e368115..f5a231172 100644 --- a/cmd/podman/registry/config.go +++ b/cmd/podman/registry/config.go @@ -44,11 +44,12 @@ func newPodmanConfig() { case "linux": // Some linux clients might only be compiled without ABI // support (e.g., podman-remote). - if abiSupport && !remoteOverride { + if abiSupport && !IsRemote() { mode = entities.ABIMode } else { mode = entities.TunnelMode } + default: fmt.Fprintf(os.Stderr, "%s is not a supported OS", runtime.GOOS) os.Exit(1) diff --git a/completions/bash/podman b/completions/bash/podman index 458090ac4..eb727ef63 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -2119,12 +2119,13 @@ _podman_container_run() { --shm-size --stop-signal --stop-timeout - --tmpfs - --tz --subgidname --subuidname --sysctl --systemd + --tmpfs + --tz + --umask --uidmap --ulimit --user -u diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index 2375d512e..91eeb7a7f 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -299,13 +299,13 @@ is_release() { } setup_rootless() { - req_env_var ROOTLESS_USER GOSRC SECRET_ENV_RE ROOTLESS_ENV_RE + req_env_var ROOTLESS_USER GOPATH GOSRC SECRET_ENV_RE ROOTLESS_ENV_RE # Only do this once if passwd --status $ROOTLESS_USER then echo "Updating $ROOTLESS_USER user permissions on possibly changed libpod code" - chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOSRC" + chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOPATH" "$GOSRC" return 0 fi @@ -316,7 +316,7 @@ setup_rootless() { echo "creating $ROOTLESS_UID:$ROOTLESS_GID $ROOTLESS_USER user" groupadd -g $ROOTLESS_GID $ROOTLESS_USER useradd -g $ROOTLESS_GID -u $ROOTLESS_UID --no-user-group --create-home $ROOTLESS_USER - chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOSRC" + chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOPATH" "$GOSRC" echo "creating ssh keypair for $USER" [[ -r "$HOME/.ssh/id_rsa" ]] || \ diff --git a/contrib/cirrus/logformatter b/contrib/cirrus/logformatter index 60c1e5985..b56a829c5 100755 --- a/contrib/cirrus/logformatter +++ b/contrib/cirrus/logformatter @@ -303,14 +303,15 @@ END_HTML # (bindings test sometimes emits 'Running' with leading bullet char) elsif ($line =~ /^•?Running:/) { # Highlight the important (non-boilerplate) podman command. + $line =~ s/\s+--remote\s+/ /g; # --remote takes no args # Strip out the global podman options, but show them on hover - $line =~ s{(\S+\/podman)((\s+--(root|runroot|runtime|tmpdir|storage-opt|conmon|cgroup-manager|cni-config-dir|storage-driver|events-backend) \S+)*)(.*)}{ - my ($full_path, $options, $args) = ($1, $2, $5); + $line =~ s{(\S+\/podman(-remote)?)((\s+--(root|runroot|runtime|tmpdir|storage-opt|conmon|cgroup-manager|cni-config-dir|storage-driver|events-backend|url) \S+)*)(.*)}{ + my ($full_path, $remote, $options, $args) = ($1, $2||'', $3, $6); $options =~ s/^\s+//; # Separate each '--foo bar' with newlines for readability $options =~ s/ --/\n--/g; - qq{<span title="$full_path"><b>podman</b></span> <span class=\"boring\" title=\"$options\">[options]</span><b>$args</b>}; + qq{<span title="$full_path"><b>podman$remote</b></span> <span class=\"boring\" title=\"$options\">[options]</span><b>$args</b>}; }e; $current_output = ''; } @@ -418,10 +419,27 @@ END_HTML } } - # FIXME: if Cirrus magic envariables are available, write a link to results + # If Cirrus magic envariables are available, write a link to results. + # FIXME: it'd be so nice to make this a clickable live link. + # + # STATIC_MAGIC_BLOB is the name of a google-storage bucket. It is + # unlikely to change often, but if it does you will suddenly start + # seeing errors when trying to view formatted logs: + # + # AccessDeniedAccess denied.Anonymous caller does not have storage.objects.get access to the Google Cloud Storage object. + # + # This happened in July 2020 when github.com/containers/libpod was + # renamed to podman. If something like that ever happens again, you + # will need to get the new magic blob value from: + # + # https://console.cloud.google.com/storage/browser?project=libpod-218412 + # + # You will also probably need to set the bucket Public by clicking on + # the bucket name, then the Permissions tab. This is safe, since this + # project is fully open-source. if ($have_formatted_log && $ENV{CIRRUS_TASK_ID}) { my $URL_BASE = "https://storage.googleapis.com"; - my $STATIC_MAGIC_BLOB = "cirrus-ci-5385732420009984-fcae48"; + my $STATIC_MAGIC_BLOB = "cirrus-ci-6707778565701632-fcae48"; my $ARTIFACT_NAME = "html"; my $URL = "${URL_BASE}/${STATIC_MAGIC_BLOB}/artifacts/$ENV{CIRRUS_REPO_FULL_NAME}/$ENV{CIRRUS_TASK_ID}/${ARTIFACT_NAME}/${outfile}"; diff --git a/contrib/cirrus/logformatter.t b/contrib/cirrus/logformatter.t index d2193cc6c..440299cc2 100755 --- a/contrib/cirrus/logformatter.t +++ b/contrib/cirrus/logformatter.t @@ -132,6 +132,8 @@ $SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP} [+0103s] /var/tmp/go/src/github.com/containers/libpod/test/e2e/pod_restart_test.go:28 [+0103s] Running: /var/tmp/go/src/github.com/containers/libpod/bin/podman --storage-opt vfs.imagestore=/tmp/podman/imagecachedir --root /tmp/podman_test553496330/crio --runroot /tmp/podman_test553496330/crio-run --runtime /usr/bin/runc --conmon /usr/bin/conmon --cni-config-dir /etc/cni/net.d --cgroup-manager systemd --tmpdir /tmp/podman_test553496330 --events-backend file --storage-driver vfs pod rm -fa [+0103s] 4810be0cfbd42241e349dbe7d50fbc54405cd320a6637c65fd5323f34d64af89 +[+0104s] Running: /var/tmp/go/src/github.com/containers/libpod/bin/podman-remote --storage-opt vfs.imagestore=/tmp/podman/imagecachedir --root /tmp/podman_test553496330/crio --runroot /tmp/podman_test553496330/crio-run --runtime /usr/bin/runc --conmon /usr/bin/conmon --cni-config-dir /etc/cni/net.d --cgroup-manager systemd --tmpdir /tmp/podman_test553496330 --events-backend file --storage-driver vfs --remote --url unix:/run/user/12345/podman-xyz.sock pod rm -fa +[+0104s] 4810be0cfbd42241e349dbe7d50fbc54405cd320a6637c65fd5323f34d64af89 again [+0107s] • [+0107s] ------------------------------ [+0107s] podman system reset @@ -186,6 +188,21 @@ $SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP} --events-backend file --storage-driver vfs">[options]</span><b> pod rm -fa</b> <span class="timestamp"> </span>4810be0cfbd42241e349dbe7d50fbc54405cd320a6637c65fd5323f34d64af89 + +<span class="timestamp">[+0104s] </span>Running: <span title="/var/tmp/go/src/github.com/containers/libpod/bin/podman-remote"><b>podman-remote</b></span> <span class="boring" title="--storage-opt vfs.imagestore=/tmp/podman/imagecachedir +--root /tmp/podman_test553496330/crio +--runroot /tmp/podman_test553496330/crio-run +--runtime /usr/bin/runc +--conmon /usr/bin/conmon +--cni-config-dir /etc/cni/net.d +--cgroup-manager systemd +--tmpdir /tmp/podman_test553496330 +--events-backend file +--storage-driver vfs +--url unix:/run/user/12345/podman-xyz.sock">[options]</span><b> pod rm -fa</b> +<span class="timestamp"> </span>4810be0cfbd42241e349dbe7d50fbc54405cd320a6637c65fd5323f34d64af89 again + + <span class="timestamp">[+0107s] </span>• </pre> <hr /> diff --git a/contrib/cirrus/packer/Makefile b/contrib/cirrus/packer/Makefile index a911cafdb..c5a8e4cac 100644 --- a/contrib/cirrus/packer/Makefile +++ b/contrib/cirrus/packer/Makefile @@ -5,7 +5,8 @@ PACKER_DIST_FILENAME := packer_${PACKER_VER}_linux_${GOARCH}.zip # Only needed for libpod_base_images target TIMESTAMP := $(shell date +%s) -GOSRC ?= $(shell realpath "./../../../") +GOPATH ?= /var/tmp/go +GOSRC ?= $(GOPATH)/src/github.com/containers/libpod PACKER_BASE ?= contrib/cirrus/packer SCRIPT_BASE ?= contrib/cirrus POST_MERGE_BUCKET_SUFFIX ?= @@ -54,6 +55,7 @@ libpod_images: guard-PACKER_BUILDS libpod_images.json packer ./packer build \ -force \ $(shell test -z "${PACKER_BUILDS}" || echo "-only=${PACKER_BUILDS}") \ + -var GOPATH=$(GOPATH) \ -var GOSRC=$(GOSRC) \ -var PACKER_BASE=$(PACKER_BASE) \ -var SCRIPT_BASE=$(SCRIPT_BASE) \ diff --git a/contrib/cirrus/packer/fedora_packaging.sh b/contrib/cirrus/packer/fedora_packaging.sh index aecaaef93..b4a3a2062 100644 --- a/contrib/cirrus/packer/fedora_packaging.sh +++ b/contrib/cirrus/packer/fedora_packaging.sh @@ -74,6 +74,7 @@ INSTALL_PACKAGES=(\ gpgme-devel grubby hostname + httpd-tools iproute iptables jq @@ -168,5 +169,9 @@ fi echo "Installing runtime tooling" # Save some runtime by having these already available cd $GOSRC +# Required since initially go was not installed +source $GOSRC/$SCRIPT_BASE/lib.sh +echo "Go environment has been setup:" +go env $SUDO make install.tools $SUDO $GOSRC/hack/install_catatonit.sh diff --git a/contrib/cirrus/packer/libpod_images.yml b/contrib/cirrus/packer/libpod_images.yml index 754626a2e..38f5a8250 100644 --- a/contrib/cirrus/packer/libpod_images.yml +++ b/contrib/cirrus/packer/libpod_images.yml @@ -3,6 +3,7 @@ # All of these are required variables: BUILT_IMAGE_SUFFIX: '{{env `BUILT_IMAGE_SUFFIX`}}' + GOPATH: '{{env `GOPATH`}}' GOSRC: '{{env `GOSRC`}}' PACKER_BASE: '{{env `PACKER_BASE`}}' SCRIPT_BASE: '{{env `SCRIPT_BASE`}}' @@ -62,15 +63,22 @@ builders: # The brains of the operation, making actual modifications to the base-image. provisioners: + - type: 'shell' + inline: + - 'set -ex' + # The 'file' provisioner item (below) will create the final component + - 'mkdir -vp $(dirname {{user `GOSRC`}})' + - type: 'file' source: '{{user `GOSRC`}}' - destination: '/tmp/libpod' + destination: '{{user `GOSRC`}}' - type: 'shell' script: '{{user `GOSRC`}}/{{user `PACKER_BASE`}}/{{split build_name "-" 0}}_setup.sh' environment_vars: - 'PACKER_BUILDER_NAME={{build_name}}' - - 'GOSRC=/tmp/libpod' + - 'GOPATH={{user `GOPATH`}}' + - 'GOSRC={{user `GOSRC`}}' - 'PACKER_BASE={{user `PACKER_BASE`}}' - 'SCRIPT_BASE={{user `SCRIPT_BASE`}}' diff --git a/contrib/cirrus/packer/ubuntu_packaging.sh b/contrib/cirrus/packer/ubuntu_packaging.sh index 09f9aab9f..d11c612c5 100644 --- a/contrib/cirrus/packer/ubuntu_packaging.sh +++ b/contrib/cirrus/packer/ubuntu_packaging.sh @@ -36,6 +36,7 @@ ooe.sh curl -L -o /tmp/Release.key "https://download.opensuse.org/repositories/d ooe.sh $SUDO apt-key add - < /tmp/Release.key INSTALL_PACKAGES=(\ + apache2-utils apparmor aufs-tools autoconf @@ -153,7 +154,12 @@ if [[ ${#DOWNLOAD_PACKAGES[@]} -gt 0 ]]; then fi echo "Installing runtime tooling" +# Save some runtime by having these already available cd $GOSRC +# Required since initially go was not installed +source $GOSRC/$SCRIPT_BASE/lib.sh +echo "Go environment has been setup:" +go env $SUDO hack/install_catatonit.sh $SUDO make install.libseccomp.sudo $SUDO make install.tools diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index ea2c7d8e0..fbdae83fa 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -41,7 +41,6 @@ case "${OS_RELEASE_ID}" in ubuntu) apt-get update apt-get install -y containers-common - sed -ie 's/^\(# \)\?apparmor_profile =.*/apparmor_profile = ""/' /etc/containers/containers.conf if [[ "$OS_RELEASE_VER" == "19" ]]; then apt-get purge -y --auto-remove golang* apt-get install -y golang-1.13 diff --git a/docs/source/index.rst b/docs/source/index.rst index 18a5554ca..715ca2744 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,13 +2,13 @@ What is Podman? ================================== -Podman_ is a daemonless, open source, Linux native tool designed to make it easy to find, run, build, share and deploy applications using Open Containers Initiative (OCI_) Containers_ and `Container Images`_. Podman provides a command line interface (CLI) familiar to anyone who has used the Docker `Container Engine`_. Most users can simply alias Docker to Podman (`alias docker=podman`) without any problems. Similar to other common `Container Engines`_ (Docker, CRI-O, containerd), Podman relies on an OCI compliant `Container Runtime`_ (runc, crun, runv, etc) to interface with the operating system and create the running containers.This makes the running containers created by Podman nearly indistinguishable from those created by any other common container engine. +Podman_ is a daemonless, open source, Linux native tool designed to make it easy to find, run, build, share and deploy applications using Open Containers Initiative (OCI_) Containers_ and `Container Images`_. Podman provides a command line interface (CLI) familiar to anyone who has used the Docker `Container Engine`_. Most users can simply alias Docker to Podman (`alias docker=podman`) without any problems. Similar to other common `Container Engines`_ (Docker, CRI-O, containerd), Podman relies on an OCI compliant `Container Runtime`_ (runc, crun, runv, etc) to interface with the operating system and create the running containers. This makes the running containers created by Podman nearly indistinguishable from those created by any other common container engine. Containers under the control of Podman can either be run by root or by a non-privileged user. Podman manages the entire container ecosystem which includes pods, containers, container images, and container volumes using the libpod_ library. Podman specializes in all of the commands and functions that help you to maintain and modify OCI container images, such as pulling and tagging. It allows you to create, run, and maintain those containers and container images in a production environment. The Podman service runs only on Linux platforms, however a REST API and clients are currently under development which will allow Mac and Windows platforms to call the service. There is currently a RESTful based remote client which runs on Mac or Windows platforms that allows the remote client to talk to the Podman server on a Linux platform. In addition to those clients, there is also a Mac client. -If you are completely new to containers, we recommend that you check out the :doc:`Introduction`. For power users or those comming from Docker, check out our :doc:`Tutorials`. For advanced users and contributors, you can get very detailed information about the Podman CLI by looking our :doc:`Commands` page. Finally, for Developers looking at how to interact with the Podman API, please see our API documentation :doc:`Reference`. +If you are completely new to containers, we recommend that you check out the :doc:`Introduction`. For power users or those coming from Docker, check out our :doc:`Tutorials`. For advanced users and contributors, you can get very detailed information about the Podman CLI by looking at our :doc:`Commands` page. Finally, for Developers looking at how to interact with the Podman API, please see our API documentation :doc:`Reference`. .. toctree:: :maxdepth: 2 diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index a422dd184..b4456225e 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -234,6 +234,12 @@ Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sd Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000) +**--disable-content-trust** + +This is a Docker specific option to disable image verification to a Docker +registry and is not supported by Podman. This flag is a NOOP and provided +solely for scripting compatibility. + **--dns**=*dns* Set custom DNS servers. Invalid if using **--dns** and **--network** that is set to 'none' or 'container:<name|id>'. @@ -833,6 +839,10 @@ standard input. Set timezone in container. This flag takes area-based timezones, GMT time, as well as `local`, which sets the timezone in the container to match the host machine. See `/usr/share/zoneinfo/` for valid timezones. +**--umask**=*umask* + +Set the umask inside the container. Defaults to `0022`. + **--uidmap**=*container_uid:host_uid:amount* UID map for the user namespace. Using this flag will run the container with user namespace enabled. It conflicts with the `--userns` and `--subuidname` flags. @@ -1120,14 +1130,13 @@ required for VPN, without it containers need to be run with the --network=host f Environment variables within containers can be set using multiple different options: This section describes the precedence. -Precedence Order: - **--env-host** : Host environment of the process executing Podman is added. - - Container image : Any environment variables specified in the container image. - - **--env-file** : Any environment variables specified via env-files. If multiple files specified, then they override each other in order of entry. +Precedence order (later entries override earlier entries): - **--env** : Any environment variables specified will override previous settings. +- **--env-host** : Host environment of the process executing Podman is added. +- **--http-proxy**: By default, several environment variables will be passed in from the host, such as **http_proxy** and **no_proxy**. See **--http-proxy** for details. +- Container image : Any environment variables specified in the container image. +- **--env-file** : Any environment variables specified via env-files. If multiple files specified, then they override each other in order of entry. +- **--env** : Any environment variables specified will override previous settings. Create containers and set the environment ending with a __*__ and a ***** diff --git a/docs/source/markdown/podman-pull.1.md b/docs/source/markdown/podman-pull.1.md index 5d941219a..201b10aa6 100644 --- a/docs/source/markdown/podman-pull.1.md +++ b/docs/source/markdown/podman-pull.1.md @@ -73,6 +73,12 @@ The [username[:password]] to use to authenticate with the registry if required. If one or both values are not supplied, a command line prompt will appear and the value can be entered. The password is entered without echo. +**--disable-content-trust** + +This is a Docker specific option to disable image verification to a Docker +registry and is not supported by Podman. This flag is a NOOP and provided +solely for scripting compatibility. + **--override-os**=*OS* Use OS instead of the running OS for choosing images diff --git a/docs/source/markdown/podman-push.1.md b/docs/source/markdown/podman-push.1.md index f029c8db1..fffd76801 100644 --- a/docs/source/markdown/podman-push.1.md +++ b/docs/source/markdown/podman-push.1.md @@ -71,6 +71,12 @@ Note: This flag can only be set when using the **dir** transport After copying the image, write the digest of the resulting image to the file. (Not available for remote commands) +**--disable-content-trust** + +This is a Docker specific option to disable image verification to a Docker +registry and is not supported by Podman. This flag is a NOOP and provided +solely for scripting compatibility. + **--format**, **-f**=*format* Manifest Type (oci, v2s1, or v2s2) to use when pushing an image to a directory using the 'dir:' transport (default is manifest type of source) diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index a7fd5a7eb..b959b947f 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -247,6 +247,12 @@ Limit write rate (in bytes per second) to a device (e.g. **--device-write-bps=/d Limit write rate (in IO operations per second) to a device (e.g. **--device-write-iops=/dev/sda:1000**). +**--disable-content-trust** + +This is a Docker specific option to disable image verification to a Docker +registry and is not supported by Podman. This flag is a NOOP and provided +solely for scripting compatibility. + **--dns**=*ipaddr* Set custom DNS servers. Invalid if using **--dns** with **--network** that is set to **none** or **container:**_id_. @@ -874,6 +880,10 @@ standard input. Set timezone in container. This flag takes area-based timezones, GMT time, as well as `local`, which sets the timezone in the container to match the host machine. See `/usr/share/zoneinfo/` for valid timezones. +**--umask**=*umask* + +Set the umask inside the container. Defaults to `0022`. + **--uidmap**=*container_uid*:*host_uid*:*amount* Run the container in a new user namespace using the supplied mapping. This option conflicts @@ -1119,7 +1129,7 @@ the exit codes follow the **chroot**(1) standard, see below: **Exit code** _contained command_ exit code - $ podman run busybox /bin/sh -c 'exit 3' + $ podman run busybox /bin/sh -c 'exit 3'; echo $? 3 ## EXAMPLES @@ -1399,9 +1409,10 @@ required for VPN, without it containers need to be run with the **--network=host ## ENVIRONMENT Environment variables within containers can be set using multiple different options, -in the following order of precedence: +in the following order of precedence (later entries override earlier entries): - **--env-host**: Host environment of the process executing Podman is added. +- **--http-proxy**: By default, several environment variables will be passed in from the host, such as **http_proxy** and **no_proxy**. See **--http-proxy** for details. - Container image: Any environment variables specified in the container image. - **--env-file**: Any environment variables specified via env-files. If multiple files specified, then they override each other in order of entry. - **--env**: Any environment variables specified will override previous settings. @@ -11,11 +11,11 @@ require ( github.com/containernetworking/cni v0.7.2-0.20200304161608-4fae32b84921 github.com/containernetworking/plugins v0.8.6 github.com/containers/buildah v1.15.1-0.20200708111410-d2ea9429455d - github.com/containers/common v0.16.0 + github.com/containers/common v0.18.0 github.com/containers/conmon v2.0.19+incompatible github.com/containers/image/v5 v5.5.1 github.com/containers/psgo v1.5.1 - github.com/containers/storage v1.21.1 + github.com/containers/storage v1.21.2 github.com/coreos/go-systemd/v22 v22.1.0 github.com/cri-o/ocicni v0.2.0 github.com/cyphar/filepath-securejoin v0.2.2 @@ -41,7 +41,7 @@ require ( github.com/opencontainers/image-spec v1.0.2-0.20190823105129-775207bd45b6 github.com/opencontainers/runc v1.0.0-rc91.0.20200708210054-ce54a9d4d79b github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 - github.com/opencontainers/runtime-tools v0.9.0 + github.com/opencontainers/runtime-tools v0.9.1-0.20200714183735-07406c5828aa github.com/opencontainers/selinux v1.6.0 github.com/opentracing/opentracing-go v1.2.0 github.com/pkg/errors v0.9.1 @@ -73,8 +73,8 @@ github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHV github.com/containers/buildah v1.15.1-0.20200708111410-d2ea9429455d h1:HgJJn1UBFjM464NpEmgLwVje5vSF/fBYAdLLoww9HgU= github.com/containers/buildah v1.15.1-0.20200708111410-d2ea9429455d/go.mod h1:HUAiD1mCGPFPcIuk5zls1LElLhXo7Q3hWDwheojjyAs= github.com/containers/common v0.15.2/go.mod h1:rhpXuGLTEKsk/xX/x0iKGHjRadMHpBd2ZiNDugwXPEM= -github.com/containers/common v0.16.0 h1:zAxDJ2tA2wBEjXwV/+ddC8s1f3MfqulH3waSjKxlX3o= -github.com/containers/common v0.16.0/go.mod h1:siKqOA03Bhh7Ss2m7fCsbVvbjwaNqrI+gZtC9FUp+DI= +github.com/containers/common v0.18.0 h1:pZB6f17N5QV43TcT06gtx1lb0rxd/4StFdVhP9CtgQg= +github.com/containers/common v0.18.0/go.mod h1:H2Wqvx6wkqdzT4RcTCqIG4W0HSOZwUbbNiUTX1+VohU= github.com/containers/conmon v2.0.19+incompatible h1:1bDVRvHy2MUNTUT/SW6LlHsJHQBTSwXvnKNdcB/a1vQ= github.com/containers/conmon v2.0.19+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.5.1 h1:h1FCOXH6Ux9/p/E4rndsQOC4yAdRU0msRTfLVeQ7FDQ= @@ -86,8 +86,8 @@ github.com/containers/ocicrypt v1.0.2/go.mod h1:nsOhbP19flrX6rE7ieGFvBlr7modwmNj github.com/containers/psgo v1.5.1 h1:MQNb7FLbXqBdqz6u4lI2QWizVz4RSTzs1+Nk9XT1iVA= github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU= github.com/containers/storage v1.20.2/go.mod h1:oOB9Ie8OVPojvoaKWEGSEtHbXUAs+tSyr7RO7ZGteMc= -github.com/containers/storage v1.21.1 h1:FGA2c7+0Bn8ndrlrj+HHmKeVjFD3yVhvYa0gijsrg1M= -github.com/containers/storage v1.21.1/go.mod h1:I1EIAA7B4OwWRSA0b4yq2AW1wjvvfcY0zLWQuwTa4zw= +github.com/containers/storage v1.21.2 h1:bf9IqA+g6ClBviqVG5lVCp5tTH9lvWwjYws7mVYSti0= +github.com/containers/storage v1.21.2/go.mod h1:I1EIAA7B4OwWRSA0b4yq2AW1wjvvfcY0zLWQuwTa4zw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-iptables v0.4.5 h1:DpHb9vJrZQEFMcVLFKAAGMUVX0XoRC0ptCthinRYm38= @@ -342,6 +342,8 @@ github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2/go.m github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/runtime-tools v0.9.0 h1:FYgwVsKRI/H9hU32MJ/4MLOzXWodKK5zsQavY8NPMkU= github.com/opencontainers/runtime-tools v0.9.0/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/runtime-tools v0.9.1-0.20200714183735-07406c5828aa h1:iyj+fFHVBn0xOalz9UChYzSU1K0HJ+d75b4YqShBRhI= +github.com/opencontainers/runtime-tools v0.9.1-0.20200714183735-07406c5828aa/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/selinux v1.3.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs= github.com/opencontainers/selinux v1.5.1/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g= github.com/opencontainers/selinux v1.5.2/go.mod h1:yTcKuYAh6R95iDpefGLQaPaRwJFwyzAJufJyiTt7s0g= diff --git a/libpod/container.go b/libpod/container.go index fda018640..8a69df685 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -437,6 +437,9 @@ type ContainerConfig struct { // Timezone is the timezone inside the container. // Local means it has the same timezone as the host machine Timezone string `json:"timezone,omitempty"` + + // Umask is the umask inside the container. + Umask string `json:"umask,omitempty"` } // ContainerNamedVolume is a named volume that will be mounted into the @@ -1276,5 +1279,8 @@ func (c *Container) AutoRemove() bool { func (c *Container) Timezone() string { return c.config.Timezone +} +func (c *Container) Umask() string { + return c.config.Umask } diff --git a/libpod/container_exec.go b/libpod/container_exec.go index bd04ee9b9..a16aea06d 100644 --- a/libpod/container_exec.go +++ b/libpod/container_exec.go @@ -729,10 +729,6 @@ func (c *Container) Exec(config *ExecConfig, streams *define.AttachStreams, resi return -1, err } - if exitCode != 0 { - return exitCode, errors.Wrapf(define.ErrOCIRuntime, "exec session exited with non-zero exit code %d", exitCode) - } - return exitCode, nil } diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index 680776dba..a0d223c8c 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -325,6 +325,14 @@ func (c *Container) generateInspectContainerConfig(spec *spec.Spec) *define.Insp ctrConfig.Timezone = c.config.Timezone + // Pad Umask to 4 characters + if len(c.config.Umask) < 4 { + pad := strings.Repeat("0", 4-len(c.config.Umask)) + ctrConfig.Umask = pad + c.config.Umask + } else { + ctrConfig.Umask = c.config.Umask + } + return ctrConfig } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 1c21f2ff9..09bf33728 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -250,7 +250,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } // Apply AppArmor checks and load the default profile if needed. - if !c.config.Privileged { + if len(c.config.Spec.Process.ApparmorProfile) > 0 { updatedProfile, err := apparmor.CheckProfileAndLoadDefault(c.config.Spec.Process.ApparmorProfile) if err != nil { return nil, err @@ -355,6 +355,14 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { g.SetProcessGID(uint32(execUser.Gid)) } + if c.config.Umask != "" { + decVal, err := strconv.ParseUint(c.config.Umask, 8, 32) + if err != nil { + return nil, errors.Wrapf(err, "Invalid Umask Value") + } + g.SetProcessUmask(uint32(decVal)) + } + // Add addition groups if c.config.GroupAdd is not empty if len(c.config.Groups) > 0 { gids, err := lookup.GetContainerGroups(c.config.Groups, c.state.Mountpoint, overrides) diff --git a/libpod/define/config.go b/libpod/define/config.go index 64b24d9e2..6c426f2ec 100644 --- a/libpod/define/config.go +++ b/libpod/define/config.go @@ -20,6 +20,8 @@ var ( NameRegex = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9_.-]*$") // RegexError is thrown in presence of an invalid container/pod name. RegexError = errors.Wrapf(ErrInvalidArg, "names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*") + // UmaskRegex is a regular expression to validate Umask. + UmaskRegex = regexp.MustCompile(`^[0-7]{1,4}$`) ) const ( diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go index fbd9da3e7..a08cb3de6 100644 --- a/libpod/define/container_inspect.go +++ b/libpod/define/container_inspect.go @@ -61,6 +61,8 @@ type InspectContainerConfig struct { // systemd mode, the container configuration is customized to optimize // running systemd in the container. SystemdMode bool `json:"SystemdMode,omitempty"` + // Umask is the umask inside the container. + Umask string `json:"Umask,omitempty"` } // InspectRestartPolicy holds information about the container's restart policy. diff --git a/libpod/healthcheck.go b/libpod/healthcheck.go index b04742974..4818f8dc4 100644 --- a/libpod/healthcheck.go +++ b/libpod/healthcheck.go @@ -92,7 +92,7 @@ func (c *Container) runHealthCheck() (define.HealthCheckStatus, error) { hcResult := define.HealthCheckSuccess config := new(ExecConfig) config.Command = newCommand - _, hcErr := c.Exec(config, streams, nil) + exitCode, hcErr := c.Exec(config, streams, nil) if hcErr != nil { errCause := errors.Cause(hcErr) hcResult = define.HealthCheckFailure @@ -104,6 +104,9 @@ func (c *Container) runHealthCheck() (define.HealthCheckStatus, error) { } else { returnCode = 125 } + } else if exitCode != 0 { + hcResult = define.HealthCheckFailure + returnCode = 1 } timeEnd := time.Now() if c.HealthCheckConfig().StartPeriod > 0 { diff --git a/libpod/options.go b/libpod/options.go index 40cf452db..41b0d7212 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1607,6 +1607,20 @@ func WithTimezone(path string) CtrCreateOption { } } +// WithUmask sets the umask in the container +func WithUmask(umask string) CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return define.ErrCtrFinalized + } + if !define.UmaskRegex.MatchString(umask) { + return errors.Wrapf(define.ErrInvalidArg, "Invalid umask string %s", umask) + } + ctr.config.Umask = umask + return nil + } +} + // Pod Creation Options // WithPodName sets the name of the pod. diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index f82da2c95..52a62a25d 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -340,9 +340,7 @@ func getPodPorts(containers []v1.Container) []ocicni.PortMapping { HostPort: p.HostPort, ContainerPort: p.ContainerPort, Protocol: strings.ToLower(string(p.Protocol)), - } - if p.HostIP != "" { - logrus.Debug("HostIP on port bindings is not supported") + HostIP: p.HostIP, } // only hostPort is utilized in podman context, all container ports // are accessible inside the shared network namespace @@ -453,11 +451,16 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container containerConfig.Command = []string{} if imageData != nil && imageData.Config != nil { - containerConfig.Command = append(containerConfig.Command, imageData.Config.Entrypoint...) + containerConfig.Command = imageData.Config.Entrypoint } if len(containerYAML.Command) != 0 { - containerConfig.Command = append(containerConfig.Command, containerYAML.Command...) - } else if imageData != nil && imageData.Config != nil { + containerConfig.Command = containerYAML.Command + } + // doc https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes + if len(containerYAML.Args) != 0 { + containerConfig.Command = append(containerConfig.Command, containerYAML.Args...) + } else if len(containerYAML.Command) == 0 { + // Add the Cmd from the image config only if containerYAML.Command and containerYAML.Args are empty containerConfig.Command = append(containerConfig.Command, imageData.Config.Cmd...) } if imageData != nil && len(containerConfig.Command) == 0 { diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go index 622313a04..eddc4ad5d 100644 --- a/pkg/specgen/container_validate.go +++ b/pkg/specgen/container_validate.go @@ -81,10 +81,6 @@ func (s *SpecGenerator) Validate() error { if len(s.CapAdd) > 0 && s.Privileged { return exclusiveOptions("CapAdd", "privileged") } - // apparmor and privileged are exclusive - if len(s.ApparmorProfile) > 0 && s.Privileged { - return exclusiveOptions("AppArmorProfile", "privileged") - } // userns and idmappings conflict if s.UserNS.IsPrivate() && s.IDMappings == nil { return errors.Wrap(ErrInvalidSpecConfig, "IDMappings are required when not creating a User namespace") diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 6dbc45c16..934d5fbac 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -145,6 +145,9 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. if s.Timezone != "" { options = append(options, libpod.WithTimezone(s.Timezone)) } + if s.Umask != "" { + options = append(options, libpod.WithUmask(s.Umask)) + } useSystemd := false switch s.Systemd { diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index 4953735b1..f279aac1c 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -285,13 +285,6 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt } } - // SECURITY OPTS - g.SetProcessNoNewPrivileges(s.NoNewPrivileges) - - if !s.Privileged { - g.SetProcessApparmorProfile(s.ApparmorProfile) - } - BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), &g) for name, val := range s.Env { diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go index 70493cd5f..fcd1622f9 100644 --- a/pkg/specgen/generate/security.go +++ b/pkg/specgen/generate/security.go @@ -3,6 +3,7 @@ package generate import ( "strings" + "github.com/containers/common/pkg/apparmor" "github.com/containers/common/pkg/capabilities" "github.com/containers/common/pkg/config" "github.com/containers/libpod/v2/libpod" @@ -56,6 +57,28 @@ func setLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig s return nil } +func setupApparmor(s *specgen.SpecGenerator, rtc *config.Config, g *generate.Generator) error { + hasProfile := len(s.ApparmorProfile) > 0 + if !apparmor.IsEnabled() { + if hasProfile { + return errors.Errorf("Apparmor profile %q specified, but Apparmor is not enabled on this system", s.ApparmorProfile) + } + return nil + } + // If privileged and caller did not specify apparmor profiles return + if s.Privileged && !hasProfile { + return nil + } + if !hasProfile { + s.ApparmorProfile = rtc.Containers.ApparmorProfile + } + if len(s.ApparmorProfile) > 0 { + g.SetProcessApparmorProfile(s.ApparmorProfile) + } + + return nil +} + func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *image.Image, rtc *config.Config) error { var ( caplist []string @@ -105,6 +128,13 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, } } } + + g.SetProcessNoNewPrivileges(s.NoNewPrivileges) + + if err := setupApparmor(s, rtc, g); err != nil { + return err + } + configSpec := g.Config configSpec.Process.Capabilities.Bounding = caplist diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index c6079be33..84a6c36a0 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -287,6 +287,8 @@ type ContainerSecurityConfig struct { // ReadOnlyFilesystem indicates that everything will be mounted // as read-only ReadOnlyFilesystem bool `json:"read_only_filesystem,omittempty"` + // Umask is the umask the init process of the container will be run with. + Umask string `json:"umask,omitempty"` } // ContainerCgroupConfig contains configuration information about a container's diff --git a/test/e2e/attach_test.go b/test/e2e/attach_test.go index 9fd1466aa..827b7568d 100644 --- a/test/e2e/attach_test.go +++ b/test/e2e/attach_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -42,6 +40,7 @@ var _ = Describe("Podman attach", func() { }) It("podman attach to non-running container", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"create", "--name", "test1", "-d", "-i", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -52,6 +51,7 @@ var _ = Describe("Podman attach", func() { }) It("podman container attach to non-running container", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"container", "create", "--name", "test1", "-d", "-i", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -87,6 +87,7 @@ var _ = Describe("Podman attach", func() { Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) }) It("podman attach to the latest container", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"run", "-d", "--name", "test1", ALPINE, "/bin/sh", "-c", "while true; do echo test1; sleep 1; done"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go index 9c8078f16..c72d2243a 100644 --- a/test/e2e/build_test.go +++ b/test/e2e/build_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -40,6 +38,7 @@ var _ = Describe("Podman build", func() { // Let's first do the most simple build possible to make sure stuff is // happy and then clean up after ourselves to make sure that works too. It("podman build and remove basic alpine", func() { + SkipIfRemote() session := podmanTest.PodmanNoCache([]string{"build", "build/basicalpine"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -69,6 +68,7 @@ var _ = Describe("Podman build", func() { // Check that builds with different values for the squash options // create the appropriate number of layers, then clean up after. It("podman build basic alpine with squash", func() { + SkipIfRemote() session := podmanTest.PodmanNoCache([]string{"build", "-f", "build/squash/Dockerfile.squash-a", "-t", "test-squash-a:latest", "build/squash"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -154,6 +154,7 @@ var _ = Describe("Podman build", func() { }) It("podman build basic alpine and print id to external file", func() { + SkipIfRemote() // Switch to temp dir and restore it afterwards cwd, err := os.Getwd() diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index aa0e9635a..4fc5b3da9 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -14,6 +14,7 @@ import ( "time" "github.com/containers/libpod/v2/libpod/define" + "github.com/containers/libpod/v2/pkg/cgroups" "github.com/containers/libpod/v2/pkg/inspect" "github.com/containers/libpod/v2/pkg/rootless" . "github.com/containers/libpod/v2/test/utils" @@ -151,6 +152,8 @@ var _ = SynchronizedBeforeSuite(func() []byte { return []byte(path) }, func(data []byte) { + cwd, _ := os.Getwd() + INTEGRATION_ROOT = filepath.Join(cwd, "../../") LockTmpDir = string(data) }) @@ -599,3 +602,27 @@ func SkipIfNotFedora() { func isRootless() bool { return os.Geteuid() != 0 } + +func SkipIfCgroupV1() { + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + if !cgroupsv2 { + Skip("Skip on systems with cgroup V1 systems") + } +} + +func SkipIfCgroupV2() { + cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() + Expect(err).To(BeNil()) + + if cgroupsv2 { + Skip("Skip on systems with cgroup V2 systems") + } +} + +// PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment +func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration { + podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil) + return &PodmanSessionIntegration{podmanSession} +} diff --git a/test/e2e/config/containers.conf b/test/e2e/config/containers.conf index 0a07676c4..5f852468d 100644 --- a/test/e2e/config/containers.conf +++ b/test/e2e/config/containers.conf @@ -50,3 +50,5 @@ dns_servers=[ "1.2.3.4", ] dns_options=[ "debug", ] tz = "Pacific/Honolulu" + +umask = "0002" diff --git a/test/e2e/containers_conf_test.go b/test/e2e/containers_conf_test.go index 23d8dd197..aebbca855 100644 --- a/test/e2e/containers_conf_test.go +++ b/test/e2e/containers_conf_test.go @@ -218,6 +218,17 @@ var _ = Describe("Podman run", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("HST")) + }) + It("podman run containers.conf umask", func() { + //containers.conf umask set to 0002 + if !strings.Contains(podmanTest.OCIRuntime, "crun") { + Skip("Test only works on crun") + } + session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "sh", "-c", "umask"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("0002")) }) + }) diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go index a1a08045a..a6f4f830b 100644 --- a/test/e2e/create_staticip_test.go +++ b/test/e2e/create_staticip_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index f21f17d39..09b4f5911 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" . "github.com/containers/libpod/v2/test/utils" . "github.com/onsi/ginkgo" @@ -499,4 +500,46 @@ var _ = Describe("Podman create", func() { Expect(data[0].Config.Timezone).To(Equal("local")) }) + It("podman create --umask", func() { + if !strings.Contains(podmanTest.OCIRuntime, "crun") { + Skip("Test only works on crun") + } + + session := podmanTest.Podman([]string{"create", "--name", "default", ALPINE}) + session.WaitWithDefaultTimeout() + inspect := podmanTest.Podman([]string{"inspect", "default"}) + inspect.WaitWithDefaultTimeout() + data := inspect.InspectContainerToJSON() + Expect(len(data)).To(Equal(1)) + Expect(data[0].Config.Umask).To(Equal("0022")) + + session = podmanTest.Podman([]string{"create", "--umask", "0002", "--name", "umask", ALPINE}) + session.WaitWithDefaultTimeout() + inspect = podmanTest.Podman([]string{"inspect", "umask"}) + inspect.WaitWithDefaultTimeout() + data = inspect.InspectContainerToJSON() + Expect(len(data)).To(Equal(1)) + Expect(data[0].Config.Umask).To(Equal("0002")) + + session = podmanTest.Podman([]string{"create", "--umask", "0077", "--name", "fedora", fedoraMinimal}) + session.WaitWithDefaultTimeout() + inspect = podmanTest.Podman([]string{"inspect", "fedora"}) + inspect.WaitWithDefaultTimeout() + data = inspect.InspectContainerToJSON() + Expect(len(data)).To(Equal(1)) + Expect(data[0].Config.Umask).To(Equal("0077")) + + session = podmanTest.Podman([]string{"create", "--umask", "22", "--name", "umask-short", ALPINE}) + session.WaitWithDefaultTimeout() + inspect = podmanTest.Podman([]string{"inspect", "umask-short"}) + inspect.WaitWithDefaultTimeout() + data = inspect.InspectContainerToJSON() + Expect(len(data)).To(Equal(1)) + Expect(data[0].Config.Umask).To(Equal("0022")) + + session = podmanTest.Podman([]string{"create", "--umask", "9999", "--name", "bad", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session.ErrorToString()).To(ContainSubstring("Invalid umask")) + }) }) diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 577a7562b..7a3bfdf61 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go index 13f4e1aef..263139064 100644 --- a/test/e2e/libpod_suite_remote_test.go +++ b/test/e2e/libpod_suite_remote_test.go @@ -214,5 +214,3 @@ func (p *PodmanTestIntegration) DelayForService() error { func populateCache(podman *PodmanTestIntegration) {} func removeCache() {} -func SkipIfCgroupV1() {} -func SkipIfCgroupV2() {} diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index 29ad01363..bfd898108 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -9,32 +9,12 @@ import ( "path/filepath" "strings" - "github.com/containers/libpod/v2/pkg/cgroups" . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" ) func SkipIfRemote() { } -func SkipIfCgroupV1() { - cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() - Expect(err).To(BeNil()) - - if !cgroupsv2 { - Skip("Skip on systems with cgroup V1 systems") - } -} - -func SkipIfCgroupV2() { - cgroupsv2, err := cgroups.IsCgroup2UnifiedMode() - Expect(err).To(BeNil()) - - if cgroupsv2 { - Skip("Skip on systems with cgroup V2 systems") - } -} - func SkipIfRootless() { if os.Geteuid() != 0 { Skip("This function is not enabled for rootless podman") @@ -66,12 +46,6 @@ func (p *PodmanTestIntegration) PodmanNoEvents(args []string) *PodmanSessionInte return &PodmanSessionIntegration{podmanSession} } -// PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment -func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration { - podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil) - return &PodmanSessionIntegration{podmanSession} -} - func (p *PodmanTestIntegration) setDefaultRegistriesConfigEnv() { defaultFile := filepath.Join(INTEGRATION_ROOT, "test/registries.conf") os.Setenv("REGISTRIES_CONFIG_PATH", defaultFile) diff --git a/test/e2e/load_test.go b/test/e2e/load_test.go index df2613334..879291c36 100644 --- a/test/e2e/load_test.go +++ b/test/e2e/load_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -125,6 +123,7 @@ var _ = Describe("Podman load", func() { }) It("podman load directory", func() { + SkipIfRemote() outdir := filepath.Join(podmanTest.TempDir, "alpine") save := podmanTest.PodmanNoCache([]string{"save", "--format", "oci-dir", "-o", outdir, ALPINE}) @@ -228,6 +227,7 @@ var _ = Describe("Podman load", func() { }) It("podman load localhost registry from dir", func() { + SkipIfRemote() outfile := filepath.Join(podmanTest.TempDir, "load") setup := podmanTest.PodmanNoCache([]string{"tag", BB, "hello:world"}) diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go index 3bdce970b..66f764925 100644 --- a/test/e2e/login_logout_test.go +++ b/test/e2e/login_logout_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/namespace_test.go b/test/e2e/namespace_test.go index 70472f384..5756a8fa2 100644 --- a/test/e2e/namespace_test.go +++ b/test/e2e/namespace_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -35,6 +33,7 @@ var _ = Describe("Podman namespaces", func() { }) It("podman namespace test", func() { + SkipIfRemote() podman1 := podmanTest.Podman([]string{"--namespace", "test1", "run", "-d", ALPINE, "echo", "hello"}) podman1.WaitWithDefaultTimeout() Expect(podman1.ExitCode()).To(Equal(0)) diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index 83b0ce32c..24f711ae7 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -140,6 +138,7 @@ var _ = Describe("Podman network create", func() { }) It("podman network create with name and subnet", func() { + SkipIfRemote() var ( results []network.NcList ) diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 23604f47d..052db3842 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -8,6 +6,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "text/template" . "github.com/containers/libpod/v2/test/utils" @@ -50,6 +49,10 @@ spec: {{ range .Cmd }} - {{.}} {{ end }} + args: + {{ range .Arg }} + - {{.}} + {{ end }} env: - name: PATH value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin @@ -82,6 +85,11 @@ spec: {{ end }} privileged: false readOnlyRootFilesystem: false + ports: + - containerPort: {{ .Port }} + hostIP: {{ .HostIP }} + hostPort: {{ .Port }} + protocol: TCP workingDir: / {{ end }} {{ end }} @@ -129,6 +137,10 @@ spec: {{ range .Cmd }} - {{.}} {{ end }} + args: + {{ range .Arg }} + - {{.}} + {{ end }} env: - name: PATH value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin @@ -171,6 +183,7 @@ spec: var ( defaultCtrName = "testCtr" defaultCtrCmd = []string{"top"} + defaultCtrArg = []string{"-d", "1.5"} defaultCtrImage = ALPINE defaultPodName = "testPod" defaultDeploymentName = "testDeployment" @@ -322,17 +335,20 @@ type Ctr struct { Name string Image string Cmd []string + Arg []string SecurityContext bool Caps bool CapAdd []string CapDrop []string PullPolicy string + HostIP string + Port string } // getCtr takes a list of ctrOptions and returns a Ctr with sane defaults // and the configured options func getCtr(options ...ctrOption) *Ctr { - c := Ctr{defaultCtrName, defaultCtrImage, defaultCtrCmd, true, false, nil, nil, ""} + c := Ctr{defaultCtrName, defaultCtrImage, defaultCtrCmd, defaultCtrArg, true, false, nil, nil, "", "", ""} for _, option := range options { option(&c) } @@ -347,6 +363,12 @@ func withCmd(cmd []string) ctrOption { } } +func withArg(arg []string) ctrOption { + return func(c *Ctr) { + c.Arg = arg + } +} + func withImage(img string) ctrOption { return func(c *Ctr) { c.Image = img @@ -379,6 +401,13 @@ func withPullPolicy(policy string) ctrOption { } } +func withHostIP(ip string, port string) ctrOption { + return func(c *Ctr) { + c.HostIP = ip + c.Port = port + } +} + func getCtrNameInPod(pod *Pod) string { return fmt.Sprintf("%s-%s", pod.Name, defaultCtrName) } @@ -430,6 +459,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman play kube test correct command", func() { + SkipIfRemote() pod := getPod() err := generatePodKubeYaml(pod, kubeYaml) Expect(err).To(BeNil()) @@ -438,14 +468,52 @@ var _ = Describe("Podman generate kube", func() { kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod)}) + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Cmd }}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + // Use the defined command to override the image's command + correctCmd := "[" + strings.Join(defaultCtrCmd, " ") + " " + strings.Join(defaultCtrArg, " ") + Expect(inspect.OutputToString()).To(ContainSubstring(correctCmd)) + }) + + It("podman play kube test correct command with only set command in yaml file", func() { + SkipIfRemote() + pod := getPod(withCtr(getCtr(withCmd([]string{"echo", "hello"}), withArg(nil)))) + err := generatePodKubeYaml(pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Cmd }}'"}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) - Expect(inspect.OutputToString()).To(ContainSubstring(defaultCtrCmd[0])) + // Use the defined command to override the image's command, and don't set the args + // so the full command in result should not contains the image's command + Expect(inspect.OutputToString()).To(ContainSubstring(`[echo hello]`)) + }) + + It("podman play kube test correct command with only set args in yaml file", func() { + pod := getPod(withCtr(getCtr(withImage(redis), withCmd(nil), withArg([]string{"echo", "hello"})))) + err := generatePodKubeYaml(pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "'{{ .Config.Cmd }}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + // this image's ENTRYPOINT is called `docker-entrypoint.sh` + // so result should be `docker-entrypoint.sh + withArg(...)` + Expect(inspect.OutputToString()).To(ContainSubstring(`[docker-entrypoint.sh echo hello]`)) }) It("podman play kube test correct output", func() { - p := getPod(withCtr(getCtr(withCmd([]string{"echo", "hello"})))) + SkipIfRemote() + p := getPod(withCtr(getCtr(withCmd([]string{"echo", "hello"}), withArg([]string{"world"})))) err := generatePodKubeYaml(p, kubeYaml) Expect(err).To(BeNil()) @@ -457,12 +525,12 @@ var _ = Describe("Podman generate kube", func() { logs := podmanTest.Podman([]string{"logs", getCtrNameInPod(p)}) logs.WaitWithDefaultTimeout() Expect(logs.ExitCode()).To(Equal(0)) - Expect(logs.OutputToString()).To(ContainSubstring("hello")) + Expect(logs.OutputToString()).To(ContainSubstring("hello world")) inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(p), "--format", "'{{ .Config.Cmd }}'"}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) - Expect(inspect.OutputToString()).To(ContainSubstring("hello")) + Expect(inspect.OutputToString()).To(ContainSubstring(`[echo hello world]`)) }) It("podman play kube test hostname", func() { @@ -498,7 +566,7 @@ var _ = Describe("Podman generate kube", func() { It("podman play kube cap add", func() { capAdd := "CAP_SYS_ADMIN" - ctr := getCtr(withCapAdd([]string{capAdd}), withCmd([]string{"cat", "/proc/self/status"})) + ctr := getCtr(withCapAdd([]string{capAdd}), withCmd([]string{"cat", "/proc/self/status"}), withArg(nil)) pod := getPod(withCtr(ctr)) err := generatePodKubeYaml(pod, kubeYaml) @@ -548,6 +616,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman play kube seccomp container level", func() { + SkipIfRemote() // expect play kube is expected to set a seccomp label if it's applied as an annotation jsonFile, err := podmanTest.CreateSeccompJson(seccompPwdEPERM) if err != nil { @@ -556,7 +625,7 @@ var _ = Describe("Podman generate kube", func() { } ctrAnnotation := "container.seccomp.security.alpha.kubernetes.io/" + defaultCtrName - ctr := getCtr(withCmd([]string{"pwd"})) + ctr := getCtr(withCmd([]string{"pwd"}), withArg(nil)) pod := getPod(withCtr(ctr), withAnnotation(ctrAnnotation, "localhost/"+filepath.Base(jsonFile))) err = generatePodKubeYaml(pod, kubeYaml) @@ -574,6 +643,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman play kube seccomp pod level", func() { + SkipIfRemote() // expect play kube is expected to set a seccomp label if it's applied as an annotation jsonFile, err := podmanTest.CreateSeccompJson(seccompPwdEPERM) if err != nil { @@ -582,7 +652,7 @@ var _ = Describe("Podman generate kube", func() { } defer os.Remove(jsonFile) - ctr := getCtr(withCmd([]string{"pwd"})) + ctr := getCtr(withCmd([]string{"pwd"}), withArg(nil)) pod := getPod(withCtr(ctr), withAnnotation("seccomp.security.alpha.kubernetes.io/pod", "localhost/"+filepath.Base(jsonFile))) err = generatePodKubeYaml(pod, kubeYaml) @@ -725,6 +795,7 @@ spec: // Deployment related tests It("podman play kube deployment 1 replica test correct command", func() { + SkipIfRemote() deployment := getDeployment() err := generateDeploymentKubeYaml(deployment, kubeYaml) Expect(err).To(BeNil()) @@ -734,13 +805,16 @@ spec: Expect(kube.ExitCode()).To(Equal(0)) podNames := getPodNamesInDeployment(deployment) - inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(&podNames[0])}) + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(&podNames[0]), "--format", "'{{ .Config.Cmd }}'"}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) - Expect(inspect.OutputToString()).To(ContainSubstring(defaultCtrCmd[0])) + // yaml's command shuold override the image's Entrypoint + correctCmd := "[" + strings.Join(defaultCtrCmd, " ") + " " + strings.Join(defaultCtrArg, " ") + Expect(inspect.OutputToString()).To(ContainSubstring(correctCmd)) }) It("podman play kube deployment more than 1 replica test correct command", func() { + SkipIfRemote() var i, numReplicas int32 numReplicas = 5 deployment := getDeployment(withReplicas(numReplicas)) @@ -752,11 +826,31 @@ spec: Expect(kube.ExitCode()).To(Equal(0)) podNames := getPodNamesInDeployment(deployment) + correctCmd := "[" + strings.Join(defaultCtrCmd, " ") + " " + strings.Join(defaultCtrArg, " ") for i = 0; i < numReplicas; i++ { - inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(&podNames[i])}) + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(&podNames[i]), "--format", "'{{ .Config.Cmd }}'"}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) - Expect(inspect.OutputToString()).To(ContainSubstring(defaultCtrCmd[0])) + Expect(inspect.OutputToString()).To(ContainSubstring(correctCmd)) } }) + + It("podman play kube test with network portbindings", func() { + ip := "127.0.0.100" + port := "5000" + ctr := getCtr(withHostIP(ip, port), withImage(BB)) + + pod := getPod(withCtr(ctr)) + err := generatePodKubeYaml(pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"port", getCtrNameInPod(pod)}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(Equal("5000/tcp -> 127.0.0.100:5000")) + }) }) diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go index 49105310b..a5fa21187 100644 --- a/test/e2e/pod_infra_container_test.go +++ b/test/e2e/pod_infra_container_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -227,6 +225,7 @@ var _ = Describe("Podman pod create", func() { }) It("podman pod container can override pod pid NS", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"pod", "create", "--share", "pid"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -258,6 +257,7 @@ var _ = Describe("Podman pod create", func() { }) It("podman pod container can override pod not sharing pid", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"pod", "create", "--share", "net"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -283,6 +283,7 @@ var _ = Describe("Podman pod create", func() { }) It("podman pod container can override pod ipc NS", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"pod", "create", "--share", "ipc"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/pod_pod_namespaces.go b/test/e2e/pod_pod_namespaces.go index fce131e20..7a6223158 100644 --- a/test/e2e/pod_pod_namespaces.go +++ b/test/e2e/pod_pod_namespaces.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -63,6 +61,7 @@ var _ = Describe("Podman pod create", func() { }) It("podman pod container dontshare PIDNS", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"pod", "create"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go index 74d1c1838..04068de06 100644 --- a/test/e2e/pod_stats_test.go +++ b/test/e2e/pod_stats_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/pod_top_test.go b/test/e2e/pod_top_test.go index f86d23d84..40e8d77d8 100644 --- a/test/e2e/pod_top_test.go +++ b/test/e2e/pod_top_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -58,6 +56,7 @@ var _ = Describe("Podman top", func() { }) It("podman pod top on pod", func() { + SkipIfRemote() _, ec, podid := podmanTest.CreatePod("") Expect(ec).To(Equal(0)) diff --git a/test/e2e/port_test.go b/test/e2e/port_test.go index 897505588..b247fcaa3 100644 --- a/test/e2e/port_test.go +++ b/test/e2e/port_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -49,6 +47,7 @@ var _ = Describe("Podman port", func() { }) It("podman port -l nginx", func() { + SkipIfRemote() session, cid := podmanTest.RunNginxWithHealthCheck("") Expect(session.ExitCode()).To(Equal(0)) @@ -64,6 +63,7 @@ var _ = Describe("Podman port", func() { }) It("podman container port -l nginx", func() { + SkipIfRemote() session, cid := podmanTest.RunNginxWithHealthCheck("") Expect(session.ExitCode()).To(Equal(0)) @@ -79,6 +79,7 @@ var _ = Describe("Podman port", func() { }) It("podman port -l port nginx", func() { + SkipIfRemote() session, cid := podmanTest.RunNginxWithHealthCheck("") Expect(session.ExitCode()).To(Equal(0)) @@ -127,18 +128,18 @@ var _ = Describe("Podman port", func() { lock2 := GetPortLock("5001") defer lock2.Unlock() - setup := podmanTest.Podman([]string{"run", "-dt", "-p", "5000:5000", "-p", "5001:5001", ALPINE, "top"}) + setup := podmanTest.Podman([]string{"run", "--name", "test", "-dt", "-p", "5000:5000", "-p", "5001:5001", ALPINE, "top"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(BeZero()) // Check that the first port was honored - result1 := podmanTest.Podman([]string{"port", "-l", "5000"}) + result1 := podmanTest.Podman([]string{"port", "test", "5000"}) result1.WaitWithDefaultTimeout() Expect(result1.ExitCode()).To(BeZero()) Expect(result1.LineInOuputStartsWith("0.0.0.0:5000")).To(BeTrue()) // Check that the second port was honored - result2 := podmanTest.Podman([]string{"port", "-l", "5001"}) + result2 := podmanTest.Podman([]string{"port", "test", "5001"}) result2.WaitWithDefaultTimeout() Expect(result2.ExitCode()).To(BeZero()) Expect(result2.LineInOuputStartsWith("0.0.0.0:5001")).To(BeTrue()) diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go index eec2877e8..665cd1b55 100644 --- a/test/e2e/pull_test.go +++ b/test/e2e/pull_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -237,6 +235,7 @@ var _ = Describe("Podman pull", func() { }) It("podman pull from docker-archive", func() { + SkipIfRemote() podmanTest.RestoreArtifact(ALPINE) tarfn := filepath.Join(podmanTest.TempDir, "alp.tar") session := podmanTest.PodmanNoCache([]string{"save", "-o", tarfn, "alpine"}) @@ -255,6 +254,7 @@ var _ = Describe("Podman pull", func() { }) It("podman pull from oci-archive", func() { + SkipIfRemote() podmanTest.RestoreArtifact(ALPINE) tarfn := filepath.Join(podmanTest.TempDir, "oci-alp.tar") session := podmanTest.PodmanNoCache([]string{"save", "--format", "oci-archive", "-o", tarfn, "alpine"}) @@ -273,6 +273,7 @@ var _ = Describe("Podman pull", func() { }) It("podman pull from local directory", func() { + SkipIfRemote() podmanTest.RestoreArtifact(ALPINE) dirpath := filepath.Join(podmanTest.TempDir, "alpine") os.MkdirAll(dirpath, os.ModePerm) @@ -297,6 +298,7 @@ var _ = Describe("Podman pull", func() { }) It("podman pull from local OCI directory", func() { + SkipIfRemote() podmanTest.RestoreArtifact(ALPINE) dirpath := filepath.Join(podmanTest.TempDir, "alpine") os.MkdirAll(dirpath, os.ModePerm) diff --git a/test/e2e/run_apparmor_test.go b/test/e2e/run_apparmor_test.go new file mode 100644 index 000000000..344309b93 --- /dev/null +++ b/test/e2e/run_apparmor_test.go @@ -0,0 +1,158 @@ +// +build !remote + +package integration + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/containers/common/pkg/apparmor" + . "github.com/containers/libpod/v2/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func skipIfAppArmorEnabled() { + if apparmor.IsEnabled() { + Skip("Apparmor is enabled") + } +} +func skipIfAppArmorDisabled() { + if !apparmor.IsEnabled() { + Skip("Apparmor is not enabled") + } +} + +var _ = Describe("Podman run", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + podmanTest.SeedImages() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + + }) + + It("podman run apparmor default", func() { + skipIfAppArmorDisabled() + session := podmanTest.Podman([]string{"create", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + cid := session.OutputToString() + // Verify that apparmor.Profile is being set + inspect := podmanTest.InspectContainer(cid) + Expect(inspect[0].AppArmorProfile).To(Equal(apparmor.Profile)) + }) + + It("podman run no apparmor --privileged", func() { + skipIfAppArmorDisabled() + session := podmanTest.Podman([]string{"create", "--privileged", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + cid := session.OutputToString() + // Verify that apparmor.Profile is being set + inspect := podmanTest.InspectContainer(cid) + Expect(inspect[0].AppArmorProfile).To(Equal("")) + }) + + It("podman run no apparmor --security-opt=apparmor.Profile --privileged", func() { + skipIfAppArmorDisabled() + session := podmanTest.Podman([]string{"create", "--security-opt", fmt.Sprintf("apparmor=%s", apparmor.Profile), "--privileged", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + cid := session.OutputToString() + // Verify that apparmor.Profile is being set + inspect := podmanTest.InspectContainer(cid) + Expect(inspect[0].AppArmorProfile).To(Equal(apparmor.Profile)) + }) + + It("podman run apparmor aa-test-profile", func() { + skipIfAppArmorDisabled() + aaProfile := ` +#include <tunables/global> +profile aa-test-profile flags=(attach_disconnected,mediate_deleted) { + #include <abstractions/base> + deny mount, + deny /sys/[^f]*/** wklx, + deny /sys/f[^s]*/** wklx, + deny /sys/fs/[^c]*/** wklx, + deny /sys/fs/c[^g]*/** wklx, + deny /sys/fs/cg[^r]*/** wklx, + deny /sys/firmware/efi/efivars/** rwklx, + deny /sys/kernel/security/** rwklx, +} +` + aaFile := filepath.Join(os.TempDir(), "aaFile") + Expect(ioutil.WriteFile(aaFile, []byte(aaProfile), 0755)).To(BeNil()) + parse := SystemExec("apparmor_parser", []string{"-Kr", aaFile}) + Expect(parse.ExitCode()).To(Equal(0)) + + session := podmanTest.Podman([]string{"create", "--security-opt", "apparmor=aa-test-profile", "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + cid := session.OutputToString() + // Verify that apparmor.Profile is being set + inspect := podmanTest.InspectContainer(cid) + Expect(inspect[0].AppArmorProfile).To(Equal("aa-test-profile")) + }) + + It("podman run apparmor invalid", func() { + skipIfAppArmorDisabled() + session := podmanTest.Podman([]string{"run", "--security-opt", "apparmor=invalid", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).ToNot(Equal(0)) + }) + + It("podman run apparmor unconfined", func() { + skipIfAppArmorDisabled() + session := podmanTest.Podman([]string{"create", "--security-opt", "apparmor=unconfined", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + cid := session.OutputToString() + // Verify that apparmor.Profile is being set + inspect := podmanTest.InspectContainer(cid) + Expect(inspect[0].AppArmorProfile).To(Equal("unconfined")) + }) + + It("podman run apparmor disabled --security-opt apparmor fails", func() { + skipIfAppArmorEnabled() + // Should fail if user specifies apparmor on disabled system + session := podmanTest.Podman([]string{"create", "--security-opt", fmt.Sprintf("apparmor=%s", apparmor.Profile), ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).ToNot(Equal(0)) + }) + + It("podman run apparmor disabled no default", func() { + skipIfAppArmorEnabled() + // Should succeed if user specifies apparmor on disabled system + session := podmanTest.Podman([]string{"create", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + cid := session.OutputToString() + // Verify that apparmor.Profile is being set + inspect := podmanTest.InspectContainer(cid) + Expect(inspect[0].AppArmorProfile).To(Equal("")) + }) +}) diff --git a/test/e2e/run_cleanup_test.go b/test/e2e/run_cleanup_test.go index 7c83acc40..596c224aa 100644 --- a/test/e2e/run_cleanup_test.go +++ b/test/e2e/run_cleanup_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -35,6 +33,7 @@ var _ = Describe("Podman run exit", func() { }) It("podman run -d mount cleanup test", func() { + SkipIfRemote() SkipIfRootless() result := podmanTest.Podman([]string{"run", "-dt", ALPINE, "top"}) diff --git a/test/e2e/run_cpu_test.go b/test/e2e/run_cpu_test.go index b4785c513..b1fb0e628 100644 --- a/test/e2e/run_cpu_test.go +++ b/test/e2e/run_cpu_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_device_test.go b/test/e2e/run_device_test.go index b1a4c9cb2..8798b2dc1 100644 --- a/test/e2e/run_device_test.go +++ b/test/e2e/run_device_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_dns_test.go b/test/e2e/run_dns_test.go index beed80fd2..a44fb7187 100644 --- a/test/e2e/run_dns_test.go +++ b/test/e2e/run_dns_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_entrypoint_test.go b/test/e2e/run_entrypoint_test.go index 741019770..f6019b37a 100644 --- a/test/e2e/run_entrypoint_test.go +++ b/test/e2e/run_entrypoint_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -46,6 +44,7 @@ CMD [] }) It("podman run entrypoint", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] ` @@ -57,6 +56,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run entrypoint with cmd", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest CMD [ "-v"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] @@ -69,6 +69,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run entrypoint with user cmd overrides image cmd", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest CMD [ "-v"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] @@ -81,6 +82,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run entrypoint with user cmd no image cmd", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] ` @@ -92,6 +94,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run user entrypoint overrides image entrypoint and image cmd", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest CMD ["-i"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] @@ -109,6 +112,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run user entrypoint with command overrides image entrypoint and image cmd", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest CMD ["-i"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] diff --git a/test/e2e/run_env_test.go b/test/e2e/run_env_test.go index c6fb1ad1b..305e37c12 100644 --- a/test/e2e/run_env_test.go +++ b/test/e2e/run_env_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_memory_test.go b/test/e2e/run_memory_test.go index 5ae45b62f..379e74629 100644 --- a/test/e2e/run_memory_test.go +++ b/test/e2e/run_memory_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 317f760db..a22f79180 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -265,10 +263,10 @@ var _ = Describe("Podman run networking", func() { }) It("podman run network expose ports in image metadata", func() { - session := podmanTest.Podman([]string{"create", "-dt", "-P", nginx}) + session := podmanTest.Podman([]string{"create", "--name", "test", "-dt", "-P", nginx}) session.Wait(90) Expect(session.ExitCode()).To(Equal(0)) - results := podmanTest.Podman([]string{"inspect", "-l"}) + results := podmanTest.Podman([]string{"inspect", "test"}) results.Wait(30) Expect(results.ExitCode()).To(Equal(0)) Expect(results.OutputToString()).To(ContainSubstring(`"80/tcp":`)) @@ -277,11 +275,11 @@ var _ = Describe("Podman run networking", func() { It("podman run network expose duplicate host port results in error", func() { SkipIfRootless() - session := podmanTest.Podman([]string{"run", "-dt", "-p", "80", ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"run", "--name", "test", "-dt", "-p", "80", ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", "-l"}) + inspect := podmanTest.Podman([]string{"inspect", "test"}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) @@ -436,6 +434,7 @@ var _ = Describe("Podman run networking", func() { }) It("podman run in custom CNI network with --static-ip", func() { + SkipIfRemote() SkipIfRootless() netName := "podmantestnetwork" ipAddr := "10.20.30.128" diff --git a/test/e2e/run_ns_test.go b/test/e2e/run_ns_test.go index 96ca2fc56..181b453c1 100644 --- a/test/e2e/run_ns_test.go +++ b/test/e2e/run_ns_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_passwd_test.go b/test/e2e/run_passwd_test.go index 3152f166b..40385e3ad 100644 --- a/test/e2e/run_passwd_test.go +++ b/test/e2e/run_passwd_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_privileged_test.go b/test/e2e/run_privileged_test.go index 03fb71656..8efbe0690 100644 --- a/test/e2e/run_privileged_test.go +++ b/test/e2e/run_privileged_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_restart_test.go b/test/e2e/run_restart_test.go index 0a1c7e134..fa9cb2495 100644 --- a/test/e2e/run_restart_test.go +++ b/test/e2e/run_restart_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -35,11 +33,12 @@ var _ = Describe("Podman run restart containers", func() { }) It("Podman start after successful run", func() { - session := podmanTest.Podman([]string{"run", ALPINE, "ls"}) + SkipIfRemote() + session := podmanTest.Podman([]string{"run", "--name", "test", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session2 := podmanTest.Podman([]string{"start", "--attach", "--latest"}) + session2 := podmanTest.Podman([]string{"start", "--attach", "test"}) session2.WaitWithDefaultTimeout() Expect(session2.ExitCode()).To(Equal(0)) }) diff --git a/test/e2e/run_seccomp.go b/test/e2e/run_seccomp.go index a6a14618c..ec688135b 100644 --- a/test/e2e/run_seccomp.go +++ b/test/e2e/run_seccomp.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_security_labels.go b/test/e2e/run_security_labels.go index 148b18daa..50209a989 100644 --- a/test/e2e/run_security_labels.go +++ b/test/e2e/run_security_labels.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -129,6 +127,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman container runlabel (podman --version)", func() { + SkipIfRemote() PodmanDockerfile := ` FROM alpine:latest LABEL io.containers.capabilities=chown,mknod` diff --git a/test/e2e/run_selinux_test.go b/test/e2e/run_selinux_test.go index 7c1946534..c88441fbc 100644 --- a/test/e2e/run_selinux_test.go +++ b/test/e2e/run_selinux_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go index 8377636cf..de7663cc2 100644 --- a/test/e2e/run_staticip_test.go +++ b/test/e2e/run_staticip_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 9d48f1540..4f4eb1028 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -160,10 +158,10 @@ var _ = Describe("Podman run", func() { }) It("podman run a container with --init", func() { - session := podmanTest.Podman([]string{"run", "--init", ALPINE, "ls"}) + session := podmanTest.Podman([]string{"run", "--name", "test", "--init", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"inspect", "-l"}) + result := podmanTest.Podman([]string{"inspect", "test"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) conData := result.InspectContainerToJSON() @@ -172,10 +170,10 @@ var _ = Describe("Podman run", func() { }) It("podman run a container with --init and --init-path", func() { - session := podmanTest.Podman([]string{"run", "--init", "--init-path", "/usr/libexec/podman/catatonit", ALPINE, "ls"}) + session := podmanTest.Podman([]string{"run", "--name", "test", "--init", "--init-path", "/usr/libexec/podman/catatonit", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"inspect", "-l"}) + result := podmanTest.Podman([]string{"inspect", "test"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) conData := result.InspectContainerToJSON() @@ -184,10 +182,10 @@ var _ = Describe("Podman run", func() { }) It("podman run a container without --init", func() { - session := podmanTest.Podman([]string{"run", ALPINE, "ls"}) + session := podmanTest.Podman([]string{"run", "--name", "test", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"inspect", "-l"}) + result := podmanTest.Podman([]string{"inspect", "test"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) conData := result.InspectContainerToJSON() @@ -259,11 +257,14 @@ var _ = Describe("Podman run", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("00000000a80425fb")) + }) + It("podman run user capabilities test with image", func() { + SkipIfRemote() dockerfile := `FROM busybox USER bin` podmanTest.BuildImage(dockerfile, "test", "false") - session = podmanTest.Podman([]string{"run", "--rm", "--user", "bin", "test", "grep", "CapBnd", "/proc/self/status"}) + session := podmanTest.Podman([]string{"run", "--rm", "--user", "bin", "test", "grep", "CapBnd", "/proc/self/status"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("00000000a80425fb")) @@ -510,6 +511,7 @@ USER bin` }) It("podman run with secrets", func() { + SkipIfRemote() containersDir := filepath.Join(podmanTest.TempDir, "containers") err := os.MkdirAll(containersDir, 0755) Expect(err).To(BeNil()) @@ -674,6 +676,7 @@ USER bin` }) It("podman run with built-in volume image", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"run", "--rm", redis, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -820,16 +823,22 @@ USER mail` }) It("podman run --rm should work", func() { - session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "ls"}) + session := podmanTest.Podman([]string{"run", "--name", "test", "--rm", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) + session = podmanTest.Podman([]string{"wait", "test"}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) numContainers := podmanTest.NumberOfContainers() Expect(numContainers).To(Equal(0)) }) It("podman run --rm failed container should delete itself", func() { - session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "foo"}) + session := podmanTest.Podman([]string{"run", "--name", "test", "--rm", ALPINE, "foo"}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) + session = podmanTest.Podman([]string{"wait", "test"}) session.WaitWithDefaultTimeout() Expect(session).To(ExitWithError()) @@ -841,6 +850,10 @@ USER mail` session := podmanTest.Podman([]string{"run", ALPINE, "foo"}) session.WaitWithDefaultTimeout() Expect(session).To(ExitWithError()) + // If remote we could have a race condition + session = podmanTest.Podman([]string{"wait", "test"}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) numContainers := podmanTest.NumberOfContainers() Expect(numContainers).To(Equal(1)) @@ -881,7 +894,7 @@ USER mail` }) It("podman run with restart-policy always restarts containers", func() { - + SkipIfRemote() testDir := filepath.Join(podmanTest.RunRoot, "restart-test") err := os.MkdirAll(testDir, 0755) Expect(err).To(BeNil()) @@ -995,14 +1008,12 @@ USER mail` }) It("podman run should fail with nonexist authfile", func() { - SkipIfRemote() session := podmanTest.Podman([]string{"run", "--authfile", "/tmp/nonexist", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Not(Equal(0))) }) It("podman run --device-cgroup-rule", func() { - SkipIfRemote() SkipIfRootless() deviceCgroupRule := "c 42:* rwm" session := podmanTest.Podman([]string{"run", "--name", "test", "-d", "--device-cgroup-rule", deviceCgroupRule, ALPINE, "top"}) @@ -1081,4 +1092,35 @@ USER mail` Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring(limit)) }) + + It("podman run umask", func() { + if !strings.Contains(podmanTest.OCIRuntime, "crun") { + Skip("Test only works on crun") + } + + session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "sh", "-c", "umask"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("0022")) + + session = podmanTest.Podman([]string{"run", "--umask", "0002", "--rm", ALPINE, "sh", "-c", "umask"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("0002")) + + session = podmanTest.Podman([]string{"run", "--umask", "0077", "--rm", fedoraMinimal, "umask"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("0077")) + + session = podmanTest.Podman([]string{"run", "--umask", "22", "--rm", ALPINE, "sh", "-c", "umask"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("0022")) + + session = podmanTest.Podman([]string{"run", "--umask", "9999", "--rm", ALPINE, "sh", "-c", "umask"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + Expect(session.ErrorToString()).To(ContainSubstring("Invalid umask")) + }) }) diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go index 42f13537d..b82fa7acb 100644 --- a/test/e2e/run_userns_test.go +++ b/test/e2e/run_userns_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 2b806ac2b..63aa116f8 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -199,6 +197,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("podman run with volumes and suid/dev/exec options", func() { + SkipIfRemote() mountPath := filepath.Join(podmanTest.TempDir, "secrets") os.Mkdir(mountPath, 0755) @@ -228,6 +227,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("podman run with tmpfs named volume mounts and unmounts", func() { + SkipIfRemote() SkipIfRootless() volName := "testvol" mkVolume := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=nodev", "testvol"}) @@ -315,6 +315,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("podman run with anonymous volume", func() { + SkipIfRemote() list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"}) list1.WaitWithDefaultTimeout() Expect(list1.ExitCode()).To(Equal(0)) @@ -333,6 +334,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("podman rm -v removes anonymous volume", func() { + SkipIfRemote() list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"}) list1.WaitWithDefaultTimeout() Expect(list1.ExitCode()).To(Equal(0)) @@ -434,6 +436,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("Podman mount over image volume with trailing /", func() { + SkipIfRemote() image := "podman-volume-test:trailing" dockerfile := ` FROM alpine:latest @@ -453,6 +456,7 @@ VOLUME /test/` }) It("podman run with overlay volume flag", func() { + SkipIfRemote() if os.Getenv("container") != "" { Skip("Overlay mounts not supported when running in a container") } diff --git a/test/e2e/runlabel_test.go b/test/e2e/runlabel_test.go index 3383fbd1e..aae193aa0 100644 --- a/test/e2e/runlabel_test.go +++ b/test/e2e/runlabel_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -48,6 +46,7 @@ var _ = Describe("podman container runlabel", func() { }) It("podman container runlabel (podman --version)", func() { + SkipIfRemote() image := "podman-runlabel-test:podman" podmanTest.BuildImage(PodmanDockerfile, image, "false") @@ -61,6 +60,7 @@ var _ = Describe("podman container runlabel", func() { }) It("podman container runlabel (ls -la)", func() { + SkipIfRemote() image := "podman-runlabel-test:ls" podmanTest.BuildImage(LsDockerfile, image, "false") diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go index aeab3ac56..65e981bbd 100644 --- a/test/e2e/search_test.go +++ b/test/e2e/search_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -229,6 +227,7 @@ registries = ['{{.Host}}:{{.Port}}']` }) It("podman search attempts HTTP if registry is in registries.insecure and force secure is false", func() { + SkipIfRemote() if podmanTest.Host.Arch == "ppc64le" { Skip("No registry image for ppc64le") } @@ -269,6 +268,7 @@ registries = ['{{.Host}}:{{.Port}}']` }) It("podman search doesn't attempt HTTP if force secure is true", func() { + SkipIfRemote() if podmanTest.Host.Arch == "ppc64le" { Skip("No registry image for ppc64le") } @@ -307,6 +307,7 @@ registries = ['{{.Host}}:{{.Port}}']` }) It("podman search doesn't attempt HTTP if registry is not listed as insecure", func() { + SkipIfRemote() if podmanTest.Host.Arch == "ppc64le" { Skip("No registry image for ppc64le") } @@ -345,6 +346,7 @@ registries = ['{{.Host}}:{{.Port}}']` }) It("podman search doesn't attempt HTTP if one registry is not listed as insecure", func() { + SkipIfRemote() if podmanTest.Host.Arch == "ppc64le" { Skip("No registry image for ppc64le") } diff --git a/test/e2e/system_df_test.go b/test/e2e/system_df_test.go index f17afaec1..b179a29d4 100644 --- a/test/e2e/system_df_test.go +++ b/test/e2e/system_df_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -37,6 +35,7 @@ var _ = Describe("podman system df", func() { }) It("podman system df", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"create", ALPINE}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go index 7b9be2275..268f62f5b 100644 --- a/test/e2e/systemd_test.go +++ b/test/e2e/systemd_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/top_test.go b/test/e2e/top_test.go index 157a7fe46..f4d1ec857 100644 --- a/test/e2e/top_test.go +++ b/test/e2e/top_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -55,22 +53,22 @@ var _ = Describe("Podman top", func() { }) It("podman top on container", func() { - session := podmanTest.Podman([]string{"run", "-d", ALPINE, "top", "-d", "2"}) + session := podmanTest.Podman([]string{"run", "--name", "test", "-d", ALPINE, "top", "-d", "2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"top", "-l"}) + result := podmanTest.Podman([]string{"top", "test"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1)) }) It("podman container top on container", func() { - session := podmanTest.Podman([]string{"container", "run", "-d", ALPINE, "top", "-d", "2"}) + session := podmanTest.Podman([]string{"container", "run", "--name", "test", "-d", ALPINE, "top", "-d", "2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"container", "top", "-l"}) + result := podmanTest.Podman([]string{"container", "top", "test"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1)) diff --git a/test/e2e/volume_prune_test.go b/test/e2e/volume_prune_test.go index c4fafa406..d98b02824 100644 --- a/test/e2e/volume_prune_test.go +++ b/test/e2e/volume_prune_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/system/015-help.bats b/test/system/015-help.bats index 3d05b44fe..76d29d22c 100644 --- a/test/system/015-help.bats +++ b/test/system/015-help.bats @@ -78,7 +78,8 @@ function check_help() { if ! expr "$usage" : '.*[A-Z]' >/dev/null; then if [ "$cmd" != "help" ]; then dprint "$command_string invalid-arg" - run_podman 125 "$@" $cmd invalid-arg + run_podman '?' "$@" $cmd invalid-arg + is "$status" 125 "'$command_string invalid-arg' - exit status" is "$output" "Error: .* takes no arguments" \ "'$command_string' with extra (invalid) arguments" fi @@ -104,7 +105,8 @@ function check_help() { # The </dev/null protects us from 'podman login' which will # try to read username/password from stdin. dprint "$command_string (without required args)" - run_podman 125 "$@" $cmd </dev/null + run_podman '?' "$@" $cmd </dev/null + is "$status" 125 "'$command_string' with no arguments - exit status" is "$output" "Error:.* \(require\|specif\|must\|provide\|need\|choose\|accepts\)" \ "'$command_string' without required arg" @@ -126,7 +128,8 @@ function check_help() { local rhs=$(sed -e 's/^[^A-Z]\+[A-Z]/X/' -e 's/ | /-or-/g' <<<"$usage") local n_args=$(wc -w <<<"$rhs") - run_podman 125 "$@" $cmd $(seq --format='x%g' 0 $n_args) + run_podman '?' "$@" $cmd $(seq --format='x%g' 0 $n_args) + is "$status" 125 "'$command_string' with >$n_args arguments - exit status" is "$output" "Error:.* \(takes no arguments\|requires exactly $n_args arg\|accepts at most\|too many arguments\|accepts $n_args arg(s), received\|accepts between .* and .* arg(s), received \)" \ "'$command_string' with >$n_args arguments" @@ -140,13 +143,17 @@ function check_help() { # Any command that takes subcommands, must throw error if called # without one. dprint "podman $@" - run_podman 125 "$@" - is "$output" "Error: missing command .*$@ COMMAND" + run_podman '?' "$@" + is "$status" 125 "'podman $*' without any subcommand - exit status" + is "$output" "Error: missing command .*$@ COMMAND" \ + "'podman $*' without any subcommand - expected error message" # Assume that 'NoSuchCommand' is not a command dprint "podman $@ NoSuchCommand" - run_podman 125 "$@" NoSuchCommand - is "$output" "Error: unrecognized command .*$@ NoSuchCommand" + run_podman '?' "$@" NoSuchCommand + is "$status" 125 "'podman $* NoSuchCommand' - exit status" + is "$output" "Error: unrecognized command .*$@ NoSuchCommand" \ + "'podman $* NoSuchCommand' - expected error message" # This can happen if the output of --help changes, such as between # the old command parser and cobra. diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go index b3278bb28..80c478505 100644 --- a/vendor/github.com/containers/common/pkg/config/config.go +++ b/vendor/github.com/containers/common/pkg/config/config.go @@ -622,9 +622,17 @@ func (c *ContainersConfig) Validate() error { // execution checks. It returns an `error` on validation failure, otherwise // `nil`. func (c *NetworkConfig) Validate() error { - if c.NetworkConfigDir != _cniConfigDir { - err := isDirectory(c.NetworkConfigDir) + expectedConfigDir := _cniConfigDir + if unshare.IsRootless() { + home, err := unshare.HomeDir() if err != nil { + return err + } + expectedConfigDir = filepath.Join(home, _cniConfigDirRootless) + } + if c.NetworkConfigDir != expectedConfigDir { + err := isDirectory(c.NetworkConfigDir) + if err != nil && !os.IsNotExist(err) { return errors.Wrapf(err, "invalid network_config_dir: %s", c.NetworkConfigDir) } } @@ -874,6 +882,10 @@ func Default() (*Config, error) { if config != nil || configErr != nil { return config, configErr } + return defConfig() +} + +func defConfig() (*Config, error) { config, configErr = NewConfig("") return config, configErr } @@ -969,13 +981,11 @@ func (c *Config) Write() error { // the cached containers.conf files. func Reload() (*Config, error) { configMutex.Lock() - configErr = nil - config = nil - configMutex.Unlock() - return Default() + defer configMutex.Unlock() + return defConfig() } -func (c *Config) ActiveDestination() (string, string, error){ +func (c *Config) ActiveDestination() (string, string, error) { if uri, found := os.LookupEnv("CONTAINER_HOST"); found { var ident string if v, found := os.LookupEnv("CONTAINER_SSHKEY"); found { diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go index 12cf1b421..57b703f53 100644 --- a/vendor/github.com/containers/common/pkg/config/default.go +++ b/vendor/github.com/containers/common/pkg/config/default.go @@ -92,8 +92,10 @@ const ( // InstallPrefix is the prefix where podman will be installed. // It can be overridden at build time. _installPrefix = "/usr" - // _cniConfigDir is the directory where cni plugins are found + // _cniConfigDir is the directory where cni configuration is found _cniConfigDir = "/etc/cni/net.d/" + // _cniConfigDirRootless is the directory where cni plugins are found + _cniConfigDirRootless = ".config/cni/net.d/" // CgroupfsCgroupsManager represents cgroupfs native cgroup manager CgroupfsCgroupsManager = "cgroupfs" // DefaultApparmorProfile specifies the default apparmor profile for the container. @@ -138,6 +140,8 @@ func DefaultConfig() (*Config, error) { netns := "bridge" + cniConfig := _cniConfigDir + defaultEngineConfig.SignaturePolicyPath = DefaultSignaturePolicyPath if unshare.IsRootless() { home, err := unshare.HomeDir() @@ -152,6 +156,7 @@ func DefaultConfig() (*Config, error) { } } netns = "slirp4netns" + cniConfig = filepath.Join(home, _cniConfigDirRootless) } cgroupNS := "host" @@ -198,7 +203,7 @@ func DefaultConfig() (*Config, error) { }, Network: NetworkConfig{ DefaultNetwork: "podman", - NetworkConfigDir: _cniConfigDir, + NetworkConfigDir: cniConfig, CNIPluginDirs: cniBinDir, }, Engine: *defaultEngineConfig, diff --git a/vendor/github.com/containers/common/pkg/config/systemd.go b/vendor/github.com/containers/common/pkg/config/systemd.go index e02f52192..02e5c4ac2 100644 --- a/vendor/github.com/containers/common/pkg/config/systemd.go +++ b/vendor/github.com/containers/common/pkg/config/systemd.go @@ -2,7 +2,17 @@ package config +import ( + "github.com/containers/common/pkg/cgroupv2" + "github.com/containers/storage/pkg/unshare" +) + func defaultCgroupManager() string { + enabled, err := cgroupv2.Enabled() + if err == nil && !enabled && unshare.IsRootless() { + return CgroupfsCgroupsManager + } + return SystemdCgroupsManager } func defaultEventsLogger() string { diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go index b75bbe971..6b226eabe 100644 --- a/vendor/github.com/containers/common/version/version.go +++ b/vendor/github.com/containers/common/version/version.go @@ -1,4 +1,4 @@ package version // Version is the version of the build. -const Version = "0.16.0" +const Version = "0.18.0" diff --git a/vendor/github.com/containers/storage/VERSION b/vendor/github.com/containers/storage/VERSION index 284497740..0369d0b1e 100644 --- a/vendor/github.com/containers/storage/VERSION +++ b/vendor/github.com/containers/storage/VERSION @@ -1 +1 @@ -1.21.1 +1.21.2 diff --git a/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go b/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go index b7a95bfc2..cba3d05ea 100644 --- a/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go +++ b/vendor/github.com/containers/storage/drivers/devmapper/deviceset.go @@ -1749,7 +1749,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) { // - Managed by container storage // - The target of this device is at major <maj> and minor <min> // - If <inode> is defined, use that file inside the device as a loopback image. Otherwise use the device itself. - devices.devicePrefix = fmt.Sprintf("container-%d:%d-%d", major(st.Dev), minor(st.Dev), st.Ino) + devices.devicePrefix = fmt.Sprintf("container-%d:%d-%d", major(uint64(st.Dev)), minor(uint64(st.Dev)), st.Ino) logrus.Debugf("devmapper: Generated prefix: %s", devices.devicePrefix) // Check for the existence of the thin-pool device diff --git a/vendor/github.com/containers/storage/pkg/archive/archive.go b/vendor/github.com/containers/storage/pkg/archive/archive.go index 863465456..78744e0f3 100644 --- a/vendor/github.com/containers/storage/pkg/archive/archive.go +++ b/vendor/github.com/containers/storage/pkg/archive/archive.go @@ -393,13 +393,15 @@ func fillGo18FileTypeBits(mode int64, fi os.FileInfo) int64 { // ReadSecurityXattrToTarHeader reads security.capability, security,image // xattrs from filesystem to a tar header func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error { + if hdr.Xattrs == nil { + hdr.Xattrs = make(map[string]string) + } for _, xattr := range []string{"security.capability", "security.ima"} { capability, err := system.Lgetxattr(path, xattr) if err != nil && err != system.EOPNOTSUPP && err != system.ErrNotSupportedPlatform { return errors.Wrapf(err, "failed to read %q attribute from %q", xattr, path) } if capability != nil { - hdr.Xattrs = make(map[string]string) hdr.Xattrs[xattr] = string(capability) } } diff --git a/vendor/github.com/containers/storage/pkg/unshare/unshare.go b/vendor/github.com/containers/storage/pkg/unshare/unshare.go index 1eff82e8e..a08fb674d 100644 --- a/vendor/github.com/containers/storage/pkg/unshare/unshare.go +++ b/vendor/github.com/containers/storage/pkg/unshare/unshare.go @@ -4,19 +4,30 @@ import ( "fmt" "os" "os/user" + "sync" "github.com/pkg/errors" ) +var ( + homeDirOnce sync.Once + homeDirErr error + homeDir string +) + // HomeDir returns the home directory for the current user. func HomeDir() (string, error) { - home := os.Getenv("HOME") - if home == "" { - usr, err := user.LookupId(fmt.Sprintf("%d", GetRootlessUID())) - if err != nil { - return "", errors.Wrapf(err, "unable to resolve HOME directory") + homeDirOnce.Do(func() { + home := os.Getenv("HOME") + if home == "" { + usr, err := user.LookupId(fmt.Sprintf("%d", GetRootlessUID())) + if err != nil { + homeDir, homeDirErr = "", errors.Wrapf(err, "unable to resolve HOME directory") + return + } + homeDir, homeDirErr = usr.HomeDir, nil } - home = usr.HomeDir - } - return home, nil + homeDir, homeDirErr = home, nil + }) + return homeDir, homeDirErr } diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/generate.go b/vendor/github.com/opencontainers/runtime-tools/generate/generate.go index 6d3268902..c757c20e0 100644 --- a/vendor/github.com/opencontainers/runtime-tools/generate/generate.go +++ b/vendor/github.com/opencontainers/runtime-tools/generate/generate.go @@ -29,6 +29,9 @@ var ( type Generator struct { Config *rspec.Spec HostSpecific bool + // This is used to keep a cache of the ENVs added to improve + // performance when adding a huge number of ENV variables + envMap map[string]int } // ExportOptions have toggles for exporting only certain parts of the specification @@ -236,7 +239,12 @@ func New(os string) (generator Generator, err error) { } } - return Generator{Config: &config}, nil + envCache := map[string]int{} + if config.Process != nil { + envCache = createEnvCacheMap(config.Process.Env) + } + + return Generator{Config: &config, envMap: envCache}, nil } // NewFromSpec creates a configuration Generator from a given @@ -246,8 +254,14 @@ func New(os string) (generator Generator, err error) { // // generator := Generator{Config: config} func NewFromSpec(config *rspec.Spec) Generator { + envCache := map[string]int{} + if config != nil && config.Process != nil { + envCache = createEnvCacheMap(config.Process.Env) + } + return Generator{ Config: config, + envMap: envCache, } } @@ -273,11 +287,27 @@ func NewFromTemplate(r io.Reader) (Generator, error) { if err := json.NewDecoder(r).Decode(&config); err != nil { return Generator{}, err } + + envCache := map[string]int{} + if config.Process != nil { + envCache = createEnvCacheMap(config.Process.Env) + } + return Generator{ Config: &config, + envMap: envCache, }, nil } +// createEnvCacheMap creates a hash map with the ENV variables given by the config +func createEnvCacheMap(env []string) map[string]int { + envMap := make(map[string]int, len(env)) + for i, val := range env { + envMap[val] = i + } + return envMap +} + // SetSpec sets the configuration in the Generator g. // // Deprecated: Replace with: @@ -414,6 +444,12 @@ func (g *Generator) SetProcessUsername(username string) { g.Config.Process.User.Username = username } +// SetProcessUmask sets g.Config.Process.User.Umask. +func (g *Generator) SetProcessUmask(umask uint32) { + g.initConfigProcess() + g.Config.Process.User.Umask = umask +} + // SetProcessGID sets g.Config.Process.User.GID. func (g *Generator) SetProcessGID(gid uint32) { g.initConfigProcess() @@ -456,21 +492,44 @@ func (g *Generator) ClearProcessEnv() { return } g.Config.Process.Env = []string{} + // Clear out the env cache map as well + g.envMap = map[string]int{} } // AddProcessEnv adds name=value into g.Config.Process.Env, or replaces an // existing entry with the given name. func (g *Generator) AddProcessEnv(name, value string) { + if name == "" { + return + } + g.initConfigProcess() + g.addEnv(fmt.Sprintf("%s=%s", name, value), name) +} - env := fmt.Sprintf("%s=%s", name, value) - for idx := range g.Config.Process.Env { - if strings.HasPrefix(g.Config.Process.Env[idx], name+"=") { - g.Config.Process.Env[idx] = env - return - } +// AddMultipleProcessEnv adds multiple name=value into g.Config.Process.Env, or replaces +// existing entries with the given name. +func (g *Generator) AddMultipleProcessEnv(envs []string) { + g.initConfigProcess() + + for _, val := range envs { + split := strings.SplitN(val, "=", 2) + g.addEnv(val, split[0]) + } +} + +// addEnv looks through adds ENV to the Process and checks envMap for +// any duplicates +// This is called by both AddMultipleProcessEnv and AddProcessEnv +func (g *Generator) addEnv(env, key string) { + if idx, ok := g.envMap[key]; ok { + // The ENV exists in the cache, so change its value in g.Config.Process.Env + g.Config.Process.Env[idx] = env + } else { + // else the env doesn't exist, so add it and add it's index to g.envMap + g.Config.Process.Env = append(g.Config.Process.Env, env) + g.envMap[key] = len(g.Config.Process.Env) - 1 } - g.Config.Process.Env = append(g.Config.Process.Env, env) } // AddProcessRlimits adds rlimit into g.Config.Process.Rlimits. @@ -1443,7 +1502,7 @@ func (g *Generator) AddDevice(device rspec.LinuxDevice) { return } if dev.Type == device.Type && dev.Major == device.Major && dev.Minor == device.Minor { - fmt.Fprintln(os.Stderr, "WARNING: The same type, major and minor should not be used for multiple devices.") + fmt.Fprintf(os.Stderr, "WARNING: Creating device %q with same type, major and minor as existing %q.\n", device.Path, dev.Path) } } diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go index 5fee5a3b2..8a8dc3970 100644 --- a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go +++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go @@ -566,6 +566,20 @@ func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp { }, }...) /* Flags parameter of the clone syscall is the 2nd on s390 */ + syscalls = append(syscalls, []rspec.LinuxSyscall{ + { + Names: []string{"clone"}, + Action: rspec.ActAllow, + Args: []rspec.LinuxSeccompArg{ + { + Index: 1, + Value: 2080505856, + ValueTwo: 0, + Op: rspec.OpMaskedEqual, + }, + }, + }, + }...) } return &rspec.LinuxSeccomp{ diff --git a/vendor/modules.txt b/vendor/modules.txt index 913cb71eb..7cd0f86df 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -84,7 +84,7 @@ github.com/containers/buildah/pkg/secrets github.com/containers/buildah/pkg/supplemented github.com/containers/buildah/pkg/umask github.com/containers/buildah/util -# github.com/containers/common v0.16.0 +# github.com/containers/common v0.18.0 github.com/containers/common/pkg/apparmor github.com/containers/common/pkg/auth github.com/containers/common/pkg/capabilities @@ -155,7 +155,7 @@ github.com/containers/psgo/internal/dev github.com/containers/psgo/internal/host github.com/containers/psgo/internal/proc github.com/containers/psgo/internal/process -# github.com/containers/storage v1.21.1 +# github.com/containers/storage v1.21.2 github.com/containers/storage github.com/containers/storage/drivers github.com/containers/storage/drivers/aufs @@ -421,7 +421,7 @@ github.com/opencontainers/runc/libcontainer/user github.com/opencontainers/runc/libcontainer/utils # github.com/opencontainers/runtime-spec v1.0.3-0.20200520003142-237cc4f519e2 github.com/opencontainers/runtime-spec/specs-go -# github.com/opencontainers/runtime-tools v0.9.0 +# github.com/opencontainers/runtime-tools v0.9.1-0.20200714183735-07406c5828aa github.com/opencontainers/runtime-tools/error github.com/opencontainers/runtime-tools/filepath github.com/opencontainers/runtime-tools/generate |