diff --git a/Makefile b/Makefile index cf796ed3c6..d63cb45497 100644 --- a/Makefile +++ b/Makefile @@ -59,10 +59,11 @@ PKG_MANAGER ?= $(shell command -v dnf yum|head -n1) PRE_COMMIT = $(shell command -v bin/venv/bin/pre-commit ~/.local/bin/pre-commit pre-commit | head -n1) # This isn't what we actually build; it's a superset, used for target -# dependencies. Basically: all *.go files, except *_test.go, and except -# anything in a dot subdirectory. If any of these files is newer than -# our target (bin/podman{,-remote}), a rebuild is triggered. -SOURCES = $(shell find . -path './.*' -prune -o \( -name '*.go' -a ! -name '*_test.go' \) -print) +# dependencies. Basically: all *.go and *.c files, except *_test.go, +# and except anything in a dot subdirectory. If any of these files is +# newer than our target (bin/podman{,-remote}), a rebuild is +# triggered. +SOURCES = $(shell find . -path './.*' -prune -o \( \( -name '*.go' -o -name '*.c' \) -a ! -name '*_test.go' \) -print) BUILDFLAGS := -mod=vendor $(BUILDFLAGS) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index cca300f076..110de4376a 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,24 @@ # Release Notes +## 3.4.2 +### Bugfixes +- Fixed a bug where `podman tag` could not tag manifest lists ([#12046](https://github.com/containers/podman/issues/12046)). +- Fixed a bug where built-in volumes specified by images would not be created correctly under some circumstances. +- Fixed a bug where, when using Podman Machine on OS X, containers in pods did not have working port forwarding from the host ([#12207](https://github.com/containers/podman/issues/12207)). +- Fixed a bug where the `podman network reload` command command on containers using the `slirp4netns` network mode and the `rootlessport` port forwarding driver would make an unnecessary attempt to restart `rootlessport` on containers that did not forward ports. +- Fixed a bug where the `podman generate kube` command would generate YAML including some unnecessary (set to default) fields (e.g. empty SELinux and DNS configuration blocks, and the `privileged` flag when set to false) ([#11995](https://github.com/containers/podman/issues/11995)). +- Fixed a bug where the `podman pod rm` command could, if interrupted at the right moment, leave a reference to an already-removed infra container behind ([#12034](https://github.com/containers/podman/issues/12034)). +- Fixed a bug where the `podman pod rm` command would not remove pods with more than one container if all containers save for the infra container were stopped unless `--force` was specified ([#11713](https://github.com/containers/podman/issues/11713)). +- Fixed a bug where the `--memory` flag to `podman run` and `podman create` did not accept a limit of 0 (which should specify unlimited memory) ([#12002](https://github.com/containers/podman/issues/12002)). +- Fixed a bug where the remote Podman client's `podman build` command could attempt to build a Dockerfile in the working directory of the `podman system service` instance instead of the Dockerfile specified by the user ([#12054](https://github.com/containers/podman/issues/12054)). +- Fixed a bug where the `podman logs --tail` command could function improperly (printing more output than requested) when the `journald` log driver was used. +- Fixed a bug where containers run using the `slirp4netns` network mode with IPv6 enabled would not have IPv6 connectivity until several seconds after they started ([#11062](https://github.com/containers/podman/issues/11062)). +- Fixed a bug where some Podman commands could cause an extra `dbus-daemon` process to be created ([#9727](https://github.com/containers/podman/issues/9727)). +- Fixed a bug where rootless Podman would sometimes print warnings about a failure to move the pause process into a given CGroup ([#12065](https://github.com/containers/podman/issues/12065)). +- Fixed a bug where the `checkpointed` field in `podman inspect` on a container was not set to false after a container was restored. +- Fixed a bug where the `podman system service` command would print overly-verbose logs about request IDs ([#12181](https://github.com/containers/podman/issues/12181)). +- Fixed a bug where Podman could, when creating a new container without a name explicitly specified by the user, sometimes use an auto-generated name already in use by another container if multiple containers were being created in parallel ([#11735](https://github.com/containers/podman/issues/11735)). + ## 3.4.1 ### Bugfixes - Fixed a bug where `podman machine init` could, under some circumstances, create invalid machine configurations which could not be started ([#11824](https://github.com/containers/podman/issues/11824)). @@ -133,7 +152,7 @@ ### Features - Containers inside VMs created by `podman machine` will now automatically handle port forwarding - containers in `podman machine` VMs that publish ports via `--publish` or `--publish-all` will have these ports not just forwarded on the VM, but also on the host system. - The `podman play kube` command's `--network` option now accepts advanced network options (e.g. `--network slirp4netns:port_handler=slirp4netns`) ([#10807](https://github.com/containers/podman/issues/10807)). -- The `podman play kube` commmand now supports Kubernetes liveness probes, which will be created as Podman healthchecks. +- The `podman play kube` command now supports Kubernetes liveness probes, which will be created as Podman healthchecks. - Podman now provides a systemd unit, `podman-restart.service`, which, when enabled, will restart all containers that were started with `--restart=always` after the system reboots. - Rootless Podman can now be configured to use CNI networking by default by using the `rootless_networking` option in `containers.conf`. - Images can now be pulled using `image:tag@digest` syntax (e.g. `podman pull fedora:34@sha256:1b0d4ddd99b1a8c8a80e885aafe6034c95f266da44ead992aab388e6aa91611a`) ([#6721](https://github.com/containers/podman/issues/6721)). @@ -389,7 +408,7 @@ - Fixed a bug where images with empty layers were stored incorrectly, causing them to be unable to be pushed or saved. - Fixed a bug where the `podman rmi` command could fail to remove corrupt images from storage. - Fixed a bug where the remote Podman client's `podman save` command did not support the `oci-dir` and `docker-dir` formats ([#9742](https://github.com/containers/podman/issues/9742)). -- Fixed a bug where volume mounts from `podman play kube` created with a trailing `/` in the container path were were not properly superceding named volumes from the image ([#9618](https://github.com/containers/podman/issues/9618)). +- Fixed a bug where volume mounts from `podman play kube` created with a trailing `/` in the container path were were not properly superseding named volumes from the image ([#9618](https://github.com/containers/podman/issues/9618)). - Fixed a bug where Podman could fail to build on 32-bit architectures. ### Misc @@ -1034,7 +1053,7 @@ ## 2.0.5 ### Features - Rootless Podman will now add an entry to `/etc/passwd` for the user who ran Podman if run with `--userns=keep-id`. -- The `podman system connection` command has been reworked to support multiple connections, and reenabled for use! +- The `podman system connection` command has been reworked to support multiple connections, and re-enabled for use! - Podman now has a new global flag, `--connection`, to specify a connection to a remote Podman API instance. ### Changes diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index b3dfc49674..643f6728a1 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -426,7 +426,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, createFlags.StringVar( &cf.Variant, variantFlagName, "", - "Use _VARIANT_ instead of the running architecture variant for choosing images", + "Use `VARIANT` instead of the running architecture variant for choosing images", ) _ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone) diff --git a/cmd/podman/containers/start.go b/cmd/podman/containers/start.go index 1163b90935..8813fc2730 100644 --- a/cmd/podman/containers/start.go +++ b/cmd/podman/containers/start.go @@ -87,6 +87,9 @@ func validateStart(cmd *cobra.Command, args []string) error { if len(args) == 0 && !startOptions.Latest && !startOptions.All { return errors.New("start requires at least one argument") } + if startOptions.All && startOptions.Latest { + return errors.Errorf("--all and --latest cannot be used together") + } if len(args) > 0 && startOptions.Latest { return errors.Errorf("--latest and containers cannot be used together") } diff --git a/cmd/podman/images/pull.go b/cmd/podman/images/pull.go index a4e3515db0..a990d16265 100644 --- a/cmd/podman/images/pull.go +++ b/cmd/podman/images/pull.go @@ -92,7 +92,7 @@ func pullFlags(cmd *cobra.Command) { _ = cmd.RegisterFlagCompletionFunc(osFlagName, completion.AutocompleteOS) variantFlagName := "variant" - flags.StringVar(&pullOptions.Variant, variantFlagName, "", " use VARIANT instead of the running architecture variant for choosing images") + flags.StringVar(&pullOptions.Variant, variantFlagName, "", "Use VARIANT instead of the running architecture variant for choosing images") _ = cmd.RegisterFlagCompletionFunc(variantFlagName, completion.AutocompleteNone) platformFlagName := "platform" diff --git a/cmd/podman/images/scp.go b/cmd/podman/images/scp.go index 1765634406..c89a090bf5 100644 --- a/cmd/podman/images/scp.go +++ b/cmd/podman/images/scp.go @@ -185,7 +185,7 @@ func saveToRemote(image, localFile string, tag string, uri *urlP.URL, iden strin return errors.Wrapf(define.ErrInvalidArg, "Renaming of an image is currently not supported") } podman := os.Args[0] - run := podman + " image save " + image + " --format=oci-archive --output=" + remoteFile // run ssh image load of the file copied via scp. Files are reverse in thie case... + run := podman + " image save " + image + " --format=oci-archive --output=" + remoteFile // run ssh image load of the file copied via scp. Files are reverse in this case... _, err = connection.ExecRemoteCommand(dial, run) if err != nil { return nil diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go index 4502b156cc..f71af8e72a 100644 --- a/cmd/podman/system/version.go +++ b/cmd/podman/system/version.go @@ -20,7 +20,7 @@ var ( versionCommand = &cobra.Command{ Use: "version [options]", Args: validate.NoArgs, - Short: "Display the Podman Version Information", + Short: "Display the Podman version information", RunE: version, ValidArgsFunction: completion.AutocompleteNone, } diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index 9a7bfba8fa..9b7c613f5d 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -143,6 +143,8 @@ setup_rootless() { local rootless_uid local rootless_gid local env_var_val + local akfilepath + local sshcmd # Only do this once; established by setup_environment.sh # shellcheck disable=SC2154 @@ -169,24 +171,25 @@ setup_rootless() { ssh-keygen -P "" -f "$HOME/.ssh/id_rsa" msg "Allowing ssh key for $ROOTLESS_USER" + akfilepath="/home/$ROOTLESS_USER/.ssh/authorized_keys" (umask 077 && mkdir "/home/$ROOTLESS_USER/.ssh") chown -R $ROOTLESS_USER:$ROOTLESS_USER "/home/$ROOTLESS_USER/.ssh" install -o $ROOTLESS_USER -g $ROOTLESS_USER -m 0600 \ - "$HOME/.ssh/id_rsa.pub" "/home/$ROOTLESS_USER/.ssh/authorized_keys" + "$HOME/.ssh/id_rsa.pub" "$akfilepath" # Makes debugging easier - cat /root/.ssh/authorized_keys >> "/home/$ROOTLESS_USER/.ssh/authorized_keys" - - msg "Configuring subuid and subgid" - grep -q "${ROOTLESS_USER}" /etc/subuid || \ - echo "${ROOTLESS_USER}:$[rootless_uid * 100]:65536" | \ - tee -a /etc/subuid >> /etc/subgid + cat /root/.ssh/authorized_keys >> "$akfilepath" msg "Ensure the ssh daemon is up and running within 5 minutes" systemctl start sshd - lilto ssh $ROOTLESS_USER@localhost \ - -o UserKnownHostsFile=/dev/null \ - -o StrictHostKeyChecking=no \ - -o CheckHostIP=no true + sshcmd="ssh $ROOTLESS_USER@localhost + -o UserKnownHostsFile=/dev/null + -o StrictHostKeyChecking=no + -o CheckHostIP=no" + lilto $sshcmd true # retry until sshd is up + + msg "Configuring rootless user self-access to ssh to localhost" + $sshcmd ssh-keygen -P '""' -f "/home/$ROOTLESS_USER/.ssh/id_rsa" + cat "/home/$ROOTLESS_USER/.ssh/id_rsa" >> "$akfilepath" } install_test_configs() { diff --git a/contrib/cirrus/pr-should-include-tests b/contrib/cirrus/pr-should-include-tests index 4b63293115..8103df41d7 100755 --- a/contrib/cirrus/pr-should-include-tests +++ b/contrib/cirrus/pr-should-include-tests @@ -12,9 +12,6 @@ fi if [[ "${CIRRUS_CHANGE_MESSAGE}" =~ NO.NEW.TESTS.NEEDED ]]; then exit 0 fi -if [[ "${CIRRUS_CHANGE_MESSAGE}" =~ NO.TESTS.NEEDED ]]; then - exit 0 -fi # HEAD should be good enough, but the CIRRUS envariable allows us to test head=${CIRRUS_CHANGE_IN_REPO:-HEAD} @@ -52,14 +49,11 @@ if [[ -z "$filtered_changes" ]]; then exit 0 fi -# One last chance: perhaps the developer included the magic '[NO (NEW) TESTS NEEDED]' +# One last chance: perhaps the developer included the magic '[NO NEW TESTS NEEDED]' # string in an amended commit. if git log --format=%B ${base}..${head} | fgrep '[NO NEW TESTS NEEDED]'; then exit 0 fi -if git log --format=%B ${base}..${head} | fgrep '[NO TESTS NEEDED]'; then - exit 0 -fi cat < /etc/subuid; \ echo podman:10000:5000 > /etc/subgid; -VOLUME /var/lib/containers -VOLUME /home/podman/.local/share/containers -RUN mkdir -p /home/podman/.local/share/containers +RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf -RUN chown podman:podman -R /home/podman +# Note VOLUME options must always happen after the chown call above +# RUN commands can not modify existing volumes +VOLUME /var/lib/containers +VOLUME /home/podman/.local/share/containers # chmod containers.conf and adjust storage.conf to enable Fuse storage. RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf diff --git a/contrib/podmanimage/testing/Dockerfile b/contrib/podmanimage/testing/Dockerfile index 58b11a20b9..03da058062 100644 --- a/contrib/podmanimage/testing/Dockerfile +++ b/contrib/podmanimage/testing/Dockerfile @@ -19,14 +19,15 @@ RUN useradd podman; \ echo podman:10000:5000 > /etc/subuid; \ echo podman:10000:5000 > /etc/subgid; -VOLUME /var/lib/containers -VOLUME /home/podman/.local/share/containers -RUN mkdir -p /home/podman/.local/share/containers +RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf -RUN chown podman:podman -R /home/podman +# Note VOLUME options must always happen after the chown call above +# RUN commands can not modify existing volumes +VOLUME /var/lib/containers +VOLUME /home/podman/.local/share/containers # chmod containers.conf and adjust storage.conf to enable Fuse storage. RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf diff --git a/contrib/podmanimage/upstream/Dockerfile b/contrib/podmanimage/upstream/Dockerfile index 75de947ea3..89ec6e39b5 100644 --- a/contrib/podmanimage/upstream/Dockerfile +++ b/contrib/podmanimage/upstream/Dockerfile @@ -68,14 +68,15 @@ RUN useradd podman; \ echo podman:10000:5000 > /etc/subuid; \ echo podman:10000:5000 > /etc/subgid; -VOLUME /var/lib/containers -VOLUME /home/podman/.local/share/containers -RUN mkdir -p /home/podman/.local/share/containers +RUN mkdir -p /home/podman/.local/share/containers; chown podman:podman -R /home/podman ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/containers.conf /etc/containers/containers.conf ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanimage/stable/podman-containers.conf /home/podman/.config/containers/containers.conf -RUN chown podman:podman -R /home/podman +# Note VOLUME options must always happen after the chown call above +# RUN commands can not modify existing volumes +VOLUME /var/lib/containers +VOLUME /home/podman/.local/share/containers # chmod containers.conf and adjust storage.conf to enable Fuse storage. RUN chmod 644 /etc/containers/containers.conf; sed -i -e 's|^#mount_program|mount_program|g' -e '/additionalimage.*/a "/var/lib/shared",' -e 's|^mountopt[[:space:]]*=.*$|mountopt = "nodev,fsync=0"|g' /etc/containers/storage.conf diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in index 683797cd0f..00f9ad6d01 100644 --- a/contrib/spec/podman.spec.in +++ b/contrib/spec/podman.spec.in @@ -36,7 +36,7 @@ Epoch: 99 %else Epoch: 0 %endif -Version: 3.4.2 +Version: 3.4.3 Release: #COMMITDATE#.git%{shortcommit0}%{?dist} Summary: Manage Pods, Containers and Container Images License: ASL 2.0 diff --git a/contrib/systemd/system/podman-restart.service b/contrib/systemd/system/podman-restart.service index baf12b3aed..b8c1adca2a 100644 --- a/contrib/systemd/system/podman-restart.service +++ b/contrib/systemd/system/podman-restart.service @@ -5,8 +5,9 @@ StartLimitIntervalSec=0 [Service] Type=oneshot +RemainAfterExit=true Environment=LOGGING="--log-level=info" ExecStart=/usr/bin/podman $LOGGING start --all --filter restart-policy=always [Install] -WantedBy=multi-user.target +WantedBy=multi-user.target default.target diff --git a/docs/source/markdown/podman-build.1.md b/docs/source/markdown/podman-build.1.md index 0f52ad592d..965f5319fb 100644 --- a/docs/source/markdown/podman-build.1.md +++ b/docs/source/markdown/podman-build.1.md @@ -631,7 +631,7 @@ Sets the configuration for user namespaces when handling `RUN` instructions. The configured value can be "" (the empty string) or "container" to indicate that a new user namespace should be created, it can be "host" to indicate that the user namespace in which `podman` itself is being run should be reused, or -it can be the path to an user namespace which is already in use by another +it can be the path to a user namespace which is already in use by another process. #### **--userns-uid-map**=*mapping* @@ -774,6 +774,14 @@ content label. Shared volume labels allow all containers to read/write content. The `Z` option tells Podman to label the content with a private unshared label. Only the current container can use a private volume. +Note: Do not relabel system files and directories. Relabeling system content +might cause other confined services on your machine to fail. For these types +of containers, disabling SELinux separation is recommended. The option +`--security-opt label=disable` disables SELinux separation for the container. +For example, if a user wanted to volume mount their entire home directory into the build containers, they need to disable SELinux separation. + + $ podman build --security-opt label=disable -v $HOME:/home/user . + `Overlay Volume Mounts` The `:O` flag tells Podman to mount the directory from the host as a diff --git a/docs/source/markdown/podman-completion.1.md b/docs/source/markdown/podman-completion.1.md index 6393323652..41f5043630 100644 --- a/docs/source/markdown/podman-completion.1.md +++ b/docs/source/markdown/podman-completion.1.md @@ -40,7 +40,7 @@ Shell completion needs to be already enabled in the environment. The following c **echo "autoload -U compinit; compinit" >> ~/.zshrc** To make it available for all zsh sessions run:\ -**podman completion -f "${fpath[1]}/_podman zsh"** +**podman completion -f "${fpath[1]}/_podman" zsh** Once the shell is reloaded the auto-completion should be working. diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index 40439dacbf..7cbb71d850 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -1231,6 +1231,15 @@ content label. Shared volume labels allow all containers to read/write content. The `Z` option tells Podman to label the content with a private unshared label. Only the current container can use a private volume. +Note: Do not relabel system files and directories. Relabeling system content +might cause other confined services on your machine to fail. For these types +of containers we recommend that disable SELinux separation. The option +`--security-opt label=disable` disables SELinux separation for containers used in the build. +For example if a user wanted to volume mount their entire home directory into a +container, they need to disable SELinux separation. + + $ podman create --security-opt label=disable -v $HOME:/home/user fedora touch /home/user/file + `Overlay Volume Mounts` The `:O` flag tells Podman to mount the directory from the host as a @@ -1453,7 +1462,7 @@ Note: RHEL7 and Centos 7 will not have this feature until RHEL7.7 is released. In order for users to run rootless, there must be an entry for their username in /etc/subuid and /etc/subgid which lists the UIDs for their user namespace. Rootless Podman works better if the fuse-overlayfs and slirp4netns packages are installed. -The fuse-overlay package provides a userspace overlay storage driver, otherwise users need to use +The fuse-overlayfs package provides a userspace overlay storage driver, otherwise users need to use the vfs storage driver, which is diskspace expensive and does not perform well. slirp4netns is required for VPN, without it containers need to be run with the --network=host flag. diff --git a/docs/source/markdown/podman-generate-kube.1.md b/docs/source/markdown/podman-generate-kube.1.md index 9ae3941ecc..a583afcf9f 100644 --- a/docs/source/markdown/podman-generate-kube.1.md +++ b/docs/source/markdown/podman-generate-kube.1.md @@ -54,13 +54,7 @@ spec: - docker-entrypoint.sh - mysqld env: - - name: PATH - value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - - name: TERM - value: xterm - name: HOSTNAME - - name: container - value: podman - name: GOSU_VERSION value: "1.10" - name: GPG_KEYS @@ -77,14 +71,14 @@ spec: ports: - containerPort: 3306 hostPort: 36533 - protocol: TCP resources: {} securityContext: - allowPrivilegeEscalation: true - privileged: false - readOnlyRootFilesystem: false + capabilities: + drop: + - CAP_MKNOD + - CAP_NET_RAW + - CAP_AUDIT_WRITE tty: true - workingDir: / status: {} ``` @@ -106,31 +100,18 @@ spec: containers: - command: - /bin/sh - env: - - name: PATH - value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - - name: TERM - value: xterm - - name: container - value: podman image: docker.io/library/alpine:latest name: test-bind-mount resources: {} securityContext: - allowPrivilegeEscalation: true capabilities: drop: - CAP_MKNOD - CAP_NET_RAW - CAP_AUDIT_WRITE - privileged: false - readOnlyRootFilesystem: false - seLinuxOptions: {} volumeMounts: - mountPath: /volume name: home-user-my-data-host - workingDir: / - dnsConfig: {} restartPolicy: Never volumes: - hostPath: @@ -158,31 +139,18 @@ spec: containers: - command: - /bin/sh - env: - - name: PATH - value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - - name: TERM - value: xterm - - name: container - value: podman image: docker.io/library/alpine:latest name: test-bind-mount resources: {} securityContext: - allowPrivilegeEscalation: true capabilities: drop: - CAP_MKNOD - CAP_NET_RAW - CAP_AUDIT_WRITE - privileged: false - readOnlyRootFilesystem: false - seLinuxOptions: {} volumeMounts: - mountPath: /volume name: priceless-data-pvc - workingDir: / - dnsConfig: {} restartPolicy: Never volumes: - name: priceless-data-pvc @@ -210,22 +178,9 @@ spec: - command: - python3 - /root/code/graph.py - env: - - name: PATH - value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - - name: TERM - value: xterm - - name: HOSTNAME - - name: container - value: podman image: quay.io/baude/demoweb:latest name: practicalarchimedes resources: {} - securityContext: - allowPrivilegeEscalation: true - capabilities: {} - privileged: false - readOnlyRootFilesystem: false tty: true workingDir: /root/code status: {} @@ -242,7 +197,6 @@ spec: - name: "8050" nodePort: 31269 port: 8050 - protocol: TCP targetPort: 0 selector: app: demoweb diff --git a/docs/source/markdown/podman-machine-init.1.md b/docs/source/markdown/podman-machine-init.1.md index 8a65be5a96..8b26728d58 100644 --- a/docs/source/markdown/podman-machine-init.1.md +++ b/docs/source/markdown/podman-machine-init.1.md @@ -18,6 +18,10 @@ tied to the Linux kernel. SSH keys are automatically generated to access the VM, and system connections to the root account and a user account inside the VM are added. +By default, the VM distribution is [Fedora CoreOS](https://getfedora.org/en/coreos?stream=testing). +Fedora CoreOS upgrades come out every 14 days and are detected and installed automatically. The VM will be rebooted during the upgrade. +For more information on updates and advanced configuration, please see the FCOS update docs [here](https://docs.fedoraproject.org/en-US/fedora-coreos/auto-updates/) and [here](https://coreos.github.io/zincati/usage/updates-strategy/). + ## OPTIONS #### **--cpus**=*number* diff --git a/docs/source/markdown/podman-machine-ssh.1.md b/docs/source/markdown/podman-machine-ssh.1.md index a5cf691074..24ae586077 100644 --- a/docs/source/markdown/podman-machine-ssh.1.md +++ b/docs/source/markdown/podman-machine-ssh.1.md @@ -9,7 +9,7 @@ podman\-machine\-ssh - SSH into a virtual machine ## DESCRIPTION SSH into a Podman-managed virtual machine and optionally execute a command -on the virtual machine. Unless using the default virtual machine, the +on the virtual machine. Unless using the default virtual machine, the first argument must be the virtual machine name. The optional command to execute can then follow. If no command is provided, an interactive session with the virtual machine is established. diff --git a/docs/source/markdown/podman-pause.1.md b/docs/source/markdown/podman-pause.1.md index 1233628225..90ea1e32ed 100644 --- a/docs/source/markdown/podman-pause.1.md +++ b/docs/source/markdown/podman-pause.1.md @@ -31,7 +31,7 @@ podman pause 860a4b23 Pause all **running** containers. ``` -podman stop -a +podman pause -a ``` ## SEE ALSO diff --git a/docs/source/markdown/podman-pod-rm.1.md b/docs/source/markdown/podman-pod-rm.1.md index d185385b6e..ce91dab5b3 100644 --- a/docs/source/markdown/podman-pod-rm.1.md +++ b/docs/source/markdown/podman-pod-rm.1.md @@ -7,7 +7,7 @@ podman\-pod\-rm - Remove one or more stopped pods and containers **podman pod rm** [*options*] *pod* ## DESCRIPTION -**podman pod rm** will remove one or more stopped pods and their containers from the host. The pod name or ID can be used. The \-f option stops all containers and then removes them before removing the pod. +**podman pod rm** will remove one or more stopped pods and their containers from the host. The pod name or ID can be used. The \-f option stops all containers and then removes them before removing the pod. If all containers added by the user are in an exited state, the pod will be removed. ## OPTIONS diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index c538935fda..811bc725b3 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -1288,6 +1288,15 @@ share the volume content. As a result, Podman labels the content with a shared content label. Shared volume labels allow all containers to read/write content. The **Z** option tells Podman to label the content with a private unshared label. +Note: Do not relabel system files and directories. Relabeling system content +might cause other confined services on your machine to fail. For these types +of containers we recommend that disable SELinux separation. The option +`--security-opt label=disable` disables SELinux separation for the container. +For example if a user wanted to volume mount their entire home directory into a +container, they need to disable SELinux separation. + + $ podman run --security-opt label=disable -v $HOME:/home/user fedora touch /home/user/file + `Overlay Volume Mounts` The `:O` flag tells Podman to mount the directory from the host as a @@ -1801,7 +1810,7 @@ Note: RHEL7 and Centos 7 will not have this feature until RHEL7.7 is released. In order for users to run rootless, there must be an entry for their username in _/etc/subuid_ and _/etc/subgid_ which lists the UIDs for their user namespace. Rootless Podman works better if the fuse-overlayfs and slirp4netns packages are installed. -The **fuse-overlay** package provides a userspace overlay storage driver, otherwise users need to use +The **fuse-overlayfs** package provides a userspace overlay storage driver, otherwise users need to use the **vfs** storage driver, which is diskspace expensive and does not perform well. slirp4netns is required for VPN, without it containers need to be run with the **--network=host** flag. diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index 864ff34bc2..49d40be0c9 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -317,7 +317,7 @@ Podman can also be used as non-root user. When podman runs in rootless mode, a u Containers created by a non-root user are not visible to other users and are not seen or managed by Podman running as root. -It is required to have multiple uids/gids set for an user. Be sure the user is present in the files `/etc/subuid` and `/etc/subgid`. +It is required to have multiple uids/gids set for a user. Be sure the user is present in the files `/etc/subuid` and `/etc/subgid`. If you have a recent version of usermod, you can execute the following commands to add the ranges to the files diff --git a/go.mod b/go.mod index bdad4c2444..5808d70d7b 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( github.com/dtylman/scp v0.0.0-20181017070807-f3000a34aef4 github.com/fsnotify/fsnotify v1.5.1 github.com/ghodss/yaml v1.0.0 - github.com/godbus/dbus/v5 v5.0.5 + github.com/godbus/dbus/v5 v5.0.6 github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf github.com/google/uuid v1.3.0 github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 diff --git a/go.sum b/go.sum index b9eed814f7..952774d351 100644 --- a/go.sum +++ b/go.sum @@ -403,8 +403,8 @@ github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68Fp github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.5 h1:9Eg0XUhQxtkV8ykTMKtMMYY72g4NgxtRq4jgh4Ih5YM= -github.com/godbus/dbus/v5 v5.0.5/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 2ca49758d9..54d6b13039 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -479,9 +479,27 @@ func (c *Container) setupStorage(ctx context.Context) error { c.setupStorageMapping(&options.IDMappingOptions, &c.config.IDMappings) - containerInfo, err := c.runtime.storageService.CreateContainerStorage(ctx, c.runtime.imageContext, c.config.RootfsImageName, c.config.RootfsImageID, c.config.Name, c.config.ID, options) - if err != nil { - return errors.Wrapf(err, "error creating container storage") + // Unless the user has specified a name, use a randomly generated one. + // Note that name conflicts may occur (see #11735), so we need to loop. + generateName := c.config.Name == "" + var containerInfo ContainerInfo + var containerInfoErr error + for { + if generateName { + name, err := c.runtime.generateName() + if err != nil { + return err + } + c.config.Name = name + } + containerInfo, containerInfoErr = c.runtime.storageService.CreateContainerStorage(ctx, c.runtime.imageContext, c.config.RootfsImageName, c.config.RootfsImageID, c.config.Name, c.config.ID, options) + + if !generateName || errors.Cause(containerInfoErr) != storage.ErrDuplicateName { + break + } + } + if containerInfoErr != nil { + return errors.Wrapf(containerInfoErr, "error creating container storage") } c.config.IDMappings.UIDMap = containerInfo.UIDMap @@ -2100,7 +2118,7 @@ func (c *Container) checkReadyForRemoval() error { return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is in invalid state", c.ID()) } - if c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) { + if c.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) && !c.IsInfra() { return errors.Wrapf(define.ErrCtrStateInvalid, "cannot remove container %s as it is %s - running or paused containers cannot be removed without force", c.ID(), c.state.State.String()) } diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 310110679a..208e089b51 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -1483,6 +1483,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti logrus.Debugf("Restored container %s", c.ID()) c.state.State = define.ContainerStateRunning + c.state.Checkpointed = false if !options.Keep { // Delete all checkpoint related files. At this point, in theory, all files diff --git a/libpod/container_log_linux.go b/libpod/container_log_linux.go index ca1e11ef5e..b6b780bab9 100644 --- a/libpod/container_log_linux.go +++ b/libpod/container_log_linux.go @@ -91,8 +91,12 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption var cursorError error for i := 1; i <= 3; i++ { cursor, cursorError = journal.GetCursor() + hundreds := 1 + for j := 1; j < i; j++ { + hundreds *= 2 + } if cursorError != nil { - time.Sleep(time.Duration(i*100) * time.Millisecond) + time.Sleep(time.Duration(hundreds*100) * time.Millisecond) continue } break @@ -117,8 +121,26 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption }() tailQueue := []*logs.LogLine{} // needed for options.Tail - doTail := options.Tail > 0 + doTail := options.Tail >= 0 + doTailFunc := func() { + // Flush *once* we hit the end of the journal. + startIndex := int64(len(tailQueue)) + outputLines := int64(0) + for startIndex > 0 && outputLines < options.Tail { + startIndex-- + for startIndex > 0 && tailQueue[startIndex].Partial() { + startIndex-- + } + outputLines++ + } + for i := startIndex; i < int64(len(tailQueue)); i++ { + logChannel <- tailQueue[i] + } + tailQueue = nil + doTail = false + } lastReadCursor := "" + partial := "" for { select { case <-ctx.Done(): @@ -148,16 +170,7 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption // Hit the end of the journal (so far?). if cursor == lastReadCursor { if doTail { - // Flush *once* we hit the end of the journal. - startIndex := int64(len(tailQueue)-1) - options.Tail - if startIndex < 0 { - startIndex = 0 - } - for i := startIndex; i < int64(len(tailQueue)); i++ { - logChannel <- tailQueue[i] - } - tailQueue = nil - doTail = false + doTailFunc() } // Unless we follow, quit. if !options.Follow { @@ -190,6 +203,9 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption return } if status == events.Exited { + if doTail { + doTailFunc() + } return } continue @@ -214,6 +230,12 @@ func (c *Container) readFromJournal(ctx context.Context, options *logs.LogOption logrus.Errorf("Failed parse log line: %v", err) return } + if logLine.Partial() { + partial += logLine.Msg + continue + } + logLine.Msg = partial + logLine.Msg + partial = "" if doTail { tailQueue = append(tailQueue, logLine) continue diff --git a/libpod/info.go b/libpod/info.go index 2eba4bbff9..47fda07256 100644 --- a/libpod/info.go +++ b/libpod/info.go @@ -333,7 +333,7 @@ func readKernelVersion() (string, error) { return "", err } f := bytes.Fields(buf) - if len(f) < 2 { + if len(f) < 3 { return string(bytes.TrimSpace(buf)), nil } return string(f[2]), nil diff --git a/libpod/kube.go b/libpod/kube.go index f5291ce60a..b34734513f 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -166,9 +166,83 @@ func (v *Volume) GenerateForKube() *v1.PersistentVolumeClaim { } } +// YAMLPodSpec represents the same k8s API core PodSpec struct with a small +// change and that is having Containers as a pointer to YAMLContainer. +// Because Go doesn't omit empty struct and we want to omit Status in YAML +// if it's empty. Fixes: GH-11998 +type YAMLPodSpec struct { + v1.PodSpec + Containers []*YAMLContainer `json:"containers"` +} + +// YAMLPod represents the same k8s API core Pod struct with a small +// change and that is having Spec as a pointer to YAMLPodSpec and +// Status as a pointer to k8s API core PodStatus. +// Because Go doesn't omit empty struct and we want to omit Status in YAML +// if it's empty. Fixes: GH-11998 +type YAMLPod struct { + v1.Pod + Spec *YAMLPodSpec `json:"spec,omitempty"` + Status *v1.PodStatus `json:"status,omitempty"` +} + +// YAMLService represents the same k8s API core Service struct with a small +// change and that is having Status as a pointer to k8s API core ServiceStatus. +// Because Go doesn't omit empty struct and we want to omit Status in YAML +// if it's empty. Fixes: GH-11998 +type YAMLService struct { + v1.Service + Status *v1.ServiceStatus `json:"status,omitempty"` +} + +// YAMLContainer represents the same k8s API core Container struct with a small +// change and that is having Resources as a pointer to k8s API core ResourceRequirements. +// Because Go doesn't omit empty struct and we want to omit Status in YAML +// if it's empty. Fixes: GH-11998 +type YAMLContainer struct { + v1.Container + Resources *v1.ResourceRequirements `json:"resources,omitempty"` +} + +// ConvertV1PodToYAMLPod takes k8s API core Pod and returns a pointer to YAMLPod +func ConvertV1PodToYAMLPod(pod *v1.Pod) *YAMLPod { + cs := []*YAMLContainer{} + for _, cc := range pod.Spec.Containers { + var res *v1.ResourceRequirements = nil + if len(cc.Resources.Limits) > 0 || len(cc.Resources.Requests) > 0 { + res = &cc.Resources + } + cs = append(cs, &YAMLContainer{Container: cc, Resources: res}) + } + mpo := &YAMLPod{Pod: *pod} + mpo.Spec = &YAMLPodSpec{PodSpec: (*pod).Spec, Containers: cs} + for _, ctr := range pod.Spec.Containers { + if ctr.SecurityContext == nil || ctr.SecurityContext.SELinuxOptions == nil { + continue + } + selinuxOpts := ctr.SecurityContext.SELinuxOptions + if selinuxOpts.User == "" && selinuxOpts.Role == "" && selinuxOpts.Type == "" && selinuxOpts.Level == "" { + ctr.SecurityContext.SELinuxOptions = nil + } + } + dnsCfg := pod.Spec.DNSConfig + if dnsCfg != nil && (len(dnsCfg.Nameservers)+len(dnsCfg.Searches)+len(dnsCfg.Options) > 0) { + mpo.Spec.DNSConfig = dnsCfg + } + status := pod.Status + if status.Phase != "" || len(status.Conditions) > 0 || + status.Message != "" || status.Reason != "" || + status.NominatedNodeName != "" || status.HostIP != "" || + status.PodIP != "" || status.StartTime != nil || + len(status.InitContainerStatuses) > 0 || len(status.ContainerStatuses) > 0 || status.QOSClass != "" || len(status.EphemeralContainerStatuses) > 0 { + mpo.Status = &status + } + return mpo +} + // GenerateKubeServiceFromV1Pod creates a v1 service object from a v1 pod object -func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) v1.Service { - service := v1.Service{} +func GenerateKubeServiceFromV1Pod(pod *v1.Pod, servicePorts []v1.ServicePort) YAMLService { + service := YAMLService{} selector := make(map[string]string) selector["app"] = pod.Labels["app"] ports := servicePorts @@ -332,7 +406,7 @@ func newPodObject(podName string, annotations map[string]string, initCtrs, conta InitContainers: initCtrs, Volumes: volumes, } - if dnsOptions != nil { + if dnsOptions != nil && (len(dnsOptions.Nameservers)+len(dnsOptions.Searches)+len(dnsOptions.Options) > 0) { ps.DNSConfig = dnsOptions } p := v1.Pod{ @@ -447,11 +521,6 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, [] kubeVolumes = append(kubeVolumes, volumes...) } - envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env) - if err != nil { - return kubeContainer, kubeVolumes, nil, annotations, err - } - portmappings, err := c.PortMappings() if err != nil { return kubeContainer, kubeVolumes, nil, annotations, err @@ -489,15 +558,23 @@ func containerToV1Container(ctx context.Context, c *Container) (v1.Container, [] kubeContainer.Command = nil } + if c.WorkingDir() != "/" && imgData.Config.WorkingDir != c.WorkingDir() { + kubeContainer.WorkingDir = c.WorkingDir() + } + if imgData.User == c.User() { kubeSec.RunAsGroup, kubeSec.RunAsUser = nil, nil } - kubeContainer.WorkingDir = c.WorkingDir() + envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env, imgData.Config.Env) + if err != nil { + return kubeContainer, kubeVolumes, nil, annotations, err + } + kubeContainer.Env = envVariables + kubeContainer.Ports = ports // This should not be applicable //container.EnvFromSource = - kubeContainer.Env = envVariables kubeContainer.SecurityContext = kubeSec kubeContainer.StdinOnce = false kubeContainer.TTY = c.config.Spec.Process.Terminal @@ -600,9 +677,14 @@ func ocicniPortMappingToContainerPort(portMappings []ocicni.PortMapping) ([]v1.C } // libpodEnvVarsToKubeEnvVars converts a key=value string slice to []v1.EnvVar -func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) { +func libpodEnvVarsToKubeEnvVars(envs []string, imageEnvs []string) ([]v1.EnvVar, error) { defaultEnv := env.DefaultEnvVariables() envVars := make([]v1.EnvVar, 0, len(envs)) + imageMap := make(map[string]string, len(imageEnvs)) + for _, ie := range envs { + split := strings.SplitN(ie, "=", 2) + imageMap[split[0]] = split[1] + } for _, e := range envs { split := strings.SplitN(e, "=", 2) if len(split) != 2 { @@ -611,6 +693,9 @@ func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) { if defaultEnv[split[0]] == split[1] { continue } + if imageMap[split[0]] == split[1] { + continue + } ev := v1.EnvVar{ Name: split[0], Value: split[1], @@ -808,33 +893,42 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) { capabilities = newCaps } + sc := v1.SecurityContext{ + // RunAsNonRoot is an optional parameter; our first implementations should be root only; however + // I'm leaving this as a bread-crumb for later + //RunAsNonRoot: &nonRoot, + } + if capabilities != nil { + sc.Capabilities = capabilities + } var selinuxOpts v1.SELinuxOptions opts := strings.SplitN(c.config.Spec.Annotations[define.InspectAnnotationLabel], ":", 2) - if len(opts) == 2 { + switch len(opts) { + case 2: switch opts[0] { case "type": selinuxOpts.Type = opts[1] + sc.SELinuxOptions = &selinuxOpts case "level": selinuxOpts.Level = opts[1] + sc.SELinuxOptions = &selinuxOpts } - } - if len(opts) == 1 { + case 1: if opts[0] == "disable" { selinuxOpts.Type = "spc_t" + sc.SELinuxOptions = &selinuxOpts } } - sc := v1.SecurityContext{ - Capabilities: capabilities, - Privileged: &privileged, - SELinuxOptions: &selinuxOpts, - // RunAsNonRoot is an optional parameter; our first implementations should be root only; however - // I'm leaving this as a bread-crumb for later - //RunAsNonRoot: &nonRoot, - ReadOnlyRootFilesystem: &ro, - AllowPrivilegeEscalation: &allowPrivEscalation, + if !allowPrivEscalation { + sc.AllowPrivilegeEscalation = &allowPrivEscalation + } + if privileged { + sc.Privileged = &privileged + } + if ro { + sc.ReadOnlyRootFilesystem = &ro } - if c.User() != "" { if !c.batched { c.lock.Lock() diff --git a/libpod/lock/shm/shm_lock.go b/libpod/lock/shm/shm_lock.go index 322e92a8f6..fea02a619f 100644 --- a/libpod/lock/shm/shm_lock.go +++ b/libpod/lock/shm/shm_lock.go @@ -130,8 +130,17 @@ func (locks *SHMLocks) AllocateSemaphore() (uint32, error) { // semaphore indexes, and can still return error codes. retCode := C.allocate_semaphore(locks.lockStruct) if retCode < 0 { + var err = syscall.Errno(-1 * retCode) // Negative errno returned - return 0, syscall.Errno(-1 * retCode) + if errors.Is(err, syscall.ENOSPC) { + // ENOSPC expands to "no space left on device". While it is technically true + // that there's no room in the SHM inn for this lock, this tends to send normal people + // down the path of checking disk-space which is not actually their problem. + // Give a clue that it's actually due to num_locks filling up. + var errFull = errors.Errorf("allocation failed; exceeded num_locks (%d)", locks.maxLocks) + return uint32(retCode), errFull + } + return uint32(retCode), syscall.Errno(-1 * retCode) } return uint32(retCode), nil diff --git a/libpod/network/cni/cni_types.go b/libpod/network/cni/cni_types.go index 91fd1c27b7..35548f4f9f 100644 --- a/libpod/network/cni/cni_types.go +++ b/libpod/network/cni/cni_types.go @@ -175,7 +175,7 @@ func newIPAMLocalHostRange(subnet types.IPNet, leaseRange *types.LeaseRange, gw Subnet: subnet.String(), } - // an user provided a range, we add it here + // a user provided a range, we add it here if leaseRange != nil { if leaseRange.StartIP != nil { hostRange.RangeStart = leaseRange.StartIP.String() diff --git a/libpod/network/cni/run.go b/libpod/network/cni/run.go index 14634262cd..3f78d79a47 100644 --- a/libpod/network/cni/run.go +++ b/libpod/network/cni/run.go @@ -199,10 +199,8 @@ func getRuntimeConfig(netns, conName, conID, networkName string, ports []cniPort IfName: opts.InterfaceName, Args: [][2]string{ {"IgnoreUnknown", "1"}, - // FIXME: Should we set the K8S args? - //{"K8S_POD_NAMESPACE", conName}, - //{"K8S_POD_INFRA_CONTAINER_ID", conID}, - // K8S_POD_NAME is used by dnsname to get the container name + // Do not set the K8S env vars, see https://github.com/containers/podman/issues/12083. + // Only K8S_POD_NAME is used by dnsname to get the container name. {"K8S_POD_NAME", conName}, }, CapabilityArgs: map[string]interface{}{}, diff --git a/libpod/networking_slirp4netns.go b/libpod/networking_slirp4netns.go index c06d215e1a..e24b54032a 100644 --- a/libpod/networking_slirp4netns.go +++ b/libpod/networking_slirp4netns.go @@ -16,6 +16,7 @@ import ( "syscall" "time" + "github.com/containernetworking/plugins/pkg/ns" "github.com/containers/podman/v3/pkg/errorhandling" "github.com/containers/podman/v3/pkg/rootless" "github.com/containers/podman/v3/pkg/rootlessport" @@ -58,6 +59,8 @@ type slirp4netnsNetworkOptions struct { outboundAddr6 string } +const ipv6ConfDefaultAcceptDadSysctl = "/proc/sys/net/ipv6/conf/default/accept_dad" + func checkSlirpFlags(path string) (*slirpFeatures, error) { cmd := exec.Command(path, "--help") out, err := cmd.CombinedOutput() @@ -297,6 +300,39 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error { } cmd.Stdout = logFile cmd.Stderr = logFile + + var slirpReadyChan (chan struct{}) + + if netOptions.enableIPv6 { + slirpReadyChan = make(chan struct{}) + defer close(slirpReadyChan) + go func() { + err := ns.WithNetNSPath(netnsPath, func(_ ns.NetNS) error { + // Duplicate Address Detection slows the ipv6 setup down for 1-2 seconds. + // Since slirp4netns is run it is own namespace and not directly routed + // we can skip this to make the ipv6 address immediately available. + // We change the default to make sure the slirp tap interface gets the + // correct value assigned so DAD is disabled for it + // Also make sure to change this value back to the original after slirp4netns + // is ready in case users rely on this sysctl. + orgValue, err := ioutil.ReadFile(ipv6ConfDefaultAcceptDadSysctl) + if err != nil { + return err + } + err = ioutil.WriteFile(ipv6ConfDefaultAcceptDadSysctl, []byte("0"), 0644) + if err != nil { + return err + } + // wait for slirp to finish setup + <-slirpReadyChan + return ioutil.WriteFile(ipv6ConfDefaultAcceptDadSysctl, orgValue, 0644) + }) + if err != nil { + logrus.Warnf("failed to set net.ipv6.conf.default.accept_dad sysctl: %v", err) + } + }() + } + if err := cmd.Start(); err != nil { return errors.Wrapf(err, "failed to start slirp4netns process") } @@ -310,6 +346,9 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error { if err := waitForSync(syncR, cmd, logFile, 1*time.Second); err != nil { return err } + if slirpReadyChan != nil { + slirpReadyChan <- struct{}{} + } // Set a default slirp subnet. Parsing a string with the net helper is easier than building the struct myself _, ctr.slirp4netnsSubnet, _ = net.ParseCIDR(defaultSlirp4netnsSubnet) diff --git a/libpod/runtime.go b/libpod/runtime.go index c22d873249..a208b6db44 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -541,6 +541,8 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { return err } if became { + // Check if the pause process was created. If it was created, then + // move it to its own systemd scope. utils.MovePauseProcessToScope(pausePid) os.Exit(ret) } diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 7d3891f6e1..f27e854a46 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -322,15 +322,6 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai } } - if ctr.config.Name == "" { - name, err := r.generateName() - if err != nil { - return nil, err - } - - ctr.config.Name = name - } - // Check CGroup parent sanity, and set it if it was not set. // Only if we're actually configuring CGroups. if !ctr.config.NoCgroups { diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 7571fdfff2..de00eb8e05 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -43,18 +43,6 @@ func (r *Runtime) NewPod(ctx context.Context, p specgen.PodSpecGenerator, option } } - if pod.config.Name == "" { - name, err := r.generateName() - if err != nil { - return nil, err - } - pod.config.Name = name - } - - if p.InfraContainerSpec != nil && p.InfraContainerSpec.Hostname == "" { - p.InfraContainerSpec.Hostname = pod.config.Name - } - // Allocate a lock for the pod lock, err := r.lockManager.AllocateLock() if err != nil { @@ -131,9 +119,33 @@ func (r *Runtime) NewPod(ctx context.Context, p specgen.PodSpecGenerator, option logrus.Infof("Pod has an infra container, but shares no namespaces") } - if err := r.state.AddPod(pod); err != nil { - return nil, errors.Wrapf(err, "error adding pod to state") + // Unless the user has specified a name, use a randomly generated one. + // Note that name conflicts may occur (see #11735), so we need to loop. + generateName := pod.config.Name == "" + var addPodErr error + for { + if generateName { + name, err := r.generateName() + if err != nil { + return nil, err + } + pod.config.Name = name + } + + if p.InfraContainerSpec != nil && p.InfraContainerSpec.Hostname == "" { + p.InfraContainerSpec.Hostname = pod.config.Name + } + if addPodErr = r.state.AddPod(pod); addPodErr == nil { + return pod, nil + } + if !generateName || (errors.Cause(addPodErr) != define.ErrPodExists && errors.Cause(addPodErr) != define.ErrCtrExists) { + break + } } + if addPodErr != nil { + return nil, errors.Wrapf(addPodErr, "error adding pod to state") + } + return pod, nil } @@ -177,10 +189,9 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if err != nil { return err } - numCtrs := len(ctrs) - // If the only container in the pod is the pause container, remove the pod and container unconditionally. + // If the only running container in the pod is the pause container, remove the pod and container unconditionally. pauseCtrID := p.state.InfraContainerID if numCtrs == 1 && ctrs[0].ID() == pauseCtrID { removeCtrs = true @@ -264,6 +275,15 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) } } + // Clear infra container ID before we remove the infra container. + // There is a potential issue if we don't do that, and removal is + // interrupted between RemoveAllContainers() below and the pod's removal + // later - we end up with a reference to a nonexistent infra container. + p.state.InfraContainerID = "" + if err := p.save(); err != nil { + return err + } + // Remove all containers in the pod from the state. if err := r.state.RemovePodContainers(p); err != nil { // If this fails, there isn't much more we can do. diff --git a/nix/default-arm64.nix b/nix/default-arm64.nix index 8868788ae1..a38cef04af 100644 --- a/nix/default-arm64.nix +++ b/nix/default-arm64.nix @@ -59,7 +59,8 @@ let self = with pkgs; buildGoModule rec { name = "podman"; - src = ./..; + src = builtins.filterSource + (path: type: !(type == "directory" && baseNameOf path == "bin")) ./..; vendorSha256 = null; doCheck = false; enableParallelBuilding = true; diff --git a/nix/default.nix b/nix/default.nix index 4d15532c22..9a4b372a46 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -57,7 +57,8 @@ let self = with pkgs; buildGoModule rec { name = "podman"; - src = ./..; + src = builtins.filterSource + (path: type: !(type == "directory" && baseNameOf path == "bin")) ./..; vendorSha256 = null; doCheck = false; enableParallelBuilding = true; diff --git a/pkg/api/handlers/compat/images_build.go b/pkg/api/handlers/compat/images_build.go index 606c52e410..6152f1c02d 100644 --- a/pkg/api/handlers/compat/images_build.go +++ b/pkg/api/handlers/compat/images_build.go @@ -151,22 +151,19 @@ func BuildImage(w http.ResponseWriter, r *http.Request) { var m = []string{} if err := json.Unmarshal([]byte(query.Dockerfile), &m); err != nil { // it's not json, assume just a string - m = append(m, query.Dockerfile) + m = []string{filepath.Join(contextDirectory, query.Dockerfile)} } containerFiles = m } else { - containerFiles = []string{"Dockerfile"} + containerFiles = []string{filepath.Join(contextDirectory, "Dockerfile")} if utils.IsLibpodRequest(r) { - containerFiles = []string{"Containerfile"} - if _, err = os.Stat(filepath.Join(contextDirectory, "Containerfile")); err != nil { - if _, err1 := os.Stat(filepath.Join(contextDirectory, "Dockerfile")); err1 == nil { - containerFiles = []string{"Dockerfile"} - } else { + containerFiles = []string{filepath.Join(contextDirectory, "Containerfile")} + if _, err = os.Stat(containerFiles[0]); err != nil { + containerFiles = []string{filepath.Join(contextDirectory, "Dockerfile")} + if _, err1 := os.Stat(containerFiles[0]); err1 != nil { utils.BadRequest(w, "dockerfile", query.Dockerfile, err) } } - } else { - containerFiles = []string{"Dockerfile"} } } diff --git a/pkg/api/server/handler_rid.go b/pkg/api/server/handler_rid.go index b624b99a62..7dcf436f78 100644 --- a/pkg/api/server/handler_rid.go +++ b/pkg/api/server/handler_rid.go @@ -2,6 +2,7 @@ package server import ( "fmt" + "io/ioutil" "net/http" "github.com/containers/podman/v3/pkg/api/types" @@ -15,7 +16,13 @@ import ( // and Apache style request logging func referenceIDHandler() mux.MiddlewareFunc { return func(h http.Handler) http.Handler { - return handlers.CombinedLoggingHandler(logrus.StandardLogger().Out, + // Only log Apache access_log-like entries at Info level or below + out := ioutil.Discard + if logrus.IsLevelEnabled(logrus.InfoLevel) { + out = logrus.StandardLogger().Out + } + + return handlers.CombinedLoggingHandler(out, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { rid := r.Header.Get("X-Reference-Id") if rid == "" { diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 95981226c2..f666692566 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -103,7 +103,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DockerImageSummary" + // $ref: "#/responses/DockerImageSummaryResponse" // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/images/json"), s.APIHandler(compat.GetImages)).Methods(http.MethodGet) @@ -831,7 +831,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: "#/responses/DockerImageSummary" + // $ref: "#/responses/LibpodImageSummaryResponse" // 500: // $ref: '#/responses/InternalError' r.Handle(VersionedPath("/libpod/images/json"), s.APIHandler(libpod.GetImages)).Methods(http.MethodGet) diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go index 0fd66652e3..3f8f6f9c51 100644 --- a/pkg/api/server/swagger.go +++ b/pkg/api/server/swagger.go @@ -6,6 +6,7 @@ import ( "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/domain/entities/reports" "github.com/containers/podman/v3/pkg/errorhandling" + docker "github.com/docker/docker/api/types" ) // No such image @@ -134,9 +135,16 @@ type swagPodAlreadyStopped struct { } } -// Image summary -// swagger:response DockerImageSummary -type swagImageSummary struct { +// Image summary for compat API +// swagger:response DockerImageSummaryResponse +type swagDockerImageSummaryResponse struct { + // in:body + Body []docker.ImageSummary +} + +// Image summary for libpod API +// swagger:response LibpodImageSummaryResponse +type swagLibpodImageSummaryResponse struct { // in:body Body []entities.ImageSummary } diff --git a/pkg/bindings/connection.go b/pkg/bindings/connection.go index e2c46e481b..2fe86ca39b 100644 --- a/pkg/bindings/connection.go +++ b/pkg/bindings/connection.go @@ -379,6 +379,11 @@ func (h *APIResponse) IsClientError() bool { return h.Response.StatusCode/100 == 4 } +// IsConflictError returns true if the response code is 409 +func (h *APIResponse) IsConflictError() bool { + return h.Response.StatusCode == 409 +} + // IsServerError returns true if the response code is 5xx func (h *APIResponse) IsServerError() bool { return h.Response.StatusCode/100 == 5 diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go index 725d066486..32a8978d92 100644 --- a/pkg/bindings/containers/attach.go +++ b/pkg/bindings/containers/attach.go @@ -214,7 +214,7 @@ func Attach(ctx context.Context, nameOrID string, stdin io.Reader, stdout io.Wri // Read multiplexed channels and write to appropriate stream fd, l, err := DemuxHeader(socket, buffer) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { return nil } return err @@ -531,7 +531,7 @@ func ExecStartAndAttach(ctx context.Context, sessionID string, options *ExecStar // Read multiplexed channels and write to appropriate stream fd, l, err := DemuxHeader(socket, buffer) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { return nil } return err diff --git a/pkg/bindings/containers/logs.go b/pkg/bindings/containers/logs.go index 67db944872..37ffdf0a58 100644 --- a/pkg/bindings/containers/logs.go +++ b/pkg/bindings/containers/logs.go @@ -39,7 +39,7 @@ func Logs(ctx context.Context, nameOrID string, options *LogOptions, stdoutChan, for { fd, l, err := DemuxHeader(response.Body, buffer) if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { return nil } return err diff --git a/pkg/bindings/errors.go b/pkg/bindings/errors.go index 9c311d9120..ec837b39c0 100644 --- a/pkg/bindings/errors.go +++ b/pkg/bindings/errors.go @@ -12,17 +12,22 @@ var ( ErrNotImplemented = errors.New("function not implemented") ) -func handleError(data []byte) error { - e := errorhandling.ErrorModel{} - if err := json.Unmarshal(data, &e); err != nil { +func handleError(data []byte, unmarshalErrorInto interface{}) error { + if err := json.Unmarshal(data, unmarshalErrorInto); err != nil { return err } - return e + return unmarshalErrorInto.(error) } // Process drains the response body, and processes the HTTP status code // Note: Closing the response.Body is left to the caller func (h APIResponse) Process(unmarshalInto interface{}) error { + return h.ProcessWithError(unmarshalInto, &errorhandling.ErrorModel{}) +} + +// Process drains the response body, and processes the HTTP status code +// Note: Closing the response.Body is left to the caller +func (h APIResponse) ProcessWithError(unmarshalInto interface{}, unmarshalErrorInto interface{}) error { data, err := ioutil.ReadAll(h.Response.Body) if err != nil { return errors.Wrap(err, "unable to process API response") @@ -33,14 +38,22 @@ func (h APIResponse) Process(unmarshalInto interface{}) error { } return nil } + + if h.IsConflictError() { + return handleError(data, unmarshalErrorInto) + } + // TODO should we add a debug here with the response code? - return handleError(data) + return handleError(data, &errorhandling.ErrorModel{}) } func CheckResponseCode(inError error) (int, error) { - e, ok := inError.(errorhandling.ErrorModel) - if !ok { + switch e := inError.(type) { + case *errorhandling.ErrorModel: + return e.Code(), nil + case *errorhandling.PodConflictErrorModel: + return e.Code(), nil + default: return -1, errors.New("error is not type ErrorModel") } - return e.Code(), nil } diff --git a/pkg/bindings/pods/pods.go b/pkg/bindings/pods/pods.go index a1a431a3b8..3b5832373a 100644 --- a/pkg/bindings/pods/pods.go +++ b/pkg/bindings/pods/pods.go @@ -9,6 +9,7 @@ import ( "github.com/containers/podman/v3/pkg/api/handlers" "github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/pkg/errorhandling" jsoniter "github.com/json-iterator/go" ) @@ -97,7 +98,7 @@ func Kill(ctx context.Context, nameOrID string, options *KillOptions) (*entities } defer response.Body.Close() - return &report, response.Process(&report) + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Pause pauses all running containers in a given pod. @@ -117,7 +118,7 @@ func Pause(ctx context.Context, nameOrID string, options *PauseOptions) (*entiti } defer response.Body.Close() - return &report, response.Process(&report) + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Prune by default removes all non-running pods in local storage. @@ -184,7 +185,7 @@ func Restart(ctx context.Context, nameOrID string, options *RestartOptions) (*en } defer response.Body.Close() - return &report, response.Process(&report) + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Remove deletes a Pod from from local storage. The optional force parameter denotes @@ -232,7 +233,8 @@ func Start(ctx context.Context, nameOrID string, options *StartOptions) (*entiti report.Id = nameOrID return &report, nil } - return &report, response.Process(&report) + + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Stop stops all containers in a Pod. The optional timeout parameter can be @@ -260,7 +262,7 @@ func Stop(ctx context.Context, nameOrID string, options *StopOptions) (*entities report.Id = nameOrID return &report, nil } - return &report, response.Process(&report) + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Top gathers statistics about the running processes in a pod. The nameOrID can be a pod name @@ -316,7 +318,7 @@ func Unpause(ctx context.Context, nameOrID string, options *UnpauseOptions) (*en } defer response.Body.Close() - return &report, response.Process(&report) + return &report, response.ProcessWithError(&report, &errorhandling.PodConflictErrorModel{}) } // Stats display resource-usage statistics of one or more pods. diff --git a/pkg/bindings/test/common_test.go b/pkg/bindings/test/common_test.go index 91ebe21fca..d996595bfb 100644 --- a/pkg/bindings/test/common_test.go +++ b/pkg/bindings/test/common_test.go @@ -225,12 +225,23 @@ func (b *bindingTest) RunTopContainer(containerName *string, podName *string) (s // This method creates a pod with the given pod name. // Podname is an optional parameter func (b *bindingTest) Podcreate(name *string) { + b.PodcreateAndExpose(name, nil) +} + +// This method creates a pod with the given pod name and publish port. +// Podname is an optional parameter +// port is an optional parameter +func (b *bindingTest) PodcreateAndExpose(name *string, port *string) { + command := []string{"pod", "create"} if name != nil { podname := *name - b.runPodman([]string{"pod", "create", "--name", podname}).Wait(45) - } else { - b.runPodman([]string{"pod", "create"}).Wait(45) + command = append(command, "--name", podname) + } + if port != nil { + podport := *port + command = append(command, "--publish", podport) } + b.runPodman(command).Wait(45) } // StringInSlice returns a boolean based on whether a given diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index b9ed67255f..0f535bc317 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -259,6 +259,7 @@ var _ = Describe("Podman containers ", func() { _, err = bt.RunTopContainer(&name, nil) Expect(err).To(BeNil()) go func() { + defer GinkgoRecover() exitCode, err = containers.Wait(bt.conn, name, nil) errChan <- err close(errChan) @@ -281,6 +282,7 @@ var _ = Describe("Podman containers ", func() { _, err := bt.RunTopContainer(&name, nil) Expect(err).To(BeNil()) go func() { + defer GinkgoRecover() exitCode, err = containers.Wait(bt.conn, name, new(containers.WaitOptions).WithCondition([]define.ContainerStatus{pause})) errChan <- err close(errChan) @@ -366,7 +368,10 @@ var _ = Describe("Podman containers ", func() { opts := new(containers.LogOptions).WithStdout(true).WithFollow(true) go func() { - containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil) + defer GinkgoRecover() + err := containers.Logs(bt.conn, r.ID, opts, stdoutChan, nil) + close(stdoutChan) + Expect(err).ShouldNot(HaveOccurred()) }() o := <-stdoutChan o = strings.TrimSpace(o) diff --git a/pkg/bindings/test/pods_test.go b/pkg/bindings/test/pods_test.go index 5331cf4398..879d4d00dc 100644 --- a/pkg/bindings/test/pods_test.go +++ b/pkg/bindings/test/pods_test.go @@ -1,6 +1,7 @@ package test_bindings import ( + "fmt" "net/http" "strings" "time" @@ -9,7 +10,9 @@ import ( "github.com/containers/podman/v3/pkg/bindings" "github.com/containers/podman/v3/pkg/bindings/pods" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/pkg/errorhandling" "github.com/containers/podman/v3/pkg/specgen" + "github.com/containers/podman/v3/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -208,6 +211,29 @@ var _ = Describe("Podman pods", func() { } }) + It("start pod with port conflict", func() { + randomport, err := utils.GetRandomPort() + Expect(err).To(BeNil()) + + portPublish := fmt.Sprintf("%d:%d", randomport, randomport) + var podwithport string = "newpodwithport" + bt.PodcreateAndExpose(&podwithport, &portPublish) + + // Start pod and expose port 12345 + _, err = pods.Start(bt.conn, podwithport, nil) + Expect(err).To(BeNil()) + + // Start another pod and expose same port 12345 + var podwithport2 string = "newpodwithport2" + bt.PodcreateAndExpose(&podwithport2, &portPublish) + + _, err = pods.Start(bt.conn, podwithport2, nil) + Expect(err).ToNot(BeNil()) + code, _ := bindings.CheckResponseCode(err) + Expect(code).To(BeNumerically("==", http.StatusConflict)) + Expect(err).To(BeAssignableToTypeOf(&errorhandling.PodConflictErrorModel{})) + }) + It("start stop restart pod", func() { // Start an invalid pod _, err = pods.Start(bt.conn, "dummyName", nil) diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go index f1ef538e4c..d0c0900129 100644 --- a/pkg/cgroups/cgroups.go +++ b/pkg/cgroups/cgroups.go @@ -461,10 +461,10 @@ func (c *CgroupControl) CreateSystemdUnit(path string) error { return systemdCreate(path, conn) } -// GetUserConnection returns an user connection to D-BUS +// GetUserConnection returns a user connection to D-BUS func GetUserConnection(uid int) (*systemdDbus.Conn, error) { return systemdDbus.NewConnection(func() (*dbus.Conn, error) { - return dbusAuthConnection(uid, dbus.SessionBusPrivate) + return dbusAuthConnection(uid, dbus.SessionBusPrivateNoAutoStartup) }) } diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index 5a469d9812..6d93ad4033 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -50,6 +50,7 @@ func (i *Image) Id() string { // nolint return i.ID } +// swagger:model LibpodImageSummary type ImageSummary struct { ID string `json:"Id"` ParentId string // nolint diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index 081a2464b7..a4d6bcf866 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -124,8 +124,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, if err != nil { return nil, err } - - b, err := generateKubeYAML(po) + b, err := generateKubeYAML(libpod.ConvertV1PodToYAMLPod(po)) if err != nil { return nil, err } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index b638bfe24c..c4d62bd894 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -226,7 +226,7 @@ func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []st for _, name := range namesOrIds { inspect, err := containers.Inspect(ic.ClientCtx, name, options) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, nil, err } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 9a746d68ce..ab2a93c75a 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -188,7 +188,7 @@ func (ir *ImageEngine) Inspect(ctx context.Context, namesOrIDs []string, opts en for _, i := range namesOrIDs { r, err := images.GetImage(ir.ClientCtx, i, options) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, nil, err } diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go index 7e59e44c2a..7c183b1ac0 100644 --- a/pkg/domain/infra/tunnel/network.go +++ b/pkg/domain/infra/tunnel/network.go @@ -23,7 +23,7 @@ func (ic *ContainerEngine) NetworkInspect(ctx context.Context, namesOrIds []stri for _, name := range namesOrIds { report, err := network.Inspect(ic.ClientCtx, name, options) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, nil, err } diff --git a/pkg/domain/infra/tunnel/secrets.go b/pkg/domain/infra/tunnel/secrets.go index 6337c7fbe8..e5fa200bdc 100644 --- a/pkg/domain/infra/tunnel/secrets.go +++ b/pkg/domain/infra/tunnel/secrets.go @@ -28,7 +28,7 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string for _, name := range nameOrIDs { inspected, err := secrets.Inspect(ic.ClientCtx, name, nil) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, nil, err } @@ -67,7 +67,7 @@ func (ic *ContainerEngine) SecretRm(ctx context.Context, nameOrIDs []string, opt for _, name := range nameOrIDs { secret, err := secrets.Inspect(ic.ClientCtx, name, nil) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, err } diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go index 2b2b2c2a1a..a3d9e1b6dd 100644 --- a/pkg/domain/infra/tunnel/volumes.go +++ b/pkg/domain/infra/tunnel/volumes.go @@ -56,7 +56,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin for _, id := range namesOrIds { data, err := volumes.Inspect(ic.ClientCtx, id, nil) if err != nil { - errModel, ok := err.(errorhandling.ErrorModel) + errModel, ok := err.(*errorhandling.ErrorModel) if !ok { return nil, nil, err } diff --git a/pkg/errorhandling/errorhandling.go b/pkg/errorhandling/errorhandling.go index 6adbc9f344..fcb0f7881d 100644 --- a/pkg/errorhandling/errorhandling.go +++ b/pkg/errorhandling/errorhandling.go @@ -83,6 +83,12 @@ func Contains(err error, sub error) bool { return strings.Contains(err.Error(), sub.Error()) } +// PodConflictErrorModel is used in remote connections with podman +type PodConflictErrorModel struct { + Errs []string + Id string //nolint +} + // ErrorModel is used in remote connections with podman type ErrorModel struct { // API root cause formatted for automated parsing @@ -106,3 +112,11 @@ func (e ErrorModel) Cause() error { func (e ErrorModel) Code() int { return e.ResponseCode } + +func (e PodConflictErrorModel) Error() string { + return strings.Join(e.Errs, ",") +} + +func (e PodConflictErrorModel) Code() int { + return 409 +} diff --git a/pkg/machine/ignition.go b/pkg/machine/ignition.go index e211f5ea6b..42d729458d 100644 --- a/pkg/machine/ignition.go +++ b/pkg/machine/ignition.go @@ -304,6 +304,24 @@ machine_enabled=true }, }) + setDockerHost := `export DOCKER_HOST="unix://$(podman info -f "{{.Host.RemoteSocket.Path}}")" +` + + files = append(files, File{ + Node: Node{ + Group: getNodeGrp("root"), + Path: "/etc/profile.d/docker-host.sh", + User: getNodeUsr("root"), + }, + FileEmbedded1: FileEmbedded1{ + Append: nil, + Contents: Resource{ + Source: encodeDataURLPtr(setDockerHost), + }, + Mode: intToPtr(0644), + }, + }) + return files } diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 6a6397257b..8007e5d8e4 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -133,12 +133,14 @@ func getMemoryLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOption if err != nil { return nil, errors.Wrapf(err, "invalid value for memory") } - memory.Limit = &ml - if c.MemorySwap == "" { - limit := 2 * ml - memory.Swap = &(limit) + if ml > 0 { + memory.Limit = &ml + if c.MemorySwap == "" { + limit := 2 * ml + memory.Swap = &(limit) + } + hasLimits = true } - hasLimits = true } if m := c.MemoryReservation; len(m) > 0 { mr, err := units.RAMInBytes(m) diff --git a/pkg/systemd/dbus.go b/pkg/systemd/dbus.go index c49f537b6c..04aaa117a2 100644 --- a/pkg/systemd/dbus.go +++ b/pkg/systemd/dbus.go @@ -84,7 +84,7 @@ func IsSystemdSessionValid(uid int) bool { return true } -// GetDbusConnection returns an user connection to D-BUS +// GetDbusConnection returns a user connection to D-BUS func GetLogindConnection(uid int) (*godbus.Conn, error) { return dbusAuthConnectionLogind(uid) } diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index 20ed72c591..dbf51f4e48 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -685,7 +685,7 @@ func SkipIfContainerized(reason string) { // 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) + podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil, nil) return &PodmanSessionIntegration{podmanSession} } diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 07515fe7b2..21f4ad8fa2 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -67,6 +67,10 @@ var _ = Describe("Podman generate kube", func() { err := yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) Expect(pod.Spec.HostNetwork).To(Equal(false)) + Expect(pod.Spec.SecurityContext).To(BeNil()) + Expect(pod.Spec.DNSConfig).To(BeNil()) + Expect(pod.Spec.Containers[0].WorkingDir).To(Equal("")) + Expect(pod.Spec.Containers[0].Env).To(BeNil()) numContainers := 0 for range pod.Spec.Containers { @@ -103,6 +107,7 @@ var _ = Describe("Podman generate kube", func() { err = yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) Expect(kube.OutputToString()).To(ContainSubstring("type: spc_t")) + }) It("podman generate service kube on container with --security-opt type", func() { @@ -1079,7 +1084,7 @@ USER test1` top1.WaitWithDefaultTimeout() Expect(top1).Should(Exit(0)) - top2 := podmanTest.Podman([]string{"run", "-dt", "--name", "top2", "--pod", "pod1", "--label", "io.containers.autoupdate=registry", "--label", "io.containers.autoupdate.authfile=/some/authfile.json", ALPINE, "top"}) + top2 := podmanTest.Podman([]string{"run", "-dt", "--name", "top2", "--workdir", "/root", "--pod", "pod1", "--label", "io.containers.autoupdate=registry", "--label", "io.containers.autoupdate.authfile=/some/authfile.json", ALPINE, "top"}) top2.WaitWithDefaultTimeout() Expect(top2).Should(Exit(0)) @@ -1090,6 +1095,8 @@ USER test1` pod := new(v1.Pod) err := yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) + Expect(pod.Spec.Containers[0].WorkingDir).To(Equal("")) + Expect(pod.Spec.Containers[1].WorkingDir).To(Equal("/root")) for _, ctr := range []string{"top1", "top2"} { v, ok := pod.GetAnnotations()["io.containers.autoupdate/"+ctr] diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go index 3115c246ff..ad511cc9e0 100644 --- a/test/e2e/libpod_suite_remote_test.go +++ b/test/e2e/libpod_suite_remote_test.go @@ -38,11 +38,25 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration return &PodmanSessionIntegration{podmanSession} } +// PodmanSystemdScope runs the podman command in a new systemd scope +func (p *PodmanTestIntegration) PodmanSystemdScope(args []string) *PodmanSessionIntegration { + var remoteArgs = []string{"--remote", "--url", p.RemoteSocket} + remoteArgs = append(remoteArgs, args...) + + wrapper := []string{"systemd-run", "--scope"} + if rootless.IsRootless() { + wrapper = []string{"systemd-run", "--scope", "--user"} + } + + podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, wrapper, nil) + return &PodmanSessionIntegration{podmanSession} +} + // PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration { var remoteArgs = []string{"--remote", "--url", p.RemoteSocket} remoteArgs = append(remoteArgs, args...) - podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, extraFiles) + podmanSession := p.PodmanAsUserBase(remoteArgs, 0, 0, "", nil, false, false, nil, extraFiles) return &PodmanSessionIntegration{podmanSession} } diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index cc03ccc963..6d2d3fee8f 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -8,6 +8,8 @@ import ( "os" "path/filepath" "strings" + + "github.com/containers/podman/v3/pkg/rootless" ) func IsRemote() bool { @@ -23,9 +25,19 @@ func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration return &PodmanSessionIntegration{podmanSession} } +// PodmanSystemdScope runs the podman command in a new systemd scope +func (p *PodmanTestIntegration) PodmanSystemdScope(args []string) *PodmanSessionIntegration { + wrapper := []string{"systemd-run", "--scope"} + if rootless.IsRootless() { + wrapper = []string{"systemd-run", "--scope", "--user"} + } + podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, wrapper, nil) + return &PodmanSessionIntegration{podmanSession} +} + // PodmanExtraFiles is the exec call to podman on the filesystem and passes down extra files func (p *PodmanTestIntegration) PodmanExtraFiles(args []string, extraFiles []*os.File) *PodmanSessionIntegration { - podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, extraFiles) + podmanSession := p.PodmanAsUserBase(args, 0, 0, "", nil, false, false, nil, extraFiles) return &PodmanSessionIntegration{podmanSession} } diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go index 71d30f063f..16e48da198 100644 --- a/test/e2e/logs_test.go +++ b/test/e2e/logs_test.go @@ -13,6 +13,19 @@ import ( . "github.com/onsi/gomega/gexec" ) +func isEventBackendJournald(podmanTest *PodmanTestIntegration) bool { + if !podmanTest.RemoteTest { + // If not remote test, '--events-backend' is set to 'file' or 'none' + return false + } + info := podmanTest.Podman([]string{"info", "--format", "{{.Host.EventLogger}}"}) + info.WaitWithDefaultTimeout() + if info.OutputToString() == "journald" { + return true + } + return false +} + var _ = Describe("Podman logs", func() { var ( tempdir string @@ -38,8 +51,18 @@ var _ = Describe("Podman logs", func() { }) for _, log := range []string{"k8s-file", "journald", "json-file"} { + // This is important to move the 'log' var to the correct scope under Ginkgo flow. + log := log + + skipIfJournaldInContainer := func() { + if log == "journald" { + SkipIfInContainer("journalctl inside a container doesn't work correctly") + } + } It("all lines: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -53,6 +76,8 @@ var _ = Describe("Podman logs", func() { }) It("tail two lines: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -65,6 +90,8 @@ var _ = Describe("Podman logs", func() { }) It("tail zero lines: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -77,6 +104,8 @@ var _ = Describe("Podman logs", func() { }) It("tail 99 lines: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -89,6 +118,8 @@ var _ = Describe("Podman logs", func() { }) It("tail 800 lines: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -101,6 +132,8 @@ var _ = Describe("Podman logs", func() { }) It("tail 2 lines with timestamps: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -113,6 +146,8 @@ var _ = Describe("Podman logs", func() { }) It("since time 2017-08-07: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -125,6 +160,8 @@ var _ = Describe("Podman logs", func() { }) It("since duration 10m: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -137,6 +174,8 @@ var _ = Describe("Podman logs", func() { }) It("until duration 10m: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -149,6 +188,7 @@ var _ = Describe("Podman logs", func() { }) It("until time NOW: "+log, func() { + skipIfJournaldInContainer() logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() @@ -165,13 +205,17 @@ var _ = Describe("Podman logs", func() { }) It("latest and container name should fail: "+log, func() { + skipIfJournaldInContainer() + results := podmanTest.Podman([]string{"logs", "-l", "foobar"}) results.WaitWithDefaultTimeout() Expect(results).To(ExitWithError()) }) It("two containers showing short container IDs: "+log, func() { + skipIfJournaldInContainer() SkipIfRemote("FIXME: podman-remote logs does not support showing two containers at the same time") + log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) log1.WaitWithDefaultTimeout() Expect(log1).Should(Exit(0)) @@ -192,6 +236,8 @@ var _ = Describe("Podman logs", func() { }) It("podman logs on a created container should result in 0 exit code: "+log, func() { + skipIfJournaldInContainer() + session := podmanTest.Podman([]string{"create", "--log-driver", log, "-t", "--name", "log", ALPINE}) session.WaitWithDefaultTimeout() Expect(session).To(Exit(0)) @@ -202,6 +248,8 @@ var _ = Describe("Podman logs", func() { }) It("streaming output: "+log, func() { + skipIfJournaldInContainer() + containerName := "logs-f" logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-dt", ALPINE, "sh", "-c", "echo podman-1; sleep 1; echo podman-2"}) @@ -210,6 +258,14 @@ var _ = Describe("Podman logs", func() { results := podmanTest.Podman([]string{"logs", "-f", containerName}) results.WaitWithDefaultTimeout() + + if log == "journald" && !isEventBackendJournald(podmanTest) { + // --follow + journald log-driver is only supported with journald events-backend(PR #10431) + Expect(results).To(Exit(125)) + Expect(results.ErrorToString()).To(ContainSubstring("using --follow with the journald --log-driver but without the journald --events-backend")) + return + } + Expect(results).To(Exit(0)) Expect(results.OutputToString()).To(ContainSubstring("podman-1")) @@ -233,6 +289,8 @@ var _ = Describe("Podman logs", func() { }) It("follow output stopped container: "+log, func() { + skipIfJournaldInContainer() + containerName := "logs-f" logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", containerName, "-d", ALPINE, "true"}) @@ -241,10 +299,17 @@ var _ = Describe("Podman logs", func() { results := podmanTest.Podman([]string{"logs", "-f", containerName}) results.WaitWithDefaultTimeout() + if log == "journald" && !isEventBackendJournald(podmanTest) { + // --follow + journald log-driver is only supported with journald events-backend(PR #10431) + Expect(results).To(Exit(125)) + return + } Expect(results).To(Exit(0)) }) It("using container with container log-size: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--log-opt=max-size=10k", "-d", ALPINE, "sh", "-c", "echo podman podman podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -266,6 +331,8 @@ var _ = Describe("Podman logs", func() { }) It("Make sure logs match expected length: "+log, func() { + skipIfJournaldInContainer() + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-t", "--name", "test", ALPINE, "sh", "-c", "echo 1; echo 2"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) @@ -284,6 +351,8 @@ var _ = Describe("Podman logs", func() { }) It("podman logs test stdout and stderr: "+log, func() { + skipIfJournaldInContainer() + cname := "log-test" logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "sh", "-c", "echo stdout; echo stderr >&2"}) logc.WaitWithDefaultTimeout() diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go index c5d91d6798..ac1f322ef6 100644 --- a/test/e2e/pod_rm_test.go +++ b/test/e2e/pod_rm_test.go @@ -301,4 +301,21 @@ var _ = Describe("Podman pod rm", func() { Expect(session).Should(Exit(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) }) + + It("podman pod rm with exited containers", func() { + _, ec, podid := podmanTest.CreatePod(nil) + Expect(ec).To(Equal(0)) + + session := podmanTest.Podman([]string{"run", "--pod", podid, ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"run", "--pod", podid, ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + result := podmanTest.Podman([]string{"pod", "rm", podid}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + }) }) diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 84707732bc..8d3b19b887 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -357,6 +357,26 @@ var _ = Describe("Podman run networking", func() { Expect(ncBusy).To(ExitWithError()) }) + It("podman run slirp4netns verify net.ipv6.conf.default.accept_dad=0", func() { + session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:enable_ipv6=true", ALPINE, "ip", "addr"}) + session.Wait(30) + Expect(session).Should(Exit(0)) + // check the ipv6 setup id done without delay (https://github.com/containers/podman/issues/11062) + Expect(session.OutputToString()).To(ContainSubstring("inet6 fd00::")) + + const ipv6ConfDefaultAcceptDadSysctl = "/proc/sys/net/ipv6/conf/all/accept_dad" + + cat := SystemExec("cat", []string{ipv6ConfDefaultAcceptDadSysctl}) + cat.Wait(30) + Expect(cat).Should(Exit(0)) + sysctlValue := cat.OutputToString() + + session = podmanTest.Podman([]string{"run", "--network", "slirp4netns:enable_ipv6=true", ALPINE, "cat", ipv6ConfDefaultAcceptDadSysctl}) + session.Wait(30) + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(Equal(sysctlValue)) + }) + It("podman run network expose host port 18082 to container port 8000 using slirp4netns port handler", func() { session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:port_handler=slirp4netns", "-dt", "-p", "18082:8000", ALPINE, "/bin/sh"}) session.Wait(30) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index b6743f4b72..ca39989cda 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -1322,13 +1322,13 @@ USER mail`, BB) } } - container := podmanTest.Podman([]string{"run", "--rm", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"}) + container := podmanTest.PodmanSystemdScope([]string{"run", "--rm", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"}) container.WaitWithDefaultTimeout() Expect(container).Should(Exit(0)) checkLines(container.OutputToStringArray()) // check that --cgroups=split is honored also when a container runs in a pod - container = podmanTest.Podman([]string{"run", "--rm", "--pod", "new:split-test-pod", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"}) + container = podmanTest.PodmanSystemdScope([]string{"run", "--rm", "--pod", "new:split-test-pod", "--cgroups=split", ALPINE, "cat", "/proc/self/cgroup"}) container.WaitWithDefaultTimeout() Expect(container).Should(Exit(0)) checkLines(container.OutputToStringArray()) diff --git a/test/e2e/system_reset_test.go b/test/e2e/system_reset_test.go index 102526a468..93ab166cd2 100644 --- a/test/e2e/system_reset_test.go +++ b/test/e2e/system_reset_test.go @@ -60,6 +60,8 @@ var _ = Describe("podman system reset", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + Expect(session.ErrorToString()).To(Not(ContainSubstring("Failed to add pause process"))) + // If remote then the API service should have exited // On local tests this is a noop podmanTest.StartRemoteService() diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go index a1b25b723e..98def3d8f2 100644 --- a/test/e2e/systemd_test.go +++ b/test/e2e/systemd_test.go @@ -4,7 +4,6 @@ import ( "io/ioutil" "os" "strings" - "time" . "github.com/containers/podman/v3/test/utils" . "github.com/onsi/ginkgo" @@ -82,27 +81,13 @@ WantedBy=multi-user.target run := podmanTest.Podman([]string{"run", "--name", ctrName, "-t", "-i", "-d", ubi_init, "/sbin/init"}) run.WaitWithDefaultTimeout() Expect(run).Should(Exit(0)) - ctrID := run.OutputToString() logs := podmanTest.Podman([]string{"logs", ctrName}) logs.WaitWithDefaultTimeout() Expect(logs).Should(Exit(0)) // Give container 10 seconds to start - started := false - for i := 0; i < 10; i++ { - runningCtrs := podmanTest.Podman([]string{"ps", "-q", "--no-trunc"}) - runningCtrs.WaitWithDefaultTimeout() - Expect(runningCtrs).Should(Exit(0)) - - if strings.Contains(runningCtrs.OutputToString(), ctrID) { - started = true - break - } - - time.Sleep(1 * time.Second) - } - + started := podmanTest.WaitContainerReady(ctrName, "Reached target Multi-User System.", 30, 1) Expect(started).To(BeTrue()) systemctl := podmanTest.Podman([]string{"exec", "-t", "-i", ctrName, "systemctl", "status", "--no-pager"}) diff --git a/test/e2e/trust_test.go b/test/e2e/trust_test.go index 7f97f280ad..b591e1c023 100644 --- a/test/e2e/trust_test.go +++ b/test/e2e/trust_test.go @@ -14,7 +14,8 @@ import ( var _ = Describe("Podman trust", func() { var ( - tempdir string + tempdir string + err error podmanTest *PodmanTestIntegration ) @@ -38,21 +39,17 @@ var _ = Describe("Podman trust", func() { }) It("podman image trust show", func() { - path, err := os.Getwd() - if err != nil { - os.Exit(1) - } - session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Dir(path), "--policypath", filepath.Join(filepath.Dir(path), "policy.json")}) + session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Join(INTEGRATION_ROOT, "test"), "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json")}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) outArray := session.OutputToStringArray() Expect(len(outArray)).To(Equal(3)) - // image order is not guaranteed. All we can do is check that - // these strings appear in output, we can't cross-check them. - Expect(session.OutputToString()).To(ContainSubstring("accept")) - Expect(session.OutputToString()).To(ContainSubstring("reject")) - Expect(session.OutputToString()).To(ContainSubstring("signed")) + // Repository order is not guaranteed. So, check that + // all expected lines appear in output; we also check total number of lines, so that handles all of them. + Expect(string(session.Out.Contents())).To(MatchRegexp(`(?m)^default\s+accept\s*$`)) + Expect(string(session.Out.Contents())).To(MatchRegexp(`(?m)^docker.io/library/hello-world\s+reject\s*$`)) + Expect(string(session.Out.Contents())).To(MatchRegexp(`(?m)^registry.access.redhat.com\s+signedBy\s+security@redhat.com, security@redhat.com\s+https://access.redhat.com/webassets/docker/content/sigstore\s*$`)) }) It("podman image trust set", func() { @@ -76,24 +73,52 @@ var _ = Describe("Podman trust", func() { }) It("podman image trust show --json", func() { - session := podmanTest.Podman([]string{"image", "trust", "show", "--json"}) + session := podmanTest.Podman([]string{"image", "trust", "show", "--registrypath", filepath.Join(INTEGRATION_ROOT, "test"), "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json"), "--json"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.IsJSONOutputValid()).To(BeTrue()) var teststruct []map[string]string json.Unmarshal(session.Out.Contents(), &teststruct) - Expect(teststruct[0]["name"]).To(Equal("* (default)")) - Expect(teststruct[0]["repo_name"]).To(Equal("default")) - Expect(teststruct[0]["type"]).To(Equal("accept")) - Expect(teststruct[1]["type"]).To(Equal("insecureAcceptAnything")) + Expect(len(teststruct)).To(Equal(3)) + // To ease comparison, group the unordered array of repos by repo (and we expect only one entry by repo, so order within groups doesn’t matter) + repoMap := map[string][]map[string]string{} + for _, e := range teststruct { + key := e["name"] + repoMap[key] = append(repoMap[key], e) + } + Expect(repoMap).To(Equal(map[string][]map[string]string{ + "* (default)": {{ + "name": "* (default)", + "repo_name": "default", + "sigstore": "", + "transport": "", + "type": "accept", + }}, + "docker.io/library/hello-world": {{ + "name": "docker.io/library/hello-world", + "repo_name": "docker.io/library/hello-world", + "sigstore": "", + "transport": "", + "type": "reject", + }}, + "registry.access.redhat.com": {{ + "name": "registry.access.redhat.com", + "repo_name": "registry.access.redhat.com", + "sigstore": "https://access.redhat.com/webassets/docker/content/sigstore", + "transport": "", + "type": "signedBy", + "gpg_id": "security@redhat.com, security@redhat.com", + }}, + })) }) It("podman image trust show --raw", func() { - session := podmanTest.Podman([]string{"image", "trust", "show", "--raw"}) + session := podmanTest.Podman([]string{"image", "trust", "show", "--policypath", filepath.Join(INTEGRATION_ROOT, "test/policy.json"), "--raw"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + contents, err := ioutil.ReadFile(filepath.Join(INTEGRATION_ROOT, "test/policy.json")) + Expect(err).ShouldNot(HaveOccurred()) Expect(session.IsJSONOutputValid()).To(BeTrue()) - Expect(session.OutputToString()).To(ContainSubstring("default")) - Expect(session.OutputToString()).To(ContainSubstring("insecureAcceptAnything")) + Expect(string(session.Out.Contents())).To(Equal(string(contents) + "\n")) }) }) diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go index 75986e671b..9398248b88 100644 --- a/test/e2e/version_test.go +++ b/test/e2e/version_test.go @@ -31,7 +31,6 @@ var _ = Describe("Podman version", func() { f := CurrentGinkgoTestDescription() processTestResult(f) podmanTest.SeedImages() - }) It("podman version", func() { @@ -96,4 +95,13 @@ var _ = Describe("Podman version", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) }) + + It("podman help", func() { + session := podmanTest.Podman([]string{"help"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.Out.Contents()).Should( + ContainSubstring("Display the Podman version information"), + ) + }) }) diff --git a/test/system/015-help.bats b/test/system/015-help.bats index 5f38c34a16..b0795b524e 100644 --- a/test/system/015-help.bats +++ b/test/system/015-help.bats @@ -86,6 +86,12 @@ function check_help() { run_podman 125 "$@" $cmd -l nonexistent-container is "$output" "Error: .*--latest and \(containers\|pods\|arguments\) cannot be used together" \ "'$command_string' with both -l and container" + + # Combine -l and -a, too (but spell it as --all, because "-a" + # means "attach" in podman container start) + run_podman 125 "$@" $cmd --all --latest + is "$output" "Error: \(--all and --latest cannot be used together\|--all, --latest and containers cannot be used together\|--all, --latest and arguments cannot be used together\|unknown flag\)" \ + "'$command_string' with both --all and --latest" fi fi diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 8640d427a3..2900540de7 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -67,6 +67,11 @@ echo $rand | 0 | $rand is "$output" ".*invalidflag" "failed when passing undefined flags to the runtime" } +@test "podman run --memory=0 runtime option" { + run_podman run --memory=0 --rm $IMAGE echo hello + is "$output" "hello" "failed to run when --memory is set to 0" +} + # 'run --preserve-fds' passes a number of additional file descriptors into the container @test "podman run --preserve-fds" { skip_if_remote "preserve-fds is meaningless over remote" diff --git a/test/system/045-start.bats b/test/system/045-start.bats index 7e4bbde8d9..2ea057cd3a 100644 --- a/test/system/045-start.bats +++ b/test/system/045-start.bats @@ -36,10 +36,6 @@ load helpers expected="Error: either start all containers or the container(s) provided in the arguments" run_podman 125 start --all 12333 is "$output" "$expected" "start --all, with args, throws error" - if ! is_remote; then - run_podman 125 start --all --latest - is "$output" "$expected" "podman start --all --latest" - fi } @test "podman start --filter - start only containers that match the filter" { diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index fc1a7c9f02..3263f3c820 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -167,6 +167,13 @@ load helpers $IMAGE nc -l -n -v -p $myport cid="$output" + # FIXME: debugging for #11871 + run_podman exec $cid cat /etc/resolv.conf + if is_rootless; then + run_podman unshare --rootless-cni cat /etc/resolv.conf + fi + ps uxww + # check that dns is working inside the container run_podman exec $cid nslookup google.com diff --git a/test/upgrade/test-upgrade.bats b/test/upgrade/test-upgrade.bats index 5cb302a85e..c9c44839ff 100644 --- a/test/upgrade/test-upgrade.bats +++ b/test/upgrade/test-upgrade.bats @@ -121,8 +121,15 @@ EOF # Clean up vestiges of previous run $PODMAN rm -f podman_parent || true - # Not entirely a NOP! This is just so we get /run/crun created on a CI VM - $PODMAN run --rm $OLD_PODMAN true + + local netname=testnet-$(random_string 10) + $PODMAN network create $netname + + # Not entirely a NOP! This is just so we get the /run/... mount points created on a CI VM + # --mac-address is needed to create /run/cni, --network is needed to create /run/containers for dnsname + $PODMAN run --rm --mac-address 78:28:a6:8d:24:8a --network $netname $OLD_PODMAN true + $PODMAN network rm -f $netname + # # Use new-podman to run the above script under old-podman. @@ -134,7 +141,8 @@ EOF # # mount /etc/containers/storage.conf to use the same storage settings as on the host # mount /dev/shm because the container locks are stored there - # mount /var/lib/cni and /etc/cni/net.d for cni networking + # mount /var/lib/cni, /run/cni and /etc/cni/net.d for cni networking + # mount /run/containers for the dnsname plugin # $PODMAN run -d --name podman_parent --pid=host \ --privileged \ @@ -145,6 +153,8 @@ EOF -v /dev/fuse:/dev/fuse \ -v /run/crun:/run/crun \ -v /run/netns:/run/netns:rshared \ + -v /run/containers:/run/containers \ + -v /run/cni:/run/cni \ -v /var/lib/cni:/var/lib/cni \ -v /etc/cni/net.d:/etc/cni/net.d \ -v /dev/shm:/dev/shm \ diff --git a/test/utils/podmantest_test.go b/test/utils/podmantest_test.go index 9bd1c4a669..1bb9ecb6bc 100644 --- a/test/utils/podmantest_test.go +++ b/test/utils/podmantest_test.go @@ -23,7 +23,7 @@ var _ = Describe("PodmanTest test", func() { FakeOutputs["check"] = []string{"check"} os.Setenv("HOOK_OPTION", "hook_option") env := os.Environ() - session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env, true, false, nil) + session := podmanTest.PodmanAsUserBase([]string{"check"}, 1000, 1000, "", env, true, false, nil, nil) os.Unsetenv("HOOK_OPTION") session.WaitWithDefaultTimeout() Expect(session.Command.Process).ShouldNot(BeNil()) diff --git a/test/utils/utils.go b/test/utils/utils.go index bfefc58ec8..d4d5e6e2f0 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -66,27 +66,31 @@ func (p *PodmanTest) MakeOptions(args []string, noEvents, noCache bool) []string // PodmanAsUserBase exec podman as user. uid and gid is set for credentials usage. env is used // to record the env for debugging -func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, noEvents, noCache bool, extraFiles []*os.File) *PodmanSession { +func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string, env []string, noEvents, noCache bool, wrapper []string, extraFiles []*os.File) *PodmanSession { var command *exec.Cmd podmanOptions := p.MakeOptions(args, noEvents, noCache) podmanBinary := p.PodmanBinary if p.RemoteTest { podmanBinary = p.RemotePodmanBinary } + + runCmd := append(wrapper, podmanBinary) if p.RemoteTest { podmanOptions = append([]string{"--remote", "--url", p.RemoteSocket}, podmanOptions...) } if env == nil { - fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(podmanOptions, " ")) + fmt.Printf("Running: %s %s\n", strings.Join(runCmd, " "), strings.Join(podmanOptions, " ")) } else { - fmt.Printf("Running: (env: %v) %s %s\n", env, podmanBinary, strings.Join(podmanOptions, " ")) + fmt.Printf("Running: (env: %v) %s %s\n", env, strings.Join(runCmd, " "), strings.Join(podmanOptions, " ")) } if uid != 0 || gid != 0 { pythonCmd := fmt.Sprintf("import os; import sys; uid = %d; gid = %d; cwd = '%s'; os.setgid(gid); os.setuid(uid); os.chdir(cwd) if len(cwd)>0 else True; os.execv(sys.argv[1], sys.argv[1:])", gid, uid, cwd) - nsEnterOpts := append([]string{"-c", pythonCmd, podmanBinary}, podmanOptions...) + runCmd = append(runCmd, podmanOptions...) + nsEnterOpts := append([]string{"-c", pythonCmd}, runCmd...) command = exec.Command("python", nsEnterOpts...) } else { - command = exec.Command(podmanBinary, podmanOptions...) + runCmd = append(runCmd, podmanOptions...) + command = exec.Command(runCmd[0], runCmd[1:]...) } if env != nil { command.Env = env @@ -106,7 +110,7 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string // PodmanBase exec podman with default env. func (p *PodmanTest) PodmanBase(args []string, noEvents, noCache bool) *PodmanSession { - return p.PodmanAsUserBase(args, 0, 0, "", nil, noEvents, noCache, nil) + return p.PodmanAsUserBase(args, 0, 0, "", nil, noEvents, noCache, nil, nil) } // WaitForContainer waits on a started container diff --git a/troubleshooting.md b/troubleshooting.md index a6c014625a..4bc115e44c 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -51,9 +51,9 @@ In cases where the container image runs as a specific, non-root user, though, th solution is to fix the user namespace. This would include container images such as the Jupyter Notebook image (which runs as "jovyan") and the Postgres image (which runs as "postgres"). In either case, use the `--userns` switch to map user namespaces, -most of the time by using keep_id option. +most of the time by using the **keep-id** option. -$ podman run -v "$PWD":/home/jovyan/work --userns=keep_id jupyter/scipy-notebook +$ podman run -v "$PWD":/home/jovyan/work --userns=keep-id jupyter/scipy-notebook --- ### 3) No such image or Bare keys cannot contain ':' diff --git a/utils/utils.go b/utils/utils.go index b08630d2f7..109ae088b9 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -14,6 +14,7 @@ import ( "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/pkg/cgroups" "github.com/containers/storage/pkg/archive" + "github.com/godbus/dbus/v5" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -177,13 +178,26 @@ func RunsOnSystemd() bool { func moveProcessToScope(pidPath, slice, scope string) error { data, err := ioutil.ReadFile(pidPath) if err != nil { + // do not raise an error if the file doesn't exist + if os.IsNotExist(err) { + return nil + } return errors.Wrapf(err, "cannot read pid file %s", pidPath) } pid, err := strconv.ParseUint(string(data), 10, 0) if err != nil { return errors.Wrapf(err, "cannot parse pid file %s", pidPath) } - return RunUnderSystemdScope(int(pid), slice, scope) + err = RunUnderSystemdScope(int(pid), slice, scope) + + // If the PID is not valid anymore, do not return an error. + if dbusErr, ok := err.(dbus.Error); ok { + if dbusErr.Name == "org.freedesktop.DBus.Error.UnixProcessIdUnknown" { + return nil + } + } + + return err } // MovePauseProcessToScope moves the pause process used for rootless mode to keep the namespaces alive to @@ -191,8 +205,8 @@ func moveProcessToScope(pidPath, slice, scope string) error { func MovePauseProcessToScope(pausePidPath string) { err := moveProcessToScope(pausePidPath, "user.slice", "podman-pause.scope") if err != nil { - unified, err := cgroups.IsCgroup2UnifiedMode() - if err != nil { + unified, err2 := cgroups.IsCgroup2UnifiedMode() + if err2 != nil { logrus.Warnf("Failed to detect if running with cgroup unified: %v", err) } if RunsOnSystemd() && unified { diff --git a/vendor/github.com/godbus/dbus/v5/auth.go b/vendor/github.com/godbus/dbus/v5/auth.go index eb0b2f4341..a59b4c0eb7 100644 --- a/vendor/github.com/godbus/dbus/v5/auth.go +++ b/vendor/github.com/godbus/dbus/v5/auth.go @@ -53,7 +53,7 @@ type Auth interface { // bus. Auth must not be called on shared connections. func (conn *Conn) Auth(methods []Auth) error { if methods == nil { - uid := strconv.Itoa(os.Getuid()) + uid := strconv.Itoa(os.Geteuid()) methods = []Auth{AuthExternal(uid), AuthCookieSha1(uid, getHomeDir())} } in := bufio.NewReader(conn.transport) diff --git a/vendor/github.com/godbus/dbus/v5/conn.go b/vendor/github.com/godbus/dbus/v5/conn.go index cb8966a742..76fc5cde3d 100644 --- a/vendor/github.com/godbus/dbus/v5/conn.go +++ b/vendor/github.com/godbus/dbus/v5/conn.go @@ -73,7 +73,7 @@ func SessionBus() (conn *Conn, err error) { return } -func getSessionBusAddress() (string, error) { +func getSessionBusAddress(autolaunch bool) (string, error) { if address := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); address != "" && address != "autolaunch:" { return address, nil @@ -81,12 +81,26 @@ func getSessionBusAddress() (string, error) { os.Setenv("DBUS_SESSION_BUS_ADDRESS", address) return address, nil } + if !autolaunch { + return "", errors.New("dbus: couldn't determine address of session bus") + } return getSessionBusPlatformAddress() } // SessionBusPrivate returns a new private connection to the session bus. func SessionBusPrivate(opts ...ConnOption) (*Conn, error) { - address, err := getSessionBusAddress() + address, err := getSessionBusAddress(true) + if err != nil { + return nil, err + } + + return Dial(address, opts...) +} + +// SessionBusPrivate returns a new private connection to the session bus. If +// the session bus is not already open, do not attempt to launch it. +func SessionBusPrivateNoAutoStartup(opts ...ConnOption) (*Conn, error) { + address, err := getSessionBusAddress(false) if err != nil { return nil, err } @@ -121,7 +135,7 @@ func SystemBus() (conn *Conn, err error) { // ConnectSessionBus connects to the session bus. func ConnectSessionBus(opts ...ConnOption) (*Conn, error) { - address, err := getSessionBusAddress() + address, err := getSessionBusAddress(true) if err != nil { return nil, err } @@ -180,7 +194,7 @@ func Dial(address string, opts ...ConnOption) (*Conn, error) { // // Deprecated: use Dial with options instead. func DialHandler(address string, handler Handler, signalHandler SignalHandler) (*Conn, error) { - return Dial(address, WithSignalHandler(signalHandler)) + return Dial(address, WithHandler(handler), WithSignalHandler(signalHandler)) } // ConnOption is a connection option. diff --git a/vendor/github.com/godbus/dbus/v5/message.go b/vendor/github.com/godbus/dbus/v5/message.go index dd86aff4f4..16693eb301 100644 --- a/vendor/github.com/godbus/dbus/v5/message.go +++ b/vendor/github.com/godbus/dbus/v5/message.go @@ -279,8 +279,8 @@ func (msg *Message) EncodeToWithFDs(out io.Writer, order binary.ByteOrder) (fds // be either binary.LittleEndian or binary.BigEndian. If the message is not // valid or an error occurs when writing, an error is returned. func (msg *Message) EncodeTo(out io.Writer, order binary.ByteOrder) (err error) { - _, err = msg.EncodeToWithFDs(out, order); - return err; + _, err = msg.EncodeToWithFDs(out, order) + return err } // IsValid checks whether msg is a valid message and returns an diff --git a/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go b/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go new file mode 100644 index 0000000000..af7bafdf95 --- /dev/null +++ b/vendor/github.com/godbus/dbus/v5/transport_unixcred_netbsd.go @@ -0,0 +1,14 @@ +package dbus + +import "io" + +func (t *unixTransport) SendNullByte() error { + n, _, err := t.UnixConn.WriteMsgUnix([]byte{0}, nil, nil) + if err != nil { + return err + } + if n != 1 { + return io.ErrShortWrite + } + return nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 04bee22c9e..fad1d50935 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -353,7 +353,7 @@ github.com/ghodss/yaml github.com/go-logr/logr # github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 github.com/go-task/slim-sprig -# github.com/godbus/dbus/v5 v5.0.5 +# github.com/godbus/dbus/v5 v5.0.6 github.com/godbus/dbus/v5 # github.com/gogo/protobuf v1.3.2 github.com/gogo/protobuf/gogoproto diff --git a/version/version.go b/version/version.go index e5d1f3d1cd..9dd8b9a834 100644 --- a/version/version.go +++ b/version/version.go @@ -27,7 +27,7 @@ const ( // NOTE: remember to bump the version at the top // of the top-level README.md file when this is // bumped. -var Version = semver.MustParse("3.4.2-dev") +var Version = semver.MustParse("3.4.3-dev") // See https://docs.docker.com/engine/api/v1.40/ // libpod compat handlers are expected to honor docker API versions