summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--RELEASE_NOTES.md359
-rw-r--r--cmd/podman/common/completion.go1
-rw-r--r--cmd/podman/common/volumes.go16
-rw-r--r--cmd/podman/pods/create.go27
-rw-r--r--docs/source/markdown/podman-create.1.md1
-rw-r--r--docs/source/markdown/podman-run.1.md1
-rw-r--r--libpod/container.go12
-rw-r--r--libpod/container_internal_linux.go1
-rw-r--r--libpod/kube.go149
-rw-r--r--libpod/networking_linux.go16
-rw-r--r--libpod/options.go29
-rw-r--r--libpod/pod.go1
-rw-r--r--libpod/runtime_pod_infra_linux.go14
-rw-r--r--pkg/api/handlers/compat/containers.go33
-rw-r--r--pkg/api/handlers/compat/resize.go2
-rw-r--r--pkg/api/handlers/libpod/pods.go90
-rw-r--r--pkg/api/handlers/utils/handler.go51
-rw-r--r--pkg/api/server/register_pods.go17
-rw-r--r--pkg/bindings/containers/attach.go2
-rw-r--r--pkg/cgroups/cgroups.go12
-rw-r--r--pkg/cgroups/cgroups_test.go32
-rw-r--r--pkg/specgen/generate/kube/kube.go32
-rw-r--r--pkg/specgen/generate/pod_create.go3
-rw-r--r--pkg/systemd/generate/common.go14
-rw-r--r--pkg/systemd/generate/common_test.go40
-rw-r--r--pkg/systemd/generate/containers.go4
-rw-r--r--pkg/systemd/generate/containers_test.go40
-rw-r--r--pkg/systemd/generate/pods.go4
-rw-r--r--pkg/terminal/console_windows.go2
-rw-r--r--pkg/util/mountOpts.go4
-rw-r--r--test/apiv2/01-basic.at4
-rw-r--r--test/apiv2/rest_api/test_rest_v2_0_0.py114
-rw-r--r--test/e2e/common_test.go26
-rw-r--r--test/e2e/exists_test.go6
-rw-r--r--test/e2e/generate_kube_test.go167
-rw-r--r--test/e2e/network_connect_disconnect_test.go20
-rw-r--r--test/e2e/play_kube_test.go62
-rw-r--r--test/e2e/pod_create_test.go35
-rw-r--r--test/e2e/pod_inspect_test.go2
-rw-r--r--test/e2e/pod_kill_test.go16
-rw-r--r--test/e2e/pod_pause_test.go8
-rw-r--r--test/e2e/pod_prune_test.go6
-rw-r--r--test/e2e/pod_ps_test.go59
-rw-r--r--test/e2e/pod_restart_test.go18
-rw-r--r--test/e2e/pod_rm_test.go24
-rw-r--r--test/e2e/pod_start_test.go49
-rw-r--r--test/e2e/pod_stats_test.go16
-rw-r--r--test/e2e/pod_stop_test.go22
-rw-r--r--test/e2e/pod_top_test.go12
-rw-r--r--test/e2e/ps_test.go4
-rw-r--r--test/e2e/restart_test.go4
-rw-r--r--test/e2e/run_networking_test.go7
-rw-r--r--test/e2e/run_volume_test.go2
-rw-r--r--test/system/030-run.bats13
-rw-r--r--test/utils/utils.go5
55 files changed, 1242 insertions, 468 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 5a5d69193..b4823e1d2 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,207 +1,170 @@
# Release Notes
+
## 3.0.0
### Features
-- Add ability to set system wide options for slirp4netns
-- Add --cidfile to container kill
-- Add commas between mount options
-- Add compose regression to ci
-- Add containerenv information to /run/.containerenv
-- Add default sysctls for pod infra containers
-- Add --filter to podman system prune
-- Adding json formatting to `--list-tags` option in `podman search` command.
-- Add mask and unmask option to --security-opt
-- Add 'MemUsageBytes' format option
-- Add more information and examples on podman and pipes
-- Add network filter for podman ps and pod ps
-- Add Networks format placeholder to podman ps and pod ps
-- Add pod filter for ps
-- Add podman network create option for bridge mtu
-- Add podman network create option for bridge vlan
-- Add pre checkpoint
-- Add Security information to podman info
-- Add support for Gentoo file to package query
-- Add support for network ids
-- Add support for pacman package version query
-- Add support for persistent volume claims in kube files
-- Add support for --platform
-- Add systempaths=unconfined option
-- Add volume filters to system prune
-- Add volume prune --filter support
-- Allow podman push to push manifest lists
-- Allow users to specify TMPDIR in containers.conf
-- Always add the default gateway to the cni config file
-- Drop default log-level from error to warn
-- Enable short-name aliasing
-- Generate kube on multiple containers
-- Generate systemd: do not set `KillMode`
-- Image sign using per user registries.d
-- Implement pod-network-reload
-- Include named volumes in container migration
-- Initial implementation of renaming containers
-- Initial implementation of volume plugins
-- Network connect disconnect on non-running containers
-- Not use local image create/add manifest
-- Podman network label support
-- Prepare support in kube play for other volume types than hostPath
-- Remote copy
-- Remove the ability to use [name:tag] in podman load command
-- Remove varlink support from Podman
-- Sign multi-arch images
-- Support --network=default as if it was private
-- Support Unix timestamps for `podman logs --since`
+- Podman now features initial support for Docker Compose.
+- Added the `podman rename` command, which allows containers to be renamed after they are created ([#1925](https://github.com/containers/podman/issues/1925)).
+- The Podman remote client now supports the `podman copy` command.
+- A new command, `podman network reload`, has been added. This command will re-configure the network of all running containers, and can be used to recreate firewall rules lost when the system firewall was reloaded (e.g. via `firewall-cmd --reload`).
+- Podman networks now have IDs. They can be seen in `podman network ls` and can be used when removing and inspecting networks. Existing networks receive IDs automatically.
+- Podman networks now also support labels. They can be added via the `--label` option to `network create`, and `podman network ls` can filter labels based on them.
+- The `podman network create` command now supports setting bridge MTU and VLAN through the `--opt` option ([#8454](https://github.com/containers/podman/issues/8454)).
+- The `podman container checkpoint` and `podman container restore` commands can now checkpoint and restore containers that include volumes.
+- The `podman container checkpoint` command now supports the `--with-previous` and `--pre-checkpoint` options, and the `podman container restore` command now support the `--import-previous` option. These add support for two-step checkpointing with lowered dump times.
+- The `podman push` command can now push manifest lists. Podman will first attempt to push as an image, then fall back to pushing as a manifest list if that fails.
+- The `podman generate kube` command can now be run on multiple containers at once, and will generate a single pod containing all of them.
+- The `podman generate kube` and `podman play kube` commands now support Kubernetes DNS configuration, and will preserve custom DNS configuration when exporting or importing YAML ([#9132](https://github.com/containers/podman/issues/9132)).
+- The `podman generate kube` command now properly supports generating YAML for containers and pods creating using host networking (`--net=host`) ([#9077](https://github.com/containers/podman/issues/9077)).
+- The `podman kill` command now supports a `--cidfile` option to kill containers given a file containing the container's ID ([#8443](https://github.com/containers/podman/issues/8443)).
+- The `podman pod create` command now supports the `--net=none` option ([#9165](https://github.com/containers/podman/issues/9165)).
+- The `podman volume create` command can now specify volume UID and GID as options with the `UID` and `GID` fields passed to the the `--opt` option.
+- Initial support has been added for Docker Volume Plugins. Podman can now define available plugins in `containers.conf` and use them to create volumes with `podman volume create --driver`.
+- The `podman run` and `podman create` commands now support a new option, `--platform`, to specify the platform of the image to be used when creating the container.
+- The `--security-opt` option to `podman run` and `podman create` now supports the `systempaths=unconfined` option to unrestrict access to all paths in the container, as well as `mask` and `unmask` options to allow more granular restriction of container paths.
+- The `podman stats --format` command now supports a new format specified, `MemUsageBytes`, which prints the raw bytes of memory consumed by a container without human-readable formatting [#8945](https://github.com/containers/podman/issues/8945).
+- The `podman ps` command can now filter containers based on what pod they are joined to via the `pod` filter ([#8512](https://github.com/containers/podman/issues/8512)).
+- The `podman pod ps` command can now filter pods based on what networks they are joined to via the `network` filter.
+- The `podman pod ps` command can now print information on what networks a pod is joined to via the `.Networks` specifier to the `--format` option.
+- The `podman system prune` command now supports filtering what containers, pods, images, and volumes will be pruned.
+- The `podman volume prune` commands now supports filtering what volumes will be pruned.
+- The `podman system prune` command now includes information on space reclaimed ([#8658](https://github.com/containers/podman/issues/8658)).
+- The `podman info` command will now properly print information about packages in use on Gentoo and Arch systems.
+- The `containers.conf` file now contains an option for disabling creation of a new kernel keyring on container creation ([#8384](https://github.com/containers/podman/issues/8384)).
+- The `podman image sign` command can now sign multi-arch images by producing a signature for each image in a given manifest list.
+- The `podman image sign` command, when run as rootless, now supports per-user registry configuration files in `$HOME/.config/containers/registries.d`.
+- Configuration options for `slirp4netns` can now be set system-wide via the `NetworkCmdOptions` configuration option in `containers.conf`.
+- The MTU of `slirp4netns` can now be configured via the `mtu=` network command option (e.g. `podman run --net slirp4netns:mtu=9000`).
+
+### Security
+- A fix for CVE-2021-20199 is included. Podman between v1.8.0 and v2.2.1 used `127.0.0.1` as the source address for all traffic forwarded into rootless containers by a forwarded port; this has been changed to address the issue.
+
### Changes
-- Add LogSize to container inspect
-- Allow image errors to bubble up from lower level functions.
-- Change name of imageVolumes in container config JSON
-- Cleanup CNI Networks on reboot
-- Consolidate filter logic to pkg subdirectory
-- Make `podman stats` slirp check more robust
-- More /var/run -> /run
-- Prefer read/write images over read/only images
-- Refactor kube.ToSpecGen parameters to struct
-- Rename AutocompletePortCommand func
-- Repeat system pruning until there is nothing removed
-- Switch references of /var/run -> /run
-- Use HTTPProxy settings from containers.conf
-- Use Libpod tmpdir for pause path
-- Use Options as CRImportCheckpoint() argument
-- Use Options as exportCheckpoint() argument
-- Use PasswordCallback instead of Password for ssh
-- Use abi PodPs implementation for libpod/pods/json endpoint
-- Validate that the bridge option is supported
-- archive: move stat-header handling into copy package
-- libpod, conmon: change log level for rootless
-- libpod: change function to accept ExecOptions
-- libpod: handle single user mapped as root
-- make podman play use ENVs from image
-- pkg/copy: introduce a Copier
-- podman events allow future time for --until
-- podman.service should be an exec service not a notify service
-- rewrite podman-cp
-- rootless: add function to retrieve gid/uid mappings
-- rootless: automatically split userns ranges
-- runtime: set XDG_* env variables if missing
-- shell completion for the network flag
-- specgen: improve heuristic for /sys bind mount
-- systemd: make rundir always accessible
+- Shortname aliasing support has now been turned on by default. All Podman commands that must pull an image will, if a TTY is available, prompt the user about what image to pull.
+- The `podman load` command no longer accepts a `NAME[:TAG]` argument. The presence of this argument broke CLI compatibility with Docker by making `docker load` commands unusable with Podman ([#7387](https://github.com/containers/podman/issues/7387)).
+- The Go bindings for the HTTP API have been rewritten with a focus on limiting dependency footprint and improving extensibility. Read more [here](https://github.com/containers/podman/blob/v3.0/pkg/bindings/README.md).
+- The legacy Varlink API has been completely removed from Podman.
+- The default log level for Podman has been changed from Error to Warn.
+- The `podman network create` command can now create `macvlan` networks using the `--driver macvlan` option for Docker compatibility. The existing `--macvlan` flag has been deprecated and will be removed in Podman 4.0 some time next year.
+- The `podman inspect` command has had the `LogPath` and `LogTag` fields moved into the `LogConfig` structure (from the root of the Inspect structure). The maximum size of the log file is also included.
+- The `podman generate systemd` command no longer generates unit files using the deprecated `KillMode=none` option ([#8615](https://github.com/containers/podman/issues/8615)).
+- The `podman stop` command now releases the container lock while waiting for it to stop - as such, commands like `podman ps` will no longer block until `podman stop` completes ([#8501](https://github.com/containers/podman/issues/8501)).
+- Networks created with `podman network create --internal` no longer use the `dnsname` plugin. This configuration never functioned as expected.
+- Error messages for the remote Podman client have been improved when it cannot connect to a Podman service.
+- Error messages for `podman run` when an invalid SELinux is specified have been improved.
+- Rootless Podman features improved support for containers with a single user mapped into the rootless user namespace.
+- Pod infra containers now respect default sysctls specified in `containers.conf` allowing for advanced configuration of the namespaces they will share.
+- SSH public key handling for remote Podman has been improved.
+
### Bugfixes
-- Close image rawSource when each loop ends
-- Containers should not get inheritable caps by default
-- Correct port range logic for port generation
-- Correct which network commands can be run as rootless
-- Disable CGv1 pod stats on net=host post
-- Do not error on installing duplicate shutdown handler
-- Do not ignore infra command from config files
-- Do not mount sysfs as rootless in more cases
-- Do not pull if image domain is localhost
-- Do not use "true" after "syslog" in exit commands
-- Do not validate the volume source path in specgen
-- Don't accidently remove XDG_RUNTIME_DIR when reseting storage
-- Ensure that `podman play kube` actually reports errors
-- Ensure that user-specified HOSTNAME is honored
-- Ensure we do not edit container config in Exec
-- Exorcise Driver code from libpod/define
-- Expose Height/Width fields to decoder
-- Expose security attribute errors with their own messages
-- Fix Wrong image tag is used when creating a container from an image with multiple tags
-- Fix `podman images...` missing headers in table templates
-- Fix build for mips architecture
-- Fix build for mips architecture follow-up
-- Fix custom mac address with a custom cni network
-- Fix extra quotation mark in manpages.
-- Fix missing options in volumes display while setting uid and gid
-- Fix missing podman-container-rename man page link
-- Fix network ls --filter invalid value flake
-- Fix option names --subuidname and --subgidname
-- Fix panic in libpod images exists endpoint
-- Fix podman build --logfile
-- Fix podman logs read partial log lines
-- Fix problems reported by staticcheck
-- Fix problems with network remove
-- Fix shell completion for ps --filter ancestor
-- Fix some nit
-- Fix spelling mistakes
-- Fix storage.conf to define driver in the VM
-- Fix support for rpmbuild < 4.12.0.
-- Fix: unpause not supported for CGv1 rootless
-- Fxes /etc/hosts duplicated every time after container restarted in a pod
-- Handle --rm when starting a container
-- Handle podman exec capabilities correctly
-- Honor the --layers flag
-- Ignore containers.conf sysctls when sharing namespaces
-- Improve error message when the the podman service is not enabled
-- Make podman generate systemd --new flag parsing more robust
-- Pass down EnableKeyring from containers.conf to conmon
-- Properly handle --cap-add all when running with a --user flag
-- Revert "Allow multiple --network flags for podman run/create"
-- Revert e6fbc15f26b2a609936dfc11732037c70ee14cba
-- Revert the custom cobra vendor
-- Rework pruning to report reclaimed space
-- Set NetNS mode instead of value
-- The slirp4netns sandbox requires pivot_root
-- close journald when reading
-- container create: do not clear image name
-- container stop: release lock before calling the runtime
-- exec: honor --privileged
-- fix: disable seccomp by default when privileged.
-- image list: ignore bare manifest list
-- network: disallow CNI networks with user namespaces
-- oci: keep LC_ env variables to conmon
-- oci: use /proc/self/fd/FD to open unix socket
-- pass full NetworkMode to ParseNetworkNamespace
-- play kube: fix args/command handling
-- play kube: set entrypoint when interpreting Command
-- podman build --force-rm defaults to true in code
-- podman logs honor stderr correctly
-- podman, exec: move conmon to the correct cgroup
-- podman-remote fix sending tar content
-- podman: drop checking valid rootless UID
-- re-open container log files
-- security: honor systempaths=unconfined for ro paths
+- Fixed a bug where the `podman history --no-trunc` command would truncate the `Created By` field ([#9120](https://github.com/containers/podman/issues/9120)).
+- Fixed a bug where root containers that did not explicitly specify a CNI network to join did not generate an entry for the network in use in the `Networks` field of the output of `podman inspect` ([#6618](https://github.com/containers/podman/issues/6618)).
+- Fixed a bug where, under some circumstances, container working directories specified by the image (via the `WORKDIR` instruction) but not present in the image, would not be created ([#9040](https://github.com/containers/podman/issues/9040)).
+- Fixed a bug where the `podman generate systemd` command would generate invalid unit files if the container was creating using a command line that included doubled braces (`{{` and `}}`), e.g. `--log-opt-tag={{.Name}}` ([#9034](https://github.com/containers/podman/issues/9034)).
+- Fixed a bug where the `podman generate systemd --new` command could generate unit files including invalid Podman commands if the container was created using merged short options (e.g. `podman run -dt`) ([#8847](https://github.com/containers/podman/issues/8847)).
+- Fixed a bug where the `podman generate systemd --new` command could generate unit files that did not handle Podman commands including some special characters (e.g. `$`) ([#9176](https://github.com/containers/podman/issues/9176)
+- Fixed a bug where rootless containers joining CNI networks could not set a static IP address ([#7842](https://github.com/containers/podman/issues/7842)).
+- Fixed a bug where rootless containers joining CNI networks could not set network aliases ([#8567](https://github.com/containers/podman/issues/8567)).
+- Fixed a bug where the remote client could, under some circumstances, not include the `Containerfile` when sending build context to the server ([#8374](https://github.com/containers/podman/issues/8374)).
+- Fixed a bug where rootless Podman did not mount `/sys` as a new `sysfs` in some circumstances where it was acceptable.
+- Fixed a bug where rootless containers that both joined a user namespace and a CNI networks would cause a segfault. These options are incompatible and now return an error.
+- Fixed a bug where the `podman play kube` command did not properly handle `CMD` and `ARGS` from images ([#8803](https://github.com/containers/podman/issues/8803)).
+- Fixed a bug where the `podman play kube` command did not properly handle environment variables from images ([#8608](https://github.com/containers/podman/issues/8608)).
+- Fixed a bug where the `podman play kube` command did not properly print errors that occurred when starting containers.
+- Fixed a bug where the `podman play kube` command errored when `hostNetwork` was used ([#8790](https://github.com/containers/podman/issues/8790)).
+- Fixed a bug where the `podman play kube` command would always pull images when the `:latest` tag was specified, even if the image was available locally ([#7838](https://github.com/containers/podman/issues/7838)).
+- Fixed a bug where the `podman play kube` command did not properly handle SELinux configuration, rending YAML with custom SELinux configuration unusable ([#8710](https://github.com/containers/podman/issues/8710)).
+- Fixed a bug where the `podman generate kube` command incorrectly populated the `args` and `command` fields of generated YAML ([#9211](https://github.com/containers/podman/issues/9211)).
+- Fixed a bug where containers in a pod would create a duplicate entry in the pod's shared `/etc/hosts` file every time the container restarted ([#8921](https://github.com/containers/podman/issues/8921)).
+- Fixed a bug where the `podman search --list-tags` command did not support the `--format` option ([#8740](https://github.com/containers/podman/issues/8740)).
+- Fixed a bug where the `http_proxy` option in `containers.conf` was not being respected, and instead was set unconditionally to true ([#8843](https://github.com/containers/podman/issues/8843)).
+- Fixed a bug where rootless Podman could, on systems with a recent Conmon and users with a long username, fail to attach to containers ([#8798](https://github.com/containers/podman/issues/8798)).
+- Fixed a bug where the `podman images` command would break and fail to display any images if an empty manifest list was present in storage ([#8931](https://github.com/containers/podman/issues/8931)).
+- Fixed a bug where locale environment variables were not properly passed on to Conmon.
+- Fixed a bug where Podman would not build on the MIPS architecture ([#8782](https://github.com/containers/podman/issues/8782)).
+- Fixed a bug where rootless Podman could fail to properly configure user namespaces for rootless containers when the user specified a `--uidmap` option that included a mapping beginning with UID `0`.
+- Fixed a bug where the `podman logs` command using the `k8s-file` backend did not properly handle partial log lines with a length of 1 ([#8879](https://github.com/containers/podman/issues/8879)).
+- Fixed a bug where the `podman logs` command with the `--follow` option did not properly handle log rotation ([#8733](https://github.com/containers/podman/issues/8733)).
+- Fixed a bug where user-specified `HOSTNAME` environment variables were overwritten by Podman ([#8886](https://github.com/containers/podman/issues/8886)).
+- Fixed a bug where Podman would applied default sysctls from `containers.conf` in too many situations (e.g. applying network sysctls when the container shared its network with a pod).
+- Fixed a bug where Podman did not properly handle cases where a secondary image store was in use and an image was present in both the secondary and primary stores ([#8176](https://github.com/containers/podman/issues/8176)).
+- Fixed a bug where systemd-managed rootless Podman containers where the user in the container was not root could fail as the container's PID file was not accessible to systemd on the host ([#8506](https://github.com/containers/podman/issues/8506)).
+- Fixed a bug where the `--privileged` option to `podman run` and `podman create` would, under some circumstances, not disable Seccomp ([#8849](https://github.com/containers/podman/issues/8849)).
+- Fixed a bug where the `podman exec` command did not properly add capabilities when the container or exec session were run with `--privileged`.
+- Fixed a bug where rootless Podman would use the `--enable-sandbox` option to `slirp4netns` unconditionally, even when `pivot_root` was disabled, rendering `slirp4netns` unusable when `pivot_root` was disabled ([#8846](https://github.com/containers/podman/issues/8846)).
+- Fixed a bug where `podman build --logfile` did not actually write the build's log to the logfile.
+- Fixed a bug where the `podman system service` command did not close STDIN, and could display user-interactive prompts ([#8700](https://github.com/containers/podman/issues/8700)).
+- Fixed a bug where the `podman system reset` command could, under some circumstances, remove all the contents of the `XDG_RUNTIME_DIR` directory ([#8680](https://github.com/containers/podman/issues/8680)).
+- Fixed a bug where the `podman network create` command created CNI configurations that did not include a default gateway ([#8748](https://github.com/containers/podman/issues/8748)).
+- Fixed a bug where the `podman.service` systemd unit provided by default used the wrong service type, and would cause systemd to not correctly register the service as started ([#8751](https://github.com/containers/podman/issues/8751)).
+- Fixed a bug where, if the `TMPDIR` environment variable was set for the container engine in `containers.conf`, it was being ignored.
+- Fixed a bug where the `podman events` command did not properly handle future times given to the `--until` option ([#8694](https://github.com/containers/podman/issues/8694)).
+- Fixed a bug where the `podman logs` command wrote container `STDERR` logs to `STDOUT` instead of `STDERR` ([#8683](https://github.com/containers/podman/issues/8683)).
+- Fixed a bug where containers created from an image with multiple tags would report that they were created from the wrong tag ([#8547](https://github.com/containers/podman/issues/8547)).
+- Fixed a bug where container capabilities were not set properly when the `--cap-add=all` and `--user` options to `podman create` and `podman run` were combined.
+- Fixed a bug where the `--layers` option to `podman build` was nonfunctional ([#8643](https://github.com/containers/podman/issues/8643)).
+- Fixed a bug where the `podman system prune` command did not act recursively, and thus would leave images, containers, pods, and volumes present that would be removed by a subsequent call to `podman system prune` ([#7990](https://github.com/containers/podman/issues/7990)).
+- Fixed a bug where the `--publish` option to `podman run` and `podman create` did not properly handle ports specified as a range of ports with no host port specified ([#8650](https://github.com/containers/podman/issues/8650)).
+- Fixed a bug where `--format` did not support JSON output for individual fields ([#8444](https://github.com/containers/podman/issues/8444)).
+- Fixed a bug where the `podman stats` command would fail when run on root containers using the `slirp4netns` network mode ([#7883](https://github.com/containers/podman/issues/7883)).
+- Fixed a bug where the Podman remote client would ask for a password even if the server's SSH daemon did not support password authentication ([#8498](https://github.com/containers/podman/issues/8498)).
+- Fixed a bug where the `podman stats` command would fail if the system did not support one or more of the cgroup controllers Podman supports ([#8588](https://github.com/containers/podman/issues/8588)).
+- Fixed a bug where the `--mount` option to `podman create` and `podman run` did not ignore the `consistency` mount option.
+- Fixed a bug where failures during the resizing of a container's TTY would print the wrong error.
+- Fixed a bug where the `podman network disconnect` command could cause the `podman inspect` command to fail for a container until it was restarted ([#9234](https://github.com/containers/podman/issues/9234)).
+- Fixed a bug where containers created from a read-only rootfs (using the `--rootfs` option to `podman create` and `podman run`) would fail ([#9230](https://github.com/containers/podman/issues/9230)).
+
### API
-- Add API for communicating with Docker volume plugins
-- Change bindings to stop two API calls for ping
-- Close the stdin/tty when using podman as a restAPI.
-- Compat api containers/json add support for filters
-- Container rename bindings
-- Do not pass name argument to Load API
-- Docker compat API - /images/search returns wrong structure (#7857)
-- Docker compat API - containers create ignores the name
-- Fix some network compat api problems
-- Jira RUN-1106 Container handlers updates
-- Jira RUN-1106 Image handlers updates
-- Jira RUN-1106 Network handlers updates
-- Jira RUN-1106 System handlers updates
-- Jira RUN-1106 Volumes handlers updates
-- Makefile: add target to generate bindings
-- More docker compat API fixes
-- Podman image bindings for 3.0
-- REST API v2 - ping - fix typo in header
-- REST API v2 - ping - remove newline from response to improve Docker compatibility
-- Reduce general binding binary size
-- Restore compatible API for prune endpoints
-- compat create should use bindings
-- hack/podman-socat captures the API stream
-- libpod API: pull: fix channel race
-- misc bindings to podman v3
-- pkg/copy: add parsing API
-- podman v3 container bindings
-- podman v3 pod bindings
+- Libpod API version has been bumped to v3.0.0.
+- All Libpod Pod APIs have been modified to properly report errors with individual containers. Cases where the operation as a whole succeeded but individual containers failed now report an HTTP 409 error ([#8865](https://github.com/containers/podman/issues/8865)).
+- The Compat API for Containers now supports the Rename and Copy APIs.
+- Fixed a bug where the Compat Prune APIs (for volumes, containers, and images) did not return the amount of space reclaimed in their responses.
+- Fixed a bug where the Compat and Libpod Exec APIs for Containers would drop errors that occurred prior to the exec session successfully starting (e.g. a "no such file" error if an invalid executable was passed) ([#8281](https://github.com/containers/podman/issues/8281))
+- Fixed a bug where the Volumes field in the Compat Create API for Containers was being ignored ([#8649](https://github.com/containers/podman/issues/8649)).
+- Fixed a bug where the NetworkMode field in the Compat Create API for Containers was not handling some values, e.g. `container:`, correctly.
+- Fixed a bug where the Compat Create API for Containers did not set container name properly.
+- Fixed a bug where containers created using the Compat Create API unconditionally used Kubernetes file logging (the default specified in `containers.conf` is now used).
+- Fixed a bug where the Compat Inspect API for Containers could include container states not recognized by Docker.
+- Fixed a bug where Podman did not properly clean up after calls to the Events API when the `journald` backend was in use, resulting in a leak of file descriptors ([#8864](https://github.com/containers/podman/issues/8864)).
+- Fixed a bug where the Libpod Pull endpoint for Images could fail with an `index out of range` error under certain circumstances ([#8870](https://github.com/containers/podman/issues/8870)).
+- Fixed a bug where the Libpod Exists endpoint for Images could panic.
+- Fixed a bug where the Compat List API for Containers did not support all filters ([#8860](https://github.com/containers/podman/issues/8860)).
+- Fixed a bug where the Compat List API for Containers did not properly populate the Status field.
+- Fixed a bug where the Compat and Libpod Resize APIs for Containers ignored the height and width parameters ([#7102](https://github.com/containers/podman/issues/7102)).
+- Fixed a bug where the Compat Search API for Images returned an incorrectly-formatted JSON response ([#8758](https://github.com/containers/podman/pull/8758)).
+- Fixed a bug where the Compat Load API for Images did not properly clean up temporary files.
+- Fixed a bug where the Compat Create API for Networks could panic when an empty IPAM configuration was specified.
+- Fixed a bug where the Compat Inspect and List APIs for Networks did not include Scope.
+
+### Misc
+- Updated Buildah to v1.19.2
+- Updated the containers/storage library to v1.24.5
+- Updated the containers/common library to v0.33.4
+
+## v2.2.1
+### Changes
+- Due to a conflict with a previously-removed field, we were forced to modify the way image volumes (mounting images into containers using `--mount type=image`) were handled in the database. As a result, containers created in Podman 2.2.0 with image volumes will not have them in v2.2.1, and these containers will need to be re-created.
+
+### Bugfixes
+- Fixed a bug where rootless Podman would, on systems without the `XDG_RUNTIME_DIR` environment variable defined, use an incorrect path for the PID file of the Podman pause process, causing Podman to fail to start ([#8539](https://github.com/containers/podman/issues/8539)).
+- Fixed a bug where containers created using Podman v1.7 and earlier were unusable in Podman due to JSON decode errors ([#8613](https://github.com/containers/podman/issues/8613)).
+- Fixed a bug where Podman could retrieve invalid cgroup paths, instead of erroring, for containers that were not running.
+- Fixed a bug where the `podman system reset` command would print a warning about a duplicate shutdown handler being registered.
+- Fixed a bug where rootless Podman would attempt to mount `sysfs` in circumstances where it was not allowed; some OCI runtimes (notably `crun`) would fall back to alternatives and not fail, but others (notably `runc`) would fail to run containers.
+- Fixed a bug where the `podman run` and `podman create` commands would fail to create containers from untagged images ([#8558](https://github.com/containers/podman/issues/8558)).
+- Fixed a bug where remote Podman would prompt for a password even when the server did not support password authentication ([#8498](https://github.com/containers/podman/issues/8498)).
+- Fixed a bug where the `podman exec` command did not move the Conmon process for the exec session into the correct cgroup.
+- Fixed a bug where shell completion for the `ancestor` option to `podman ps --filter` did not work correctly.
+- Fixed a bug where detached containers would not properly clean themselves up (or remove themselves if `--rm` was set) if the Podman command that created them was invoked with `--log-level=debug`.
+
+### API
+- Fixed a bug where the Compat Create endpoint for Containers did not properly handle the `Binds` and `Mounts` parameters in `HostConfig`.
+- Fixed a bug where the Compat Create endpoint for Containers ignored the `Name` query parameter.
+- Fixed a bug where the Compat Create endpoint for Containers did not properly handle the "default" value for `NetworkMode` (this value is used extensively by `docker-compose`) ([#8544](https://github.com/containers/podman/issues/8544)).
+- Fixed a bug where the Compat Build endpoint for Images would sometimes incorrectly use the `target` query parameter as the image's tag.
+
### Misc
-- Bump github.com/containernetworking/plugins from 0.8.7 to 0.9.0
-- Bump github.com/containers/common from 0.30.0 to 0.31.1
-- Bump github.com/containers/image/v5 from 5.8.1 to 5.9.0
-- Bump github.com/containers/storage from 1.24.1 to 1.24.5
-- Bump github.com/cri-o/ocicni to latest master
-- Bump github.com/google/uuid from 1.1.2 to 1.1.5
-- Bump github.com/onsi/gomega from 1.10.3 to 1.10.4
-- Bump github.com/opencontainers/selinux from 1.6.0 to 1.8.0
-- Bump github.com/stretchr/testify from 1.6.1 to 1.7.0
-- Bump k8s.io/apimachinery from 0.19.4 to 0.20.2
-- Bump master to v3.0.0-dev
-- Bump to containers/buildah 1.9.2
-- Bump version in README to v2.2.0
-- vendor containers/psgo@v1.5.2
+- Podman v2.2.0 vendored a non-released, custom version of the `github.com/spf13/cobra` package; this has been reverted to the latest upstream release to aid in packaging.
+- Updated the containers/image library to v5.9.0
## 2.2.0
### Features
@@ -344,7 +307,7 @@
- Fixed a bug where a client disconnecting from the Libpod or Compat events endpoints could result in the server using 100% CPU ([#7946](https://github.com/containers/podman/issues/7946)).
- Fixed a bug where the "no such image" error message sent by the Compat Inspect endpoint for Images returned a 404 status code with an error that was improperly formatted for Docker compatibility.
- Fixed a bug where the Compat Create endpoint for networks did not properly set a default for the `driver` parameter if it was not provided by the client.
-- Fixed a bug where the Compat Inspect endpoint for images did not populate the `RootFS` field of the response.
+- Fixed a bug where the Compat Inspect endpoint for images did not populate the `RootFS`, `VirtualSize`, `ParentId`, `Architecture`, `Os`, and `OsVersion` fields of the response.
- Fixed a bug where the Compat Inspect endpoint for images would omit the `ParentId` field if the image had no parent, and the `Created` field if the image did not have a creation time.
- Fixed a bug where the Compat Remove endpoint for Networks did not support the `Force` query parameter.
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index c9a3c5e94..09dd74e20 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -817,6 +817,7 @@ func AutocompleteNetworkFlag(cmd *cobra.Command, args []string, toComplete strin
"allow_host_loopback=": getBoolCompletion,
"cidr=": nil,
"enable_ipv6=": getBoolCompletion,
+ "mtu=": nil,
"outbound_addr=": nil,
"outbound_addr6=": nil,
"port_handler=": func(_ string) ([]string, cobra.ShellCompDirective) {
diff --git a/cmd/podman/common/volumes.go b/cmd/podman/common/volumes.go
index a6e6faeca..2a598d7a5 100644
--- a/cmd/podman/common/volumes.go
+++ b/cmd/podman/common/volumes.go
@@ -353,6 +353,10 @@ func getBindMount(args []string) (spec.Mount, error) {
default:
return newMount, errors.Wrapf(util.ErrBadMntOption, "%s mount option must be 'private' or 'shared'", kv[0])
}
+ case "consistency":
+ // Often used on MACs and mistakenly on Linux platforms.
+ // Since Docker ignores this option so shall we.
+ continue
default:
return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0])
}
@@ -437,6 +441,10 @@ func getTmpfsMount(args []string) (spec.Mount, error) {
}
newMount.Destination = filepath.Clean(kv[1])
setDest = true
+ case "consistency":
+ // Often used on MACs and mistakenly on Linux platforms.
+ // Since Docker ignores this option so shall we.
+ continue
default:
return newMount, errors.Wrapf(util.ErrBadMntOption, kv[0])
}
@@ -534,6 +542,10 @@ func getNamedVolume(args []string) (*specgen.NamedVolume, error) {
}
newVolume.Dest = filepath.Clean(kv[1])
setDest = true
+ case "consistency":
+ // Often used on MACs and mistakenly on Linux platforms.
+ // Since Docker ignores this option so shall we.
+ continue
default:
return nil, errors.Wrapf(util.ErrBadMntOption, kv[0])
}
@@ -581,6 +593,10 @@ func getImageVolume(args []string) (*specgen.ImageVolume, error) {
default:
return nil, errors.Wrapf(util.ErrBadMntOption, "invalid rw value %q", kv[1])
}
+ case "consistency":
+ // Often used on MACs and mistakenly on Linux platforms.
+ // Since Docker ignores this option so shall we.
+ continue
default:
return nil, errors.Wrapf(util.ErrBadMntOption, kv[0])
}
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index d997ea344..23fb323a0 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -171,33 +171,6 @@ func create(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
- createOptions.Net.Network = specgen.Namespace{}
- if cmd.Flag("network").Changed {
- netInput, err := cmd.Flags().GetString("network")
- if err != nil {
- return err
- }
- parts := strings.SplitN(netInput, ":", 2)
-
- n := specgen.Namespace{}
- switch {
- case netInput == "bridge":
- n.NSMode = specgen.Bridge
- case netInput == "host":
- n.NSMode = specgen.Host
- case netInput == "slirp4netns", strings.HasPrefix(netInput, "slirp4netns:"):
- n.NSMode = specgen.Slirp
- if len(parts) > 1 {
- createOptions.Net.NetworkOptions = make(map[string][]string)
- createOptions.Net.NetworkOptions[parts[0]] = strings.Split(parts[1], ",")
- }
- default:
- // Container and NS mode are presently unsupported
- n.NSMode = specgen.Bridge
- createOptions.Net.CNINetworks = strings.Split(netInput, ",")
- }
- createOptions.Net.Network = n
- }
if len(createOptions.Net.PublishPorts) > 0 {
if !createOptions.Infra {
return errors.Errorf("you must have an infra container to publish port bindings to the host")
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index 8deaa8540..02eeb557c 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -635,6 +635,7 @@ Valid _mode_ values are:
- **private**: create a new namespace for the container (default)
- **slirp4netns[:OPTIONS,...]**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. It is possible to specify these additional options:
- **allow_host_loopback=true|false**: Allow the slirp4netns to reach the host loopback IP (`10.0.2.2`). Default is false.
+ - **mtu=MTU**: Specify the MTU to use for this network. (Default is `65520`).
- **cidr=CIDR**: Specify ip range to use for this network. (Default is `10.0.2.0/24`).
- **enable_ipv6=true|false**: Enable IPv6. Default is false. (Required for `outbound_addr6`).
- **outbound_addr=INTERFACE**: Specify the outbound interface slirp should bind to (ipv4 traffic only).
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 74c231184..edcd63935 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -671,6 +671,7 @@ Valid _mode_ values are:
- **private**: create a new namespace for the container (default)
- **slirp4netns[:OPTIONS,...]**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. It is possible to specify these additional options:
- **allow_host_loopback=true|false**: Allow the slirp4netns to reach the host loopback IP (`10.0.2.2`). Default is false.
+ - **mtu=MTU**: Specify the MTU to use for this network. (Default is `65520`).
- **cidr=CIDR**: Specify ip range to use for this network. (Default is `10.0.2.0/24`).
- **enable_ipv6=true|false**: Enable IPv6. Default is false. (Required for `outbound_addr6`).
- **outbound_addr=INTERFACE**: Specify the outbound interface slirp should bind to (ipv4 traffic only).
diff --git a/libpod/container.go b/libpod/container.go
index 58bf95470..ed7535bc8 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -1073,6 +1073,18 @@ func networkDisabled(c *Container) (bool, error) {
return false, nil
}
+func (c *Container) HostNetwork() bool {
+ if c.config.CreateNetNS || c.config.NetNsCtr != "" {
+ return false
+ }
+ for _, ns := range c.config.Spec.Linux.Namespaces {
+ if ns.Type == spec.NetworkNamespace {
+ return false
+ }
+ }
+ return true
+}
+
// ContainerState returns containerstate struct
func (c *Container) ContainerState() (*ContainerState, error) {
if !c.batched {
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 6c9489a08..ba85a1f47 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -213,6 +213,7 @@ func (c *Container) resolveWorkDir() error {
// we need to return the full error.
return errors.Wrapf(err, "error detecting workdir %q on container %s", workdir, c.ID())
}
+ return nil
}
// Ensure container entrypoint is created (if required).
diff --git a/libpod/kube.go b/libpod/kube.go
index 753c58099..f9ead027d 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -49,6 +49,7 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) {
}
extraHost := make([]v1.HostAlias, 0)
+ hostNetwork := false
if p.HasInfraContainer() {
infraContainer, err := p.getInfraContainer()
if err != nil {
@@ -69,9 +70,9 @@ func (p *Pod) GenerateForKube() (*v1.Pod, []v1.ServicePort, error) {
return nil, servicePorts, err
}
servicePorts = containerPortsToServicePorts(ports)
-
+ hostNetwork = p.config.InfraContainer.HostNetwork
}
- pod, err := p.podWithContainers(allContainers, ports)
+ pod, err := p.podWithContainers(allContainers, ports, hostNetwork)
if err != nil {
return nil, servicePorts, err
}
@@ -167,13 +168,14 @@ func containersToServicePorts(containers []v1.Container) []v1.ServicePort {
return sps
}
-func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPort) (*v1.Pod, error) {
+func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPort, hostNetwork bool) (*v1.Pod, error) {
deDupPodVolumes := make(map[string]*v1.Volume)
first := true
podContainers := make([]v1.Container, 0, len(containers))
+ dnsInfo := v1.PodDNSConfig{}
for _, ctr := range containers {
if !ctr.IsInfra() {
- ctr, volumes, err := containerToV1Container(ctr)
+ ctr, volumes, _, err := containerToV1Container(ctr)
if err != nil {
return nil, err
}
@@ -196,6 +198,22 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
vol := vol
deDupPodVolumes[vol.Name] = &vol
}
+ } else {
+ _, _, infraDNS, err := containerToV1Container(ctr)
+ if err != nil {
+ return nil, err
+ }
+ if infraDNS != nil {
+ if servers := infraDNS.Nameservers; len(servers) > 0 {
+ dnsInfo.Nameservers = servers
+ }
+ if searches := infraDNS.Searches; len(searches) > 0 {
+ dnsInfo.Searches = searches
+ }
+ if options := infraDNS.Options; len(options) > 0 {
+ dnsInfo.Options = options
+ }
+ }
}
}
podVolumes := make([]v1.Volume, 0, len(deDupPodVolumes))
@@ -203,10 +221,10 @@ func (p *Pod) podWithContainers(containers []*Container, ports []v1.ContainerPor
podVolumes = append(podVolumes, *vol)
}
- return addContainersAndVolumesToPodObject(podContainers, podVolumes, p.Name()), nil
+ return addContainersAndVolumesToPodObject(podContainers, podVolumes, p.Name(), &dnsInfo, hostNetwork), nil
}
-func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.Volume, podName string) *v1.Pod {
+func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.Volume, podName string, dnsOptions *v1.PodDNSConfig, hostNetwork bool) *v1.Pod {
tm := v12.TypeMeta{
Kind: "Pod",
APIVersion: "v1",
@@ -225,8 +243,12 @@ func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.
CreationTimestamp: v12.Now(),
}
ps := v1.PodSpec{
- Containers: containers,
- Volumes: volumes,
+ Containers: containers,
+ Volumes: volumes,
+ HostNetwork: hostNetwork,
+ }
+ if dnsOptions != nil {
+ ps.DNSConfig = dnsOptions
}
p := v1.Pod{
TypeMeta: tm,
@@ -241,32 +263,69 @@ func addContainersAndVolumesToPodObject(containers []v1.Container, volumes []v1.
func simplePodWithV1Containers(ctrs []*Container) (*v1.Pod, error) {
kubeCtrs := make([]v1.Container, 0, len(ctrs))
kubeVolumes := make([]v1.Volume, 0)
+ hostNetwork := true
+ podDNS := v1.PodDNSConfig{}
for _, ctr := range ctrs {
- kubeCtr, kubeVols, err := containerToV1Container(ctr)
+ if !ctr.HostNetwork() {
+ hostNetwork = false
+ }
+ kubeCtr, kubeVols, ctrDNS, err := containerToV1Container(ctr)
if err != nil {
return nil, err
}
kubeCtrs = append(kubeCtrs, kubeCtr)
kubeVolumes = append(kubeVolumes, kubeVols...)
- }
- return addContainersAndVolumesToPodObject(kubeCtrs, kubeVolumes, strings.ReplaceAll(ctrs[0].Name(), "_", "")), nil
+ // Combine DNS information in sum'd structure
+ if ctrDNS != nil {
+ // nameservers
+ if servers := ctrDNS.Nameservers; servers != nil {
+ if podDNS.Nameservers == nil {
+ podDNS.Nameservers = make([]string, 0)
+ }
+ for _, s := range servers {
+ if !util.StringInSlice(s, podDNS.Nameservers) { // only append if it does not exist
+ podDNS.Nameservers = append(podDNS.Nameservers, s)
+ }
+ }
+ }
+ // search domains
+ if domains := ctrDNS.Searches; domains != nil {
+ if podDNS.Searches == nil {
+ podDNS.Searches = make([]string, 0)
+ }
+ for _, d := range domains {
+ if !util.StringInSlice(d, podDNS.Searches) { // only append if it does not exist
+ podDNS.Searches = append(podDNS.Searches, d)
+ }
+ }
+ }
+ // dns options
+ if options := ctrDNS.Options; options != nil {
+ if podDNS.Options == nil {
+ podDNS.Options = make([]v1.PodDNSConfigOption, 0)
+ }
+ podDNS.Options = append(podDNS.Options, options...)
+ }
+ } // end if ctrDNS
+ }
+ return addContainersAndVolumesToPodObject(kubeCtrs, kubeVolumes, strings.ReplaceAll(ctrs[0].Name(), "_", ""), &podDNS, hostNetwork), nil
}
// containerToV1Container converts information we know about a libpod container
// to a V1.Container specification.
-func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
+func containerToV1Container(c *Container) (v1.Container, []v1.Volume, *v1.PodDNSConfig, error) {
kubeContainer := v1.Container{}
kubeVolumes := []v1.Volume{}
kubeSec, err := generateKubeSecurityContext(c)
if err != nil {
- return kubeContainer, kubeVolumes, err
+ return kubeContainer, kubeVolumes, nil, err
}
if len(c.config.Spec.Linux.Devices) > 0 {
// TODO Enable when we can support devices and their names
kubeContainer.VolumeDevices = generateKubeVolumeDeviceFromLinuxDevice(c.Spec().Linux.Devices)
- return kubeContainer, kubeVolumes, errors.Wrapf(define.ErrNotImplemented, "linux devices")
+ return kubeContainer, kubeVolumes, nil, errors.Wrapf(define.ErrNotImplemented, "linux devices")
}
if len(c.config.UserVolumes) > 0 {
@@ -274,7 +333,7 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
// Volume names need to be coordinated "globally" in the kube files.
volumeMounts, volumes, err := libpodMountsToKubeVolumeMounts(c)
if err != nil {
- return kubeContainer, kubeVolumes, err
+ return kubeContainer, kubeVolumes, nil, err
}
kubeContainer.VolumeMounts = volumeMounts
kubeVolumes = append(kubeVolumes, volumes...)
@@ -282,34 +341,33 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
envVariables, err := libpodEnvVarsToKubeEnvVars(c.config.Spec.Process.Env)
if err != nil {
- return kubeContainer, kubeVolumes, err
+ return kubeContainer, kubeVolumes, nil, err
}
portmappings, err := c.PortMappings()
if err != nil {
- return kubeContainer, kubeVolumes, err
+ return kubeContainer, kubeVolumes, nil, err
}
ports, err := ocicniPortMappingToContainerPort(portmappings)
if err != nil {
- return kubeContainer, kubeVolumes, err
+ return kubeContainer, kubeVolumes, nil, err
}
- containerCommands := c.Command()
- kubeContainer.Name = removeUnderscores(c.Name())
+ // Handle command and arguments.
+ if ep := c.Entrypoint(); len(ep) > 0 {
+ // If we have an entrypoint, set the container's command as
+ // arguments.
+ kubeContainer.Command = ep
+ kubeContainer.Args = c.Command()
+ } else {
+ kubeContainer.Command = c.Command()
+ }
+ kubeContainer.Name = removeUnderscores(c.Name())
_, image := c.Image()
kubeContainer.Image = image
kubeContainer.Stdin = c.Stdin()
- // prepend the entrypoint of the container to command
- if ep := c.Entrypoint(); len(c.Entrypoint()) > 0 {
- ep = append(ep, containerCommands...)
- containerCommands = ep
- }
- kubeContainer.Command = containerCommands
- // TODO need to figure out how we handle command vs entry point. Kube appears to prefer entrypoint.
- // right now we just take the container's command
- //container.Args = args
kubeContainer.WorkingDir = c.WorkingDir()
kubeContainer.Ports = ports
// This should not be applicable
@@ -355,7 +413,38 @@ func containerToV1Container(c *Container) (v1.Container, []v1.Volume, error) {
}
}
- return kubeContainer, kubeVolumes, nil
+ // Obtain the DNS entries from the container
+ dns := v1.PodDNSConfig{}
+
+ // DNS servers
+ if servers := c.config.DNSServer; len(servers) > 0 {
+ dnsServers := make([]string, 0)
+ for _, server := range servers {
+ dnsServers = append(dnsServers, server.String())
+ }
+ dns.Nameservers = dnsServers
+ }
+
+ // DNS search domains
+ if searches := c.config.DNSSearch; len(searches) > 0 {
+ dns.Searches = searches
+ }
+
+ // DNS options
+ if options := c.config.DNSOption; len(options) > 0 {
+ dnsOptions := make([]v1.PodDNSConfigOption, 0)
+ for _, option := range options {
+ // the option can be "k:v" or just "k", no delimiter is required
+ opts := strings.SplitN(option, ":", 2)
+ dnsOpt := v1.PodDNSConfigOption{
+ Name: opts[0],
+ Value: &opts[1],
+ }
+ dnsOptions = append(dnsOptions, dnsOpt)
+ }
+ dns.Options = dnsOptions
+ }
+ return kubeContainer, kubeVolumes, &dns, nil
}
// ocicniPortMappingToContainerPort takes an ocicni portmapping and converts
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index ffd39dfa9..9edea4fea 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -15,6 +15,7 @@ import (
"path/filepath"
"regexp"
"sort"
+ "strconv"
"strings"
"syscall"
"time"
@@ -42,6 +43,9 @@ const (
// slirp4netnsDNS is the IP for the built-in DNS server in the slirp network
slirp4netnsDNS = "10.0.2.3"
+
+ // slirp4netnsMTU the default MTU override
+ slirp4netnsMTU = 65520
)
// Get an OCICNI network config
@@ -282,6 +286,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
enableIPv6 := false
outboundAddr := ""
outboundAddr6 := ""
+ mtu := slirp4netnsMTU
if ctr.config.NetworkOptions != nil {
slirpOptions = append(slirpOptions, ctr.config.NetworkOptions["slirp4netns"]...)
@@ -345,6 +350,11 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
}
}
outboundAddr6 = value
+ case "mtu":
+ mtu, err = strconv.Atoi(value)
+ if mtu < 68 || err != nil {
+ return errors.Errorf("invalid mtu %q", value)
+ }
default:
return errors.Errorf("unknown option for slirp4netns: %q", o)
}
@@ -358,8 +368,8 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
if disableHostLoopback && slirpFeatures.HasDisableHostLoopback {
cmdArgs = append(cmdArgs, "--disable-host-loopback")
}
- if slirpFeatures.HasMTU {
- cmdArgs = append(cmdArgs, "--mtu", "65520")
+ if mtu > -1 && slirpFeatures.HasMTU {
+ cmdArgs = append(cmdArgs, fmt.Sprintf("--mtu=%d", mtu))
}
if !noPivotRoot && slirpFeatures.HasEnableSandbox {
cmdArgs = append(cmdArgs, "--enable-sandbox")
@@ -1158,7 +1168,7 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
// update network status if container is not running
networkStatus := c.state.NetworkStatus
// clip out the index of the network
- tmpNetworkStatus := make([]*cnitypes.Result, len(networkStatus)-1)
+ tmpNetworkStatus := make([]*cnitypes.Result, 0, len(networkStatus)-1)
for k, v := range networkStatus {
if index != k {
tmpNetworkStatus = append(tmpNetworkStatus, v)
diff --git a/libpod/options.go b/libpod/options.go
index c7bac7e1f..20f62ee37 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -2190,13 +2190,37 @@ func WithPodNetworks(networks []string) PodCreateOption {
}
}
+// WithPodNoNetwork tells the pod to disable external networking.
+func WithPodNoNetwork() PodCreateOption {
+ return func(pod *Pod) error {
+ if pod.valid {
+ return define.ErrPodFinalized
+ }
+
+ if !pod.config.InfraContainer.HasInfraContainer {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot disable pod networking as no infra container is being created")
+ }
+
+ if len(pod.config.InfraContainer.PortBindings) > 0 ||
+ pod.config.InfraContainer.StaticIP != nil ||
+ pod.config.InfraContainer.StaticMAC != nil ||
+ len(pod.config.InfraContainer.Networks) > 0 ||
+ pod.config.InfraContainer.HostNetwork {
+ return errors.Wrapf(define.ErrInvalidArg, "cannot disable pod network if network-related configuration is specified")
+ }
+
+ pod.config.InfraContainer.NoNetwork = true
+
+ return nil
+ }
+}
+
// WithPodHostNetwork tells the pod to use the host's network namespace.
func WithPodHostNetwork() PodCreateOption {
return func(pod *Pod) error {
if pod.valid {
return define.ErrPodFinalized
}
-
if !pod.config.InfraContainer.HasInfraContainer {
return errors.Wrapf(define.ErrInvalidArg, "cannot configure pod host networking as no infra container is being created")
}
@@ -2204,7 +2228,8 @@ func WithPodHostNetwork() PodCreateOption {
if len(pod.config.InfraContainer.PortBindings) > 0 ||
pod.config.InfraContainer.StaticIP != nil ||
pod.config.InfraContainer.StaticMAC != nil ||
- len(pod.config.InfraContainer.Networks) > 0 {
+ len(pod.config.InfraContainer.Networks) > 0 ||
+ pod.config.InfraContainer.NoNetwork {
return errors.Wrapf(define.ErrInvalidArg, "cannot set host network if network-related configuration is specified")
}
diff --git a/libpod/pod.go b/libpod/pod.go
index c8f62ca18..784c2cf5e 100644
--- a/libpod/pod.go
+++ b/libpod/pod.go
@@ -93,6 +93,7 @@ type podState struct {
type InfraContainerConfig struct {
ConmonPidFile string `json:"conmonPidFile"`
HasInfraContainer bool `json:"makeInfraContainer"`
+ NoNetwork bool `json:"noNetwork,omitempty"`
HostNetwork bool `json:"infraHostNetwork,omitempty"`
PortBindings []ocicni.PortMapping `json:"infraPortBindings"`
StaticIP net.IP `json:"staticIP,omitempty"`
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index dd957527d..564851f4e 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -94,8 +94,16 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
}
}
- // Since user namespace sharing is not implemented, we only need to check if it's rootless
- if !p.config.InfraContainer.HostNetwork {
+ switch {
+ case p.config.InfraContainer.HostNetwork:
+ if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
+ return nil, errors.Wrapf(err, "error removing network namespace from pod %s infra container", p.ID())
+ }
+ case p.config.InfraContainer.NoNetwork:
+ // Do nothing - we have a network namespace by default,
+ // but should not configure slirp.
+ default:
+ // Since user namespace sharing is not implemented, we only need to check if it's rootless
netmode := "bridge"
if isRootless || p.config.InfraContainer.Slirp4netns {
netmode = "slirp4netns"
@@ -106,8 +114,6 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm
// PostConfigureNetNS should not be set since user namespace sharing is not implemented
// and rootless networking no longer supports post configuration setup
options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, false, netmode, p.config.InfraContainer.Networks))
- } else if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
- return nil, errors.Wrapf(err, "error removing network namespace from pod %s infra container", p.ID())
}
// For each option in InfraContainerConfig - if set, pass into
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index 5c5586323..a8f850823 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -20,6 +20,7 @@ import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/go-connections/nat"
+ "github.com/docker/go-units"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
"github.com/pkg/errors"
@@ -263,6 +264,7 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error
sizeRootFs int64
sizeRW int64
state define.ContainerStatus
+ status string
)
if state, err = l.State(); err != nil {
@@ -273,6 +275,35 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error
stateStr = "created"
}
+ if state == define.ContainerStateConfigured || state == define.ContainerStateCreated {
+ status = "Created"
+ } else if state == define.ContainerStateStopped || state == define.ContainerStateExited {
+ exitCode, _, err := l.ExitCode()
+ if err != nil {
+ return nil, err
+ }
+ finishedTime, err := l.FinishedTime()
+ if err != nil {
+ return nil, err
+ }
+ status = fmt.Sprintf("Exited (%d) %s ago", exitCode, units.HumanDuration(time.Since(finishedTime)))
+ } else if state == define.ContainerStateRunning || state == define.ContainerStatePaused {
+ startedTime, err := l.StartedTime()
+ if err != nil {
+ return nil, err
+ }
+ status = fmt.Sprintf("Up %s", units.HumanDuration(time.Since(startedTime)))
+ if state == define.ContainerStatePaused {
+ status += " (Paused)"
+ }
+ } else if state == define.ContainerStateRemoving {
+ status = "Removal In Progress"
+ } else if state == define.ContainerStateStopping {
+ status = "Stopping"
+ } else {
+ status = "Unknown"
+ }
+
if sz {
if sizeRW, err = l.RWSize(); err != nil {
return nil, err
@@ -294,7 +325,7 @@ func LibpodToContainer(l *libpod.Container, sz bool) (*handlers.Container, error
SizeRootFs: sizeRootFs,
Labels: l.Labels(),
State: stateStr,
- Status: "",
+ Status: status,
HostConfig: struct {
NetworkMode string `json:",omitempty"`
}{
diff --git a/pkg/api/handlers/compat/resize.go b/pkg/api/handlers/compat/resize.go
index cc8c6ef0a..a769ae1b5 100644
--- a/pkg/api/handlers/compat/resize.go
+++ b/pkg/api/handlers/compat/resize.go
@@ -84,5 +84,5 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) {
// reasons.
status = http.StatusCreated
}
- utils.WriteResponse(w, status, "")
+ w.WriteHeader(status)
}
diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go
index 2409d3a20..2c35dd191 100644
--- a/pkg/api/handlers/libpod/pods.go
+++ b/pkg/api/handlers/libpod/pods.go
@@ -139,19 +139,20 @@ func PodStop(w http.ResponseWriter, r *http.Request) {
logrus.Errorf("Error cleaning up pod %s container %s: %v", pod.ID(), id, err)
}
}
- var errs []error //nolint
+
+ report := entities.PodStopReport{Id: pod.ID()}
for id, err := range responses {
- errs = append(errs, errors.Wrapf(err, "error stopping container %s", id))
+ report.Errs = append(report.Errs, errors.Wrapf(err, "error stopping container %s", id))
}
- report := entities.PodStopReport{
- Errs: errs,
- Id: pod.ID(),
+
+ code := http.StatusOK
+ if len(report.Errs) > 0 {
+ code = http.StatusConflict
}
- utils.WriteResponse(w, http.StatusOK, report)
+ utils.WriteResponse(w, code, report)
}
func PodStart(w http.ResponseWriter, r *http.Request) {
- var errs []error //nolint
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
pod, err := runtime.LookupPod(name)
@@ -168,19 +169,23 @@ func PodStart(w http.ResponseWriter, r *http.Request) {
utils.WriteResponse(w, http.StatusNotModified, "")
return
}
+
responses, err := pod.Start(r.Context())
if err != nil && errors.Cause(err) != define.ErrPodPartialFail {
- utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
+ utils.Error(w, "Something went wrong", http.StatusConflict, err)
return
}
+
+ report := entities.PodStartReport{Id: pod.ID()}
for id, err := range responses {
- errs = append(errs, errors.Wrapf(err, "error starting container %s", id))
+ report.Errs = append(report.Errs, errors.Wrapf(err, "error starting container "+id))
}
- report := entities.PodStartReport{
- Errs: errs,
- Id: pod.ID(),
+
+ code := http.StatusOK
+ if len(report.Errs) > 0 {
+ code = http.StatusConflict
}
- utils.WriteResponse(w, http.StatusOK, report)
+ utils.WriteResponse(w, code, report)
}
func PodDelete(w http.ResponseWriter, r *http.Request) {
@@ -209,14 +214,11 @@ func PodDelete(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
- report := entities.PodRmReport{
- Id: pod.ID(),
- }
+ report := entities.PodRmReport{Id: pod.ID()}
utils.WriteResponse(w, http.StatusOK, report)
}
func PodRestart(w http.ResponseWriter, r *http.Request) {
- var errs []error //nolint
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
pod, err := runtime.LookupPod(name)
@@ -229,14 +231,17 @@ func PodRestart(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
+
+ report := entities.PodRestartReport{Id: pod.ID()}
for id, err := range responses {
- errs = append(errs, errors.Wrapf(err, "error restarting container %s", id))
+ report.Errs = append(report.Errs, errors.Wrapf(err, "error restarting container %s", id))
}
- report := entities.PodRestartReport{
- Errs: errs,
- Id: pod.ID(),
+
+ code := http.StatusOK
+ if len(report.Errs) > 0 {
+ code = http.StatusConflict
}
- utils.WriteResponse(w, http.StatusOK, report)
+ utils.WriteResponse(w, code, report)
}
func PodPrune(w http.ResponseWriter, r *http.Request) {
@@ -267,7 +272,6 @@ func PodPruneHelper(r *http.Request) ([]*entities.PodPruneReport, error) {
}
func PodPause(w http.ResponseWriter, r *http.Request) {
- var errs []error //nolint
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
pod, err := runtime.LookupPod(name)
@@ -280,18 +284,20 @@ func PodPause(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
return
}
+
+ report := entities.PodPauseReport{Id: pod.ID()}
for id, v := range responses {
- errs = append(errs, errors.Wrapf(v, "error pausing container %s", id))
+ report.Errs = append(report.Errs, errors.Wrapf(v, "error pausing container %s", id))
}
- report := entities.PodPauseReport{
- Errs: errs,
- Id: pod.ID(),
+
+ code := http.StatusOK
+ if len(report.Errs) > 0 {
+ code = http.StatusConflict
}
- utils.WriteResponse(w, http.StatusOK, report)
+ utils.WriteResponse(w, code, report)
}
func PodUnpause(w http.ResponseWriter, r *http.Request) {
- var errs []error //nolint
runtime := r.Context().Value("runtime").(*libpod.Runtime)
name := utils.GetName(r)
pod, err := runtime.LookupPod(name)
@@ -304,14 +310,17 @@ func PodUnpause(w http.ResponseWriter, r *http.Request) {
utils.Error(w, "failed to pause pod", http.StatusInternalServerError, err)
return
}
+
+ report := entities.PodUnpauseReport{Id: pod.ID()}
for id, v := range responses {
- errs = append(errs, errors.Wrapf(v, "error unpausing container %s", id))
+ report.Errs = append(report.Errs, errors.Wrapf(v, "error unpausing container %s", id))
}
- report := entities.PodUnpauseReport{
- Errs: errs,
- Id: pod.ID(),
+
+ code := http.StatusOK
+ if len(report.Errs) > 0 {
+ code = http.StatusConflict
}
- utils.WriteResponse(w, http.StatusOK, &report)
+ utils.WriteResponse(w, code, &report)
}
func PodTop(w http.ResponseWriter, r *http.Request) {
@@ -361,7 +370,6 @@ func PodKill(w http.ResponseWriter, r *http.Request) {
runtime = r.Context().Value("runtime").(*libpod.Runtime)
decoder = r.Context().Value("decoder").(*schema.Decoder)
signal = "SIGKILL"
- errs []error //nolint
)
query := struct {
Signal string `schema:"signal"`
@@ -413,16 +421,18 @@ func PodKill(w http.ResponseWriter, r *http.Request) {
return
}
+ report := &entities.PodKillReport{Id: pod.ID()}
for _, v := range responses {
if v != nil {
- errs = append(errs, v)
+ report.Errs = append(report.Errs, v)
}
}
- report := &entities.PodKillReport{
- Errs: errs,
- Id: pod.ID(),
+
+ code := http.StatusOK
+ if len(report.Errs) > 0 {
+ code = http.StatusConflict
}
- utils.WriteResponse(w, http.StatusOK, report)
+ utils.WriteResponse(w, code, report)
}
func PodExists(w http.ResponseWriter, r *http.Request) {
diff --git a/pkg/api/handlers/utils/handler.go b/pkg/api/handlers/utils/handler.go
index 517dccad0..b3c674788 100644
--- a/pkg/api/handlers/utils/handler.go
+++ b/pkg/api/handlers/utils/handler.go
@@ -1,16 +1,17 @@
package utils
import (
- "encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"
+ "unsafe"
"github.com/blang/semver"
"github.com/gorilla/mux"
+ jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -43,8 +44,8 @@ var (
// clients to shop for the Version they wish to support
APIVersion = map[VersionTree]map[VersionLevel]semver.Version{
LibpodTree: {
- CurrentAPIVersion: semver.MustParse("2.0.0"),
- MinimalAPIVersion: semver.MustParse("2.0.0"),
+ CurrentAPIVersion: semver.MustParse("3.0.0"),
+ MinimalAPIVersion: semver.MustParse("3.0.0"),
},
CompatTree: {
CurrentAPIVersion: semver.MustParse("1.40.0"),
@@ -144,6 +145,50 @@ func WriteResponse(w http.ResponseWriter, code int, value interface{}) {
}
}
+func init() {
+ jsoniter.RegisterTypeEncoderFunc("error", MarshalErrorJSON, MarshalErrorJSONIsEmpty)
+ jsoniter.RegisterTypeEncoderFunc("[]error", MarshalErrorSliceJSON, MarshalErrorSliceJSONIsEmpty)
+}
+
+var json = jsoniter.ConfigCompatibleWithStandardLibrary
+
+// MarshalErrorJSON writes error to stream as string
+func MarshalErrorJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
+ p := *((*error)(ptr))
+ if p == nil {
+ stream.WriteNil()
+ } else {
+ stream.WriteString(p.Error())
+ }
+}
+
+// MarshalErrorSliceJSON writes []error to stream as []string JSON blob
+func MarshalErrorSliceJSON(ptr unsafe.Pointer, stream *jsoniter.Stream) {
+ a := *((*[]error)(ptr))
+ switch {
+ case len(a) == 0:
+ stream.WriteNil()
+ default:
+ stream.WriteArrayStart()
+ for i, e := range a {
+ if i > 0 {
+ stream.WriteMore()
+ }
+ stream.WriteString(e.Error())
+ }
+ stream.WriteArrayEnd()
+ }
+}
+
+func MarshalErrorJSONIsEmpty(_ unsafe.Pointer) bool {
+ return false
+}
+
+func MarshalErrorSliceJSONIsEmpty(_ unsafe.Pointer) bool {
+ return false
+}
+
+// WriteJSON writes an interface value encoded as JSON to w
func WriteJSON(w http.ResponseWriter, code int, value interface{}) {
// FIXME: we don't need to write the header in all/some circumstances.
w.Header().Set("Content-Type", "application/json")
diff --git a/pkg/api/server/register_pods.go b/pkg/api/server/register_pods.go
index 105de4ee7..4873eb926 100644
--- a/pkg/api/server/register_pods.go
+++ b/pkg/api/server/register_pods.go
@@ -43,6 +43,11 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// $ref: "#/definitions/IdResponse"
// 400:
// $ref: "#/responses/BadParamError"
+ // 409:
+ // description: status conflict
+ // schema:
+ // type: string
+ // description: message describing error
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/pods/create"), s.APIHandler(libpod.PodCreate)).Methods(http.MethodPost)
@@ -149,7 +154,7 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// 404:
// $ref: "#/responses/NoSuchPod"
// 409:
- // $ref: "#/responses/ConflictError"
+ // $ref: "#/responses/PodKillReport"
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/pods/{name}/kill"), s.APIHandler(libpod.PodKill)).Methods(http.MethodPost)
@@ -170,6 +175,8 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// $ref: '#/responses/PodPauseReport'
// 404:
// $ref: "#/responses/NoSuchPod"
+ // 409:
+ // $ref: '#/responses/PodPauseReport'
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/pods/{name}/pause"), s.APIHandler(libpod.PodPause)).Methods(http.MethodPost)
@@ -189,6 +196,8 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// $ref: '#/responses/PodRestartReport'
// 404:
// $ref: "#/responses/NoSuchPod"
+ // 409:
+ // $ref: "#/responses/PodRestartReport"
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/pods/{name}/restart"), s.APIHandler(libpod.PodRestart)).Methods(http.MethodPost)
@@ -210,6 +219,8 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// $ref: "#/responses/PodAlreadyStartedError"
// 404:
// $ref: "#/responses/NoSuchPod"
+ // 409:
+ // $ref: '#/responses/PodStartReport'
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/pods/{name}/start"), s.APIHandler(libpod.PodStart)).Methods(http.MethodPost)
@@ -237,6 +248,8 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// $ref: "#/responses/BadParamError"
// 404:
// $ref: "#/responses/NoSuchPod"
+ // 409:
+ // $ref: "#/responses/PodStopReport"
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/pods/{name}/stop"), s.APIHandler(libpod.PodStop)).Methods(http.MethodPost)
@@ -256,6 +269,8 @@ func (s *APIServer) registerPodsHandlers(r *mux.Router) error {
// $ref: '#/responses/PodUnpauseReport'
// 404:
// $ref: "#/responses/NoSuchPod"
+ // 409:
+ // $ref: '#/responses/PodUnpauseReport'
// 500:
// $ref: "#/responses/InternalError"
r.Handle(VersionedPath("/libpod/pods/{name}/unpause"), s.APIHandler(libpod.PodUnpause)).Methods(http.MethodPost)
diff --git a/pkg/bindings/containers/attach.go b/pkg/bindings/containers/attach.go
index 69ae7a32f..586cdec8c 100644
--- a/pkg/bindings/containers/attach.go
+++ b/pkg/bindings/containers/attach.go
@@ -348,7 +348,7 @@ func attachHandleResize(ctx, winCtx context.Context, winChange chan os.Signal, i
resizeErr = ResizeContainerTTY(ctx, id, new(ResizeTTYOptions).WithHeight(h).WithWidth(w))
}
if resizeErr != nil {
- logrus.Warnf("failed to resize TTY: %v", err)
+ logrus.Warnf("failed to resize TTY: %v", resizeErr)
}
}
}
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index c200dd01a..285fd093a 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -24,6 +24,7 @@ var (
ErrCgroupDeleted = errors.New("cgroup deleted")
// ErrCgroupV1Rootless means the cgroup v1 were attempted to be used in rootless environment
ErrCgroupV1Rootless = errors.New("no support for CGroups V1 in rootless environments")
+ ErrStatCgroup = errors.New("no cgroup available for gathering user statistics")
)
// CgroupControl controls a cgroup hierarchy
@@ -525,10 +526,19 @@ func (c *CgroupControl) AddPid(pid int) error {
// Stat returns usage statistics for the cgroup
func (c *CgroupControl) Stat() (*Metrics, error) {
m := Metrics{}
+ found := false
for _, h := range handlers {
if err := h.Stat(c, &m); err != nil {
- return nil, err
+ if !os.IsNotExist(errors.Cause(err)) {
+ return nil, err
+ }
+ logrus.Warningf("Failed to retrieve cgroup stats: %v", err)
+ continue
}
+ found = true
+ }
+ if !found {
+ return nil, ErrStatCgroup
}
return &m, nil
}
diff --git a/pkg/cgroups/cgroups_test.go b/pkg/cgroups/cgroups_test.go
new file mode 100644
index 000000000..54315f7be
--- /dev/null
+++ b/pkg/cgroups/cgroups_test.go
@@ -0,0 +1,32 @@
+package cgroups
+
+import (
+ "testing"
+
+ "github.com/containers/podman/v2/pkg/rootless"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+func TestCreated(t *testing.T) {
+ // tests only works in rootless mode
+ if rootless.IsRootless() {
+ return
+ }
+
+ var resources spec.LinuxResources
+ cgr, err := New("machine.slice", &resources)
+ if err != nil {
+ t.Error(err)
+ }
+ if err := cgr.Delete(); err != nil {
+ t.Error(err)
+ }
+
+ cgr, err = NewSystemd("machine.slice")
+ if err != nil {
+ t.Error(err)
+ }
+ if err := cgr.Delete(); err != nil {
+ t.Error(err)
+ }
+}
diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go
index e39a700eb..98ab82259 100644
--- a/pkg/specgen/generate/kube/kube.go
+++ b/pkg/specgen/generate/kube/kube.go
@@ -3,6 +3,7 @@ package kube
import (
"context"
"fmt"
+ "net"
"strings"
"github.com/containers/common/pkg/parse"
@@ -44,6 +45,31 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec)
podPorts := getPodPorts(podYAML.Spec.Containers)
p.PortMappings = podPorts
+ if dnsConfig := podYAML.Spec.DNSConfig; dnsConfig != nil {
+ // name servers
+ if dnsServers := dnsConfig.Nameservers; len(dnsServers) > 0 {
+ servers := make([]net.IP, 0)
+ for _, server := range dnsServers {
+ servers = append(servers, net.ParseIP(server))
+ }
+ p.DNSServer = servers
+ }
+ // search domans
+ if domains := dnsConfig.Searches; len(domains) > 0 {
+ p.DNSSearch = domains
+ }
+ // dns options
+ if options := dnsConfig.Options; len(options) > 0 {
+ dnsOptions := make([]string, 0)
+ for _, opts := range options {
+ d := opts.Name
+ if opts.Value != nil {
+ d += ":" + *opts.Value
+ }
+ dnsOptions = append(dnsOptions, d)
+ }
+ }
+ }
return p, nil
}
@@ -256,16 +282,16 @@ func setupSecurityContext(s *specgen.SpecGenerator, containerYAML v1.Container)
if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil {
if seopt.User != "" {
- s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("role:%s", seopt.User))
+ s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("user:%s", seopt.User))
}
if seopt.Role != "" {
s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("role:%s", seopt.Role))
}
if seopt.Type != "" {
- s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("role:%s", seopt.Type))
+ s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("type:%s", seopt.Type))
}
if seopt.Level != "" {
- s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("role:%s", seopt.Level))
+ s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("level:%s", seopt.Level))
}
}
if caps := containerYAML.SecurityContext.Capabilities; caps != nil {
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index 43caf0fe9..645bf7a47 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -102,6 +102,9 @@ func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime) ([]libpod
case specgen.Slirp:
logrus.Debugf("Pod will use slirp4netns")
options = append(options, libpod.WithPodSlirp4netns(p.NetworkOptions))
+ case specgen.NoNetwork:
+ logrus.Debugf("Pod will not use networking")
+ options = append(options, libpod.WithPodNoNetwork())
default:
return nil, errors.Errorf("pods presently do not support network mode %s", p.NetNS.NSMode)
}
diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go
index de6751a17..e9902319c 100644
--- a/pkg/systemd/generate/common.go
+++ b/pkg/systemd/generate/common.go
@@ -60,13 +60,21 @@ func filterPodFlags(command []string) []string {
return processed
}
-// quoteArguments makes sure that all arguments with at least one whitespace
+// escapeSystemdArguments makes sure that all arguments with at least one whitespace
// are quoted to make sure those are interpreted as one argument instead of
-// multiple ones.
-func quoteArguments(command []string) []string {
+// multiple ones. Also make sure to escape all characters which have a special
+// meaning to systemd -> $,% and \
+// see: https://www.freedesktop.org/software/systemd/man/systemd.service.html#Command%20lines
+func escapeSystemdArguments(command []string) []string {
for i := range command {
+ command[i] = strings.ReplaceAll(command[i], "$", "$$")
+ command[i] = strings.ReplaceAll(command[i], "%", "%%")
if strings.ContainsAny(command[i], " \t") {
command[i] = strconv.Quote(command[i])
+ } else if strings.Contains(command[i], `\`) {
+ // strconv.Quote also escapes backslashes so
+ // we should replace only if strconv.Quote was not used
+ command[i] = strings.ReplaceAll(command[i], `\`, `\\`)
}
}
return command
diff --git a/pkg/systemd/generate/common_test.go b/pkg/systemd/generate/common_test.go
index d0ec5637c..a0691d1ad 100644
--- a/pkg/systemd/generate/common_test.go
+++ b/pkg/systemd/generate/common_test.go
@@ -29,7 +29,7 @@ func TestFilterPodFlags(t *testing.T) {
}
}
-func TestQuoteArguments(t *testing.T) {
+func TestEscapeSystemdArguments(t *testing.T) {
tests := []struct {
input []string
output []string
@@ -46,10 +46,46 @@ func TestQuoteArguments(t *testing.T) {
[]string{"foo", "bar=\"arg with\ttab\""},
[]string{"foo", "\"bar=\\\"arg with\\ttab\\\"\""},
},
+ {
+ []string{"$"},
+ []string{"$$"},
+ },
+ {
+ []string{"foo", "command with dollar sign $"},
+ []string{"foo", "\"command with dollar sign $$\""},
+ },
+ {
+ []string{"foo", "command with two dollar signs $$"},
+ []string{"foo", "\"command with two dollar signs $$$$\""},
+ },
+ {
+ []string{"%"},
+ []string{"%%"},
+ },
+ {
+ []string{"foo", "command with percent sign %"},
+ []string{"foo", "\"command with percent sign %%\""},
+ },
+ {
+ []string{"foo", "command with two percent signs %%"},
+ []string{"foo", "\"command with two percent signs %%%%\""},
+ },
+ {
+ []string{`\`},
+ []string{`\\`},
+ },
+ {
+ []string{"foo", `command with backslash \`},
+ []string{"foo", `"command with backslash \\"`},
+ },
+ {
+ []string{"foo", `command with two backslashs \\`},
+ []string{"foo", `"command with two backslashs \\\\"`},
+ },
}
for _, test := range tests {
- quoted := quoteArguments(test.input)
+ quoted := escapeSystemdArguments(test.input)
assert.Equal(t, test.output, quoted)
}
}
diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go
index 5f52b0a77..abe159812 100644
--- a/pkg/systemd/generate/containers.go
+++ b/pkg/systemd/generate/containers.go
@@ -204,7 +204,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
startCommand := []string{info.Executable}
if index > 2 {
// include root flags
- info.RootFlags = strings.Join(quoteArguments(info.CreateCommand[1:index-1]), " ")
+ info.RootFlags = strings.Join(escapeSystemdArguments(info.CreateCommand[1:index-1]), " ")
startCommand = append(startCommand, info.CreateCommand[1:index-1]...)
}
startCommand = append(startCommand,
@@ -279,7 +279,7 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst
}
}
startCommand = append(startCommand, remainingCmd...)
- startCommand = quoteArguments(startCommand)
+ startCommand = escapeSystemdArguments(startCommand)
info.ExecStartPre = "/bin/rm -f {{{{.PIDFile}}}} {{{{.ContainerIDFile}}}}"
info.ExecStart = strings.Join(startCommand, " ")
diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go
index 96d95644b..be14e4c28 100644
--- a/pkg/systemd/generate/containers_test.go
+++ b/pkg/systemd/generate/containers_test.go
@@ -352,6 +352,30 @@ Type=forking
[Install]
WantedBy=multi-user.target default.target
`
+
+ goodNewWithSpecialChars := `# jadda-jadda.service
+# autogenerated by Podman CI
+
+[Unit]
+Description=Podman jadda-jadda.service
+Documentation=man:podman-generate-systemd(1)
+Wants=network.target
+After=network-online.target
+
+[Service]
+Environment=PODMAN_SYSTEMD_UNIT=%n
+Restart=always
+TimeoutStopSec=70
+ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id
+ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --replace --name test awesome-image:latest sh -c "kill $$$$ && echo %%\\"
+ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10
+ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id
+PIDFile=%t/jadda-jadda.pid
+Type=forking
+
+[Install]
+WantedBy=multi-user.target default.target
+`
tests := []struct {
name string
info containerInfo
@@ -647,6 +671,22 @@ WantedBy=multi-user.target default.target
true,
false,
},
+ {"good with special chars",
+ containerInfo{
+ Executable: "/usr/bin/podman",
+ ServiceName: "jadda-jadda",
+ ContainerNameOrID: "jadda-jadda",
+ RestartPolicy: "always",
+ PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid",
+ StopTimeout: 10,
+ PodmanVersion: "CI",
+ CreateCommand: []string{"I'll get stripped", "create", "--name", "test", "awesome-image:latest", "sh", "-c", "kill $$ && echo %\\"},
+ EnvVariable: EnvVariable,
+ },
+ goodNewWithSpecialChars,
+ true,
+ false,
+ },
}
for _, tt := range tests {
test := tt
diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go
index c7e3aa955..d6ede19af 100644
--- a/pkg/systemd/generate/pods.go
+++ b/pkg/systemd/generate/pods.go
@@ -269,7 +269,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
return "", errors.Errorf("pod does not appear to be created via `podman pod create`: %v", info.CreateCommand)
}
podRootArgs = info.CreateCommand[1 : podCreateIndex-1]
- info.RootFlags = strings.Join(quoteArguments(podRootArgs), " ")
+ info.RootFlags = strings.Join(escapeSystemdArguments(podRootArgs), " ")
podCreateArgs = filterPodFlags(info.CreateCommand[podCreateIndex+1:])
}
// We're hard-coding the first five arguments and append the
@@ -306,7 +306,7 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions)
}
startCommand = append(startCommand, podCreateArgs...)
- startCommand = quoteArguments(startCommand)
+ startCommand = escapeSystemdArguments(startCommand)
info.ExecStartPre1 = "/bin/rm -f {{{{.PIDFile}}}} {{{{.PodIDFile}}}}"
info.ExecStartPre2 = strings.Join(startCommand, " ")
diff --git a/pkg/terminal/console_windows.go b/pkg/terminal/console_windows.go
index c7691857c..08e66cb3a 100644
--- a/pkg/terminal/console_windows.go
+++ b/pkg/terminal/console_windows.go
@@ -30,7 +30,7 @@ func setConsoleMode(handle windows.Handle, flags uint32) error {
if err := windows.SetConsoleMode(handle, mode|flags); err != nil {
// In similar code, it is not considered an error if we cannot set the
// console mode. Following same line of thinking here.
- logrus.WithError(err).Error("Failed to set console mode for cli")
+ logrus.WithError(err).Debug("Failed to set console mode for cli")
}
return nil
diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go
index 580aaf4f2..b3a38f286 100644
--- a/pkg/util/mountOpts.go
+++ b/pkg/util/mountOpts.go
@@ -86,6 +86,10 @@ func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string
return nil, errors.Wrapf(ErrDupeMntOption, "the 'tmpcopyup' or 'notmpcopyup' option can only be set once")
}
foundCopyUp = true
+ case "consistency":
+ // Often used on MACs and mistakenly on Linux platforms.
+ // Since Docker ignores this option so shall we.
+ continue
case "notmpcopyup":
if !isTmpfs {
return nil, errors.Wrapf(ErrBadMntOption, "the 'notmpcopyup' option is only allowed with tmpfs mounts")
diff --git a/test/apiv2/01-basic.at b/test/apiv2/01-basic.at
index f550d5fc3..1ddf49c6f 100644
--- a/test/apiv2/01-basic.at
+++ b/test/apiv2/01-basic.at
@@ -18,8 +18,8 @@ t HEAD libpod/_ping 200
for i in /version version; do
t GET $i 200 \
.Components[0].Name="Podman Engine" \
- .Components[0].Details.APIVersion=2.0.0 \
- .Components[0].Details.MinAPIVersion=2.0.0 \
+ .Components[0].Details.APIVersion=3.0.0 \
+ .Components[0].Details.MinAPIVersion=3.0.0 \
.Components[0].Details.Os=linux \
.ApiVersion=1.40 \
.MinAPIVersion=1.24 \
diff --git a/test/apiv2/rest_api/test_rest_v2_0_0.py b/test/apiv2/rest_api/test_rest_v2_0_0.py
index cc66dd5af..520aa161b 100644
--- a/test/apiv2/rest_api/test_rest_v2_0_0.py
+++ b/test/apiv2/rest_api/test_rest_v2_0_0.py
@@ -1,7 +1,6 @@
import json
import os
import random
-import shutil
import string
import subprocess
import sys
@@ -163,7 +162,7 @@ class TestApi(unittest.TestCase):
r = requests.post(_url(ctnr("/containers/{}/resize?h=43&w=80")))
self.assertIn(r.status_code, (200, 409), r.text)
if r.status_code == 200:
- self.assertIsNone(r.text)
+ self.assertEqual(r.text, "", r.text)
def test_attach_containers(self):
self.skipTest("FIXME: Test timeouts")
@@ -586,6 +585,117 @@ class TestApi(unittest.TestCase):
# self.assertIn(img["Id"], prune_payload["ImagesDeleted"][1]["Deleted"])
self.assertIsNotNone(prune_payload["ImagesDeleted"][1]["Deleted"])
+ def test_status_compat(self):
+ r = requests.post(
+ PODMAN_URL + "/v1.40/containers/create?name=topcontainer",
+ json={"Cmd": ["top"], "Image": "alpine:latest"},
+ )
+ self.assertEqual(r.status_code, 201, r.text)
+ payload = json.loads(r.text)
+ container_id = payload["Id"]
+ self.assertIsNotNone(container_id)
+
+ r = requests.get(
+ PODMAN_URL + "/v1.40/containers/json",
+ params={"all": "true", "filters": f'{{"id":["{container_id}"]}}'},
+ )
+ self.assertEqual(r.status_code, 200, r.text)
+ payload = json.loads(r.text)
+ self.assertEqual(payload[0]["Status"], "Created")
+
+ r = requests.post(PODMAN_URL + f"/v1.40/containers/{container_id}/start")
+ self.assertEqual(r.status_code, 204, r.text)
+
+ r = requests.get(
+ PODMAN_URL + "/v1.40/containers/json",
+ params={"all": "true", "filters": f'{{"id":["{container_id}"]}}'},
+ )
+ self.assertEqual(r.status_code, 200, r.text)
+ payload = json.loads(r.text)
+ self.assertTrue(str(payload[0]["Status"]).startswith("Up"))
+
+ r = requests.post(PODMAN_URL + f"/v1.40/containers/{container_id}/pause")
+ self.assertEqual(r.status_code, 204, r.text)
+
+ r = requests.get(
+ PODMAN_URL + "/v1.40/containers/json",
+ params={"all": "true", "filters": f'{{"id":["{container_id}"]}}'},
+ )
+ self.assertEqual(r.status_code, 200, r.text)
+ payload = json.loads(r.text)
+ self.assertTrue(str(payload[0]["Status"]).startswith("Up"))
+ self.assertTrue(str(payload[0]["Status"]).endswith("(Paused)"))
+
+ r = requests.post(PODMAN_URL + f"/v1.40/containers/{container_id}/unpause")
+ self.assertEqual(r.status_code, 204, r.text)
+ r = requests.post(PODMAN_URL + f"/v1.40/containers/{container_id}/stop")
+ self.assertEqual(r.status_code, 204, r.text)
+
+ r = requests.get(
+ PODMAN_URL + "/v1.40/containers/json",
+ params={"all": "true", "filters": f'{{"id":["{container_id}"]}}'},
+ )
+ self.assertEqual(r.status_code, 200, r.text)
+ payload = json.loads(r.text)
+ self.assertTrue(str(payload[0]["Status"]).startswith("Exited"))
+
+ r = requests.delete(PODMAN_URL + f"/v1.40/containers/{container_id}")
+ self.assertEqual(r.status_code, 204, r.text)
+
+ def test_pod_start_conflict(self):
+ """Verify issue #8865"""
+
+ pod_name = list()
+ pod_name.append("Pod_" + "".join(random.choice(string.ascii_letters) for i in range(10)))
+ pod_name.append("Pod_" + "".join(random.choice(string.ascii_letters) for i in range(10)))
+
+ r = requests.post(
+ _url("/pods/create"),
+ json={
+ "name": pod_name[0],
+ "no_infra": False,
+ "portmappings": [{"host_ip": "127.0.0.1", "host_port": 8889, "container_port": 89}],
+ },
+ )
+ self.assertEqual(r.status_code, 201, r.text)
+ r = requests.post(
+ _url("/containers/create"),
+ json={
+ "pod": pod_name[0],
+ "image": "docker.io/alpine:latest",
+ "command": ["top"],
+ },
+ )
+ self.assertEqual(r.status_code, 201, r.text)
+
+ r = requests.post(
+ _url("/pods/create"),
+ json={
+ "name": pod_name[1],
+ "no_infra": False,
+ "portmappings": [{"host_ip": "127.0.0.1", "host_port": 8889, "container_port": 89}],
+ },
+ )
+ self.assertEqual(r.status_code, 201, r.text)
+ r = requests.post(
+ _url("/containers/create"),
+ json={
+ "pod": pod_name[1],
+ "image": "docker.io/alpine:latest",
+ "command": ["top"],
+ },
+ )
+ self.assertEqual(r.status_code, 201, r.text)
+
+ r = requests.post(_url(f"/pods/{pod_name[0]}/start"))
+ self.assertEqual(r.status_code, 200, r.text)
+
+ r = requests.post(_url(f"/pods/{pod_name[1]}/start"))
+ self.assertEqual(r.status_code, 409, r.text)
+
+ start = json.loads(r.text)
+ self.assertGreater(len(start["Errs"]), 0, r.text)
+
if __name__ == "__main__":
unittest.main()
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 59b52bff7..41ad9640c 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -514,27 +514,15 @@ func (s *PodmanSessionIntegration) InspectPodArrToJSON() []define.InspectPodData
// CreatePod creates a pod with no infra container
// it optionally takes a pod name
-func (p *PodmanTestIntegration) CreatePod(name string) (*PodmanSessionIntegration, int, string) {
- var podmanArgs = []string{"pod", "create", "--infra=false", "--share", ""}
- if name != "" {
- podmanArgs = append(podmanArgs, "--name", name)
+func (p *PodmanTestIntegration) CreatePod(options map[string][]string) (*PodmanSessionIntegration, int, string) {
+ var args = []string{"pod", "create", "--infra=false", "--share", ""}
+ for k, values := range options {
+ for _, v := range values {
+ args = append(args, k+"="+v)
+ }
}
- session := p.Podman(podmanArgs)
- session.WaitWithDefaultTimeout()
- return session, session.ExitCode(), session.OutputToString()
-}
-// CreatePod creates a pod with no infra container and some labels.
-// it optionally takes a pod name
-func (p *PodmanTestIntegration) CreatePodWithLabels(name string, labels map[string]string) (*PodmanSessionIntegration, int, string) {
- var podmanArgs = []string{"pod", "create", "--infra=false", "--share", ""}
- if name != "" {
- podmanArgs = append(podmanArgs, "--name", name)
- }
- for labelKey, labelValue := range labels {
- podmanArgs = append(podmanArgs, "--label", fmt.Sprintf("%s=%s", labelKey, labelValue))
- }
- session := p.Podman(podmanArgs)
+ session := p.Podman(args)
session.WaitWithDefaultTimeout()
return session, session.ExitCode(), session.OutputToString()
}
diff --git a/test/e2e/exists_test.go b/test/e2e/exists_test.go
index 480bfe5fc..306e8c250 100644
--- a/test/e2e/exists_test.go
+++ b/test/e2e/exists_test.go
@@ -83,7 +83,7 @@ var _ = Describe("Podman image|container exists", func() {
})
It("podman pod exists in local storage by name", func() {
- setup, _, _ := podmanTest.CreatePod("foobar")
+ setup, _, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar"}})
setup.WaitWithDefaultTimeout()
Expect(setup).Should(Exit(0))
@@ -92,7 +92,7 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session).Should(Exit(0))
})
It("podman pod exists in local storage by container ID", func() {
- setup, _, podID := podmanTest.CreatePod("")
+ setup, _, podID := podmanTest.CreatePod(nil)
setup.WaitWithDefaultTimeout()
Expect(setup).Should(Exit(0))
@@ -101,7 +101,7 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session).Should(Exit(0))
})
It("podman pod exists in local storage by short container ID", func() {
- setup, _, podID := podmanTest.CreatePod("")
+ setup, _, podID := podmanTest.CreatePod(nil)
setup.WaitWithDefaultTimeout()
Expect(setup).Should(Exit(0))
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index 239817e6c..bcfab0f68 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -1,6 +1,7 @@
package integration
import (
+ "io/ioutil"
"os"
"path/filepath"
"strconv"
@@ -60,6 +61,7 @@ var _ = Describe("Podman generate kube", func() {
pod := new(v1.Pod)
err := yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
+ Expect(pod.Spec.HostNetwork).To(Equal(false))
numContainers := 0
for range pod.Spec.Containers {
@@ -130,7 +132,7 @@ var _ = Describe("Podman generate kube", func() {
})
It("podman generate kube on pod", func() {
- _, rc, _ := podmanTest.CreatePod("toppod")
+ _, rc, _ := podmanTest.CreatePod(map[string][]string{"--name": {"toppod"}})
Expect(rc).To(Equal(0))
session := podmanTest.RunTopContainerInPod("topcontainer", "toppod")
@@ -144,6 +146,7 @@ var _ = Describe("Podman generate kube", func() {
pod := new(v1.Pod)
err := yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
+ Expect(pod.Spec.HostNetwork).To(Equal(false))
numContainers := 0
for range pod.Spec.Containers {
@@ -152,6 +155,40 @@ var _ = Describe("Podman generate kube", func() {
Expect(numContainers).To(Equal(1))
})
+ It("podman generate kube on pod with host network", func() {
+ podSession := podmanTest.Podman([]string{"pod", "create", "--name", "testHostNetwork", "--network", "host"})
+ podSession.WaitWithDefaultTimeout()
+ Expect(podSession.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"create", "--name", "topcontainer", "--pod", "testHostNetwork", "--network", "host", ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "testHostNetwork"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+ Expect(pod.Spec.HostNetwork).To(Equal(true))
+ })
+
+ It("podman generate kube on container with host network", func() {
+ session := podmanTest.RunTopContainerWithArgs("topcontainer", []string{"--network", "host"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "topcontainer"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+ Expect(pod.Spec.HostNetwork).To(Equal(true))
+ })
+
It("podman generate kube on pod with hostAliases", func() {
podName := "testHost"
testIP := "127.0.0.1"
@@ -185,7 +222,7 @@ var _ = Describe("Podman generate kube", func() {
})
It("podman generate service kube on pod", func() {
- _, rc, _ := podmanTest.CreatePod("toppod")
+ _, rc, _ := podmanTest.CreatePod(map[string][]string{"--name": {"toppod"}})
Expect(rc).To(Equal(0))
session := podmanTest.RunTopContainerInPod("topcontainer", "toppod")
@@ -337,7 +374,7 @@ var _ = Describe("Podman generate kube", func() {
It("podman generate and reimport kube on pod", func() {
podName := "toppod"
- _, rc, _ := podmanTest.CreatePod(podName)
+ _, rc, _ := podmanTest.CreatePod(map[string][]string{"--name": {podName}})
Expect(rc).To(Equal(0))
session := podmanTest.Podman([]string{"create", "--pod", podName, "--name", "test1", ALPINE, "top"})
@@ -376,7 +413,7 @@ var _ = Describe("Podman generate kube", func() {
It("podman generate with user and reimport kube on pod", func() {
podName := "toppod"
- _, rc, _ := podmanTest.CreatePod(podName)
+ _, rc, _ := podmanTest.CreatePod(map[string][]string{"--name": {podName}})
Expect(rc).To(Equal(0))
session := podmanTest.Podman([]string{"create", "--pod", podName, "--name", "test1", "--user", "100:200", ALPINE, "top"})
@@ -540,4 +577,126 @@ var _ = Describe("Podman generate kube", func() {
kube.WaitWithDefaultTimeout()
Expect(kube.ExitCode()).ToNot(Equal(0))
})
+
+ It("podman generate kube on a container with dns options", func() {
+ top := podmanTest.Podman([]string{"run", "-dt", "--name", "top", "--dns", "8.8.8.8", "--dns-search", "foobar.com", "--dns-opt", "color:blue", ALPINE, "top"})
+ top.WaitWithDefaultTimeout()
+ Expect(top.ExitCode()).To(BeZero())
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "top"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+
+ Expect(StringInSlice("8.8.8.8", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
+ Expect(StringInSlice("foobar.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
+ Expect(len(pod.Spec.DNSConfig.Options)).To(BeNumerically(">", 0))
+ Expect(pod.Spec.DNSConfig.Options[0].Name).To(Equal("color"))
+ Expect(*pod.Spec.DNSConfig.Options[0].Value).To(Equal("blue"))
+ })
+
+ It("podman generate kube multiple contianer dns servers and options are cumulative", func() {
+ top1 := podmanTest.Podman([]string{"run", "-dt", "--name", "top1", "--dns", "8.8.8.8", "--dns-search", "foobar.com", ALPINE, "top"})
+ top1.WaitWithDefaultTimeout()
+ Expect(top1.ExitCode()).To(BeZero())
+
+ top2 := podmanTest.Podman([]string{"run", "-dt", "--name", "top2", "--dns", "8.7.7.7", "--dns-search", "homer.com", ALPINE, "top"})
+ top2.WaitWithDefaultTimeout()
+ Expect(top2.ExitCode()).To(BeZero())
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "top1", "top2"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+
+ Expect(StringInSlice("8.8.8.8", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
+ Expect(StringInSlice("8.7.7.7", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
+ Expect(StringInSlice("foobar.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
+ Expect(StringInSlice("homer.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
+ })
+
+ It("podman generate kube on a pod with dns options", func() {
+ top := podmanTest.Podman([]string{"run", "--pod", "new:pod1", "-dt", "--name", "top", "--dns", "8.8.8.8", "--dns-search", "foobar.com", "--dns-opt", "color:blue", ALPINE, "top"})
+ top.WaitWithDefaultTimeout()
+ Expect(top.ExitCode()).To(BeZero())
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "pod1"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+
+ Expect(StringInSlice("8.8.8.8", pod.Spec.DNSConfig.Nameservers)).To(BeTrue())
+ Expect(StringInSlice("foobar.com", pod.Spec.DNSConfig.Searches)).To(BeTrue())
+ Expect(len(pod.Spec.DNSConfig.Options)).To(BeNumerically(">", 0))
+ Expect(pod.Spec.DNSConfig.Options[0].Name).To(Equal("color"))
+ Expect(*pod.Spec.DNSConfig.Options[0].Value).To(Equal("blue"))
+ })
+
+ It("podman generate kube - set entrypoint as command", func() {
+ session := podmanTest.Podman([]string{"create", "--pod", "new:testpod", "--entrypoint", "/bin/sleep", ALPINE, "10s"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "testpod"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ // Now make sure that the container's command is set to the
+ // entrypoint and it's arguments to "10s".
+ pod := new(v1.Pod)
+ err := yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+
+ containers := pod.Spec.Containers
+ Expect(len(containers)).To(Equal(1))
+
+ Expect(containers[0].Command).To(Equal([]string{"/bin/sleep"}))
+ Expect(containers[0].Args).To(Equal([]string{"10s"}))
+ })
+
+ It("podman generate kube - use entrypoint from image", func() {
+ // Build an image with an entrypoint.
+ containerfile := `FROM quay.io/libpod/alpine:latest
+ENTRYPOINT /bin/sleep`
+
+ targetPath, err := CreateTempDirInTempDir()
+ Expect(err).To(BeNil())
+ containerfilePath := filepath.Join(targetPath, "Containerfile")
+ err = ioutil.WriteFile(containerfilePath, []byte(containerfile), 0644)
+ Expect(err).To(BeNil())
+
+ image := "generatekube:test"
+ session := podmanTest.Podman([]string{"build", "-f", containerfilePath, "-t", image})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"create", "--pod", "new:testpod", image, "10s"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "testpod"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ // Now make sure that the container's command is set to the
+ // entrypoint and it's arguments to "10s".
+ pod := new(v1.Pod)
+ err = yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+
+ containers := pod.Spec.Containers
+ Expect(len(containers)).To(Equal(1))
+
+ Expect(containers[0].Command).To(Equal([]string{"/bin/sh", "-c", "/bin/sleep"}))
+ Expect(containers[0].Args).To(Equal([]string{"10s"}))
+ })
})
diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go
index dd94bd7ca..cc23b10c1 100644
--- a/test/e2e/network_connect_disconnect_test.go
+++ b/test/e2e/network_connect_disconnect_test.go
@@ -74,6 +74,11 @@ var _ = Describe("Podman network connect and disconnect", func() {
dis.WaitWithDefaultTimeout()
Expect(dis.ExitCode()).To(BeZero())
+ inspect := podmanTest.Podman([]string{"container", "inspect", "test", "--format", "{{len .NetworkSettings.Networks}}"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(BeZero())
+ Expect(inspect.OutputToString()).To(Equal("0"))
+
exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"})
exec.WaitWithDefaultTimeout()
Expect(exec.ExitCode()).ToNot(BeZero())
@@ -146,6 +151,11 @@ var _ = Describe("Podman network connect and disconnect", func() {
connect.WaitWithDefaultTimeout()
Expect(connect.ExitCode()).To(BeZero())
+ inspect := podmanTest.Podman([]string{"container", "inspect", "test", "--format", "{{len .NetworkSettings.Networks}}"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(BeZero())
+ Expect(inspect.OutputToString()).To(Equal("2"))
+
exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth1"})
exec.WaitWithDefaultTimeout()
Expect(exec.ExitCode()).To(BeZero())
@@ -167,6 +177,11 @@ var _ = Describe("Podman network connect and disconnect", func() {
dis.WaitWithDefaultTimeout()
Expect(dis.ExitCode()).To(BeZero())
+ inspect := podmanTest.Podman([]string{"container", "inspect", "test", "--format", "{{len .NetworkSettings.Networks}}"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(BeZero())
+ Expect(inspect.OutputToString()).To(Equal("2"))
+
start := podmanTest.Podman([]string{"start", "test"})
start.WaitWithDefaultTimeout()
Expect(start.ExitCode()).To(BeZero())
@@ -202,6 +217,11 @@ var _ = Describe("Podman network connect and disconnect", func() {
dis.WaitWithDefaultTimeout()
Expect(dis.ExitCode()).To(BeZero())
+ inspect := podmanTest.Podman([]string{"container", "inspect", "test", "--format", "{{len .NetworkSettings.Networks}}"})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect.ExitCode()).To(BeZero())
+ Expect(inspect.OutputToString()).To(Equal("1"))
+
start := podmanTest.Podman([]string{"start", "test"})
start.WaitWithDefaultTimeout()
Expect(start.ExitCode()).To(BeZero())
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 5930462d5..2e5c72b0e 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -13,6 +13,7 @@ import (
. "github.com/containers/podman/v2/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+ "github.com/opencontainers/selinux/go-selinux"
)
var unknownKindYaml = `
@@ -26,6 +27,49 @@ spec:
hostname: unknown
`
+var selinuxLabelPodYaml = `
+apiVersion: v1
+kind: Pod
+metadata:
+ creationTimestamp: "2021-02-02T22:18:20Z"
+ labels:
+ app: label-pod
+ name: label-pod
+spec:
+ containers:
+ - command:
+ - top
+ - -d
+ - "1.5"
+ env:
+ - name: PATH
+ value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+ - name: TERM
+ value: xterm
+ - name: container
+ value: podman
+ - name: HOSTNAME
+ value: label-pod
+ image: quay.io/libpod/alpine:latest
+ name: test
+ securityContext:
+ allowPrivilegeEscalation: true
+ capabilities:
+ drop:
+ - CAP_MKNOD
+ - CAP_NET_RAW
+ - CAP_AUDIT_WRITE
+ privileged: false
+ readOnlyRootFilesystem: false
+ seLinuxOptions:
+ user: unconfined_u
+ role: system_r
+ type: spc_t
+ level: s0
+ workingDir: /
+status: {}
+`
+
var configMapYamlTemplate = `
apiVersion: v1
kind: ConfigMap
@@ -803,6 +847,24 @@ var _ = Describe("Podman play kube", func() {
})
+ It("podman play kube fail with custom selinux label", func() {
+ if !selinux.GetEnabled() {
+ Skip("SELinux not enabled")
+ }
+ err := writeYaml(selinuxLabelPodYaml, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube.ExitCode()).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", "label-pod-test", "--format", "'{{ .ProcessLabel }}'"})
+ inspect.WaitWithDefaultTimeout()
+ label := inspect.OutputToString()
+
+ Expect(label).To(ContainSubstring("unconfined_u:system_r:spc_t:s0"))
+ })
+
It("podman play kube fail with nonexistent authfile", func() {
err := generateKubeYaml("pod", getPod(), kubeYaml)
Expect(err).To(BeNil())
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index 9c448a81e..e57712f62 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -38,7 +38,7 @@ var _ = Describe("Podman pod create", func() {
})
It("podman create pod", func() {
- _, ec, podID := podmanTest.CreatePod("")
+ _, ec, podID := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
check := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc"})
@@ -50,7 +50,7 @@ var _ = Describe("Podman pod create", func() {
It("podman create pod with name", func() {
name := "test"
- _, ec, _ := podmanTest.CreatePod(name)
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {name}})
Expect(ec).To(Equal(0))
check := podmanTest.Podman([]string{"pod", "ps", "--no-trunc"})
@@ -61,10 +61,10 @@ var _ = Describe("Podman pod create", func() {
It("podman create pod with doubled name", func() {
name := "test"
- _, ec, _ := podmanTest.CreatePod(name)
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {name}})
Expect(ec).To(Equal(0))
- _, ec2, _ := podmanTest.CreatePod(name)
+ _, ec2, _ := podmanTest.CreatePod(map[string][]string{"--name": {name}})
Expect(ec2).To(Not(Equal(0)))
check := podmanTest.Podman([]string{"pod", "ps", "-q"})
@@ -78,7 +78,7 @@ var _ = Describe("Podman pod create", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, _ := podmanTest.CreatePod(name)
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {name}})
Expect(ec).To(Not(Equal(0)))
check := podmanTest.Podman([]string{"pod", "ps", "-q"})
@@ -476,4 +476,29 @@ entrypoint ["/fromimage"]
Expect(status3.ExitCode()).To(Equal(0))
Expect(strings.Contains(status3.OutputToString(), "Degraded")).To(BeTrue())
})
+
+ It("podman create with unsupported network options", func() {
+ podCreate := podmanTest.Podman([]string{"pod", "create", "--network", "container:doesnotmatter"})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate.ExitCode()).To(Equal(125))
+ Expect(podCreate.ErrorToString()).To(ContainSubstring("pods presently do not support network mode container"))
+
+ podCreate = podmanTest.Podman([]string{"pod", "create", "--network", "ns:/does/not/matter"})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate.ExitCode()).To(Equal(125))
+ Expect(podCreate.ErrorToString()).To(ContainSubstring("pods presently do not support network mode path"))
+ })
+
+ It("podman pod create with --net=none", func() {
+ podName := "testPod"
+ podCreate := podmanTest.Podman([]string{"pod", "create", "--network", "none", "--name", podName})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"run", "--pod", podName, ALPINE, "ip", "-o", "-4", "addr"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("inet 127.0.0.1/8 scope host lo"))
+ Expect(len(session.OutputToStringArray())).To(Equal(1))
+ })
})
diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go
index fd9589afe..d9c4a393a 100644
--- a/test/e2e/pod_inspect_test.go
+++ b/test/e2e/pod_inspect_test.go
@@ -41,7 +41,7 @@ var _ = Describe("Podman pod inspect", func() {
})
It("podman inspect a pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
diff --git a/test/e2e/pod_kill_test.go b/test/e2e/pod_kill_test.go
index 710147893..06d244f99 100644
--- a/test/e2e/pod_kill_test.go
+++ b/test/e2e/pod_kill_test.go
@@ -40,7 +40,7 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill a pod by id", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -58,7 +58,7 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill a pod by id with TERM", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -72,7 +72,7 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill a pod by name", func() {
- _, ec, podid := podmanTest.CreatePod("test1")
+ _, ec, podid := podmanTest.CreatePod(map[string][]string{"--name": {"test1"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -86,7 +86,7 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill a pod by id with a bogus signal", func() {
- _, ec, podid := podmanTest.CreatePod("test1")
+ _, ec, podid := podmanTest.CreatePod(map[string][]string{"--name": {"test1"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -100,14 +100,14 @@ var _ = Describe("Podman pod kill", func() {
})
It("podman pod kill latest pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, podid2 := podmanTest.CreatePod("")
+ _, ec, podid2 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", podid2)
@@ -128,7 +128,7 @@ var _ = Describe("Podman pod kill", func() {
It("podman pod kill all", func() {
SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -139,7 +139,7 @@ var _ = Describe("Podman pod kill", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, podid2 := podmanTest.CreatePod("")
+ _, ec, podid2 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", podid2)
diff --git a/test/e2e/pod_pause_test.go b/test/e2e/pod_pause_test.go
index 3dabf7b4a..0c1b39f38 100644
--- a/test/e2e/pod_pause_test.go
+++ b/test/e2e/pod_pause_test.go
@@ -48,7 +48,7 @@ var _ = Describe("Podman pod pause", func() {
})
It("podman pod pause a created pod by id", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "pause", podid})
@@ -57,7 +57,7 @@ var _ = Describe("Podman pod pause", func() {
})
It("podman pod pause a running pod by id", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -78,7 +78,7 @@ var _ = Describe("Podman pod pause", func() {
})
It("podman unpause a running pod by id", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -93,7 +93,7 @@ var _ = Describe("Podman pod pause", func() {
})
It("podman pod pause a running pod by name", func() {
- _, ec, _ := podmanTest.CreatePod("test1")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"test1"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "test1")
diff --git a/test/e2e/pod_prune_test.go b/test/e2e/pod_prune_test.go
index 0346cfdc8..d1ebf7249 100644
--- a/test/e2e/pod_prune_test.go
+++ b/test/e2e/pod_prune_test.go
@@ -33,7 +33,7 @@ var _ = Describe("Podman pod prune", func() {
})
It("podman pod prune empty pod", func() {
- _, ec, _ := podmanTest.CreatePod("")
+ _, ec, _ := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "prune", "--force"})
@@ -42,7 +42,7 @@ var _ = Describe("Podman pod prune", func() {
})
It("podman pod prune doesn't remove a pod with a running container", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
ec2 := podmanTest.RunTopContainerInPod("", podid)
@@ -59,7 +59,7 @@ var _ = Describe("Podman pod prune", func() {
})
It("podman pod prune removes a pod with a stopped container", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
_, ec2, _ := podmanTest.RunLsContainerInPod("", podid)
diff --git a/test/e2e/pod_ps_test.go b/test/e2e/pod_ps_test.go
index 9f63c1d5d..c20cb44e7 100644
--- a/test/e2e/pod_ps_test.go
+++ b/test/e2e/pod_ps_test.go
@@ -43,7 +43,7 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps default", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -57,7 +57,7 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps quiet flag", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
_, ec, _ = podmanTest.RunLsContainerInPod("", podid)
@@ -71,7 +71,7 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps no-trunc", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
_, ec2, _ := podmanTest.RunLsContainerInPod("", podid)
@@ -86,10 +86,10 @@ var _ = Describe("Podman ps", func() {
It("podman pod ps latest", func() {
SkipIfRemote("--latest flag n/a")
- _, ec, podid1 := podmanTest.CreatePod("")
+ _, ec, podid1 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
- _, ec2, podid2 := podmanTest.CreatePod("")
+ _, ec2, podid2 := podmanTest.CreatePod(nil)
Expect(ec2).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--latest"})
@@ -100,7 +100,7 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps id filter flag", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "ps", "--filter", fmt.Sprintf("id=%s", podid)})
@@ -109,9 +109,9 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps filter name regexp", func() {
- _, ec, podid := podmanTest.CreatePod("mypod")
+ _, ec, podid := podmanTest.CreatePod(map[string][]string{"--name": {"mypod"}})
Expect(ec).To(Equal(0))
- _, ec2, _ := podmanTest.CreatePod("mypod1")
+ _, ec2, _ := podmanTest.CreatePod(map[string][]string{"--name": {"mypod1"}})
Expect(ec2).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "name=mypod"})
@@ -138,13 +138,13 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps --sort by name", func() {
- _, ec, _ := podmanTest.CreatePod("")
+ _, ec, _ := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
- _, ec2, _ := podmanTest.CreatePod("")
+ _, ec2, _ := podmanTest.CreatePod(nil)
Expect(ec2).To(Equal(0))
- _, ec3, _ := podmanTest.CreatePod("")
+ _, ec3, _ := podmanTest.CreatePod(nil)
Expect(ec3).To(Equal(0))
session := podmanTest.Podman([]string{"pod", "ps", "--sort=name", "--format", "{{.Name}}"})
@@ -159,7 +159,7 @@ var _ = Describe("Podman ps", func() {
It("podman pod ps --ctr-names", func() {
SkipIfRootlessCgroupsV1("Not supported for rootless + CGroupsV1")
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", podid)
@@ -177,14 +177,14 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps filter ctr attributes", func() {
- _, ec, podid1 := podmanTest.CreatePod("")
+ _, ec, podid1 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", podid1)
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec2, podid2 := podmanTest.CreatePod("")
+ _, ec2, podid2 := podmanTest.CreatePod(nil)
Expect(ec2).To(Equal(0))
_, ec3, cid := podmanTest.RunLsContainerInPod("test2", podid2)
@@ -214,7 +214,7 @@ var _ = Describe("Podman ps", func() {
Expect(session.OutputToString()).To(ContainSubstring(podid2))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid1)))
- _, ec3, podid3 := podmanTest.CreatePod("")
+ _, ec3, podid3 := podmanTest.CreatePod(nil)
Expect(ec3).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "ps", "-q", "--no-trunc", "--filter", "ctr-number=1"})
@@ -259,23 +259,20 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps filter labels", func() {
- _, ec, podid1 := podmanTest.CreatePod("")
- Expect(ec).To(Equal(0))
+ s, _, podid1 := podmanTest.CreatePod(nil)
+ Expect(s).To(Exit(0))
- _, ec, podid2 := podmanTest.CreatePodWithLabels("", map[string]string{
- "app": "myapp",
- "io.podman.test.key": "irrelevant-value",
+ s, _, podid2 := podmanTest.CreatePod(map[string][]string{
+ "--label": {"app=myapp", "io.podman.test.key=irrelevant-value"},
})
- Expect(ec).To(Equal(0))
+ Expect(s).To(Exit(0))
- _, ec, podid3 := podmanTest.CreatePodWithLabels("", map[string]string{
- "app": "test",
- })
- Expect(ec).To(Equal(0))
+ s, _, podid3 := podmanTest.CreatePod(map[string][]string{"--label": {"app=test"}})
+ Expect(s).To(Exit(0))
session := podmanTest.Podman([]string{"pod", "ps", "--no-trunc", "--filter", "label=app", "--filter", "label=app=myapp"})
session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
+ Expect(session).To(Exit(0))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid1)))
Expect(session.OutputToString()).To(ContainSubstring(podid2))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid3)))
@@ -359,13 +356,13 @@ var _ = Describe("Podman ps", func() {
})
It("podman pod ps format with labels", func() {
- _, ec, _ := podmanTest.CreatePod("")
+ _, ec, _ := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
- _, ec1, _ := podmanTest.CreatePodWithLabels("", map[string]string{
- "io.podman.test.label": "value1",
- "io.podman.test.key": "irrelevant-value",
- })
+ _, ec1, _ := podmanTest.CreatePod(map[string][]string{"--label": {
+ "io.podman.test.label=value1",
+ "io.podman.test.key=irrelevant-value",
+ }})
Expect(ec1).To(Equal(0))
session := podmanTest.Podman([]string{"pod", "ps", "--format", "{{.Labels}}"})
diff --git a/test/e2e/pod_restart_test.go b/test/e2e/pod_restart_test.go
index b358c2c7a..c6b1a0d46 100644
--- a/test/e2e/pod_restart_test.go
+++ b/test/e2e/pod_restart_test.go
@@ -39,7 +39,7 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart single empty pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"pod", "restart", podid})
@@ -48,7 +48,7 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart single pod by name", func() {
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", "foobar99")
@@ -68,14 +68,14 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart multiple pods", func() {
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, _ = podmanTest.CreatePod("foobar100")
+ _, ec, _ = podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("test2", "foobar100")
@@ -106,14 +106,14 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart all pods", func() {
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, _ = podmanTest.CreatePod("foobar100")
+ _, ec, _ = podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("test2", "foobar100")
@@ -134,14 +134,14 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart latest pod", func() {
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, _ = podmanTest.CreatePod("foobar100")
+ _, ec, _ = podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("test2", "foobar100")
@@ -166,7 +166,7 @@ var _ = Describe("Podman pod restart", func() {
})
It("podman pod restart multiple pods with bogus", func() {
- _, ec, podid1 := podmanTest.CreatePod("foobar99")
+ _, ec, podid1 := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go
index 24e945d5a..40a903cd0 100644
--- a/test/e2e/pod_rm_test.go
+++ b/test/e2e/pod_rm_test.go
@@ -37,7 +37,7 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm empty pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"pod", "rm", podid})
@@ -61,10 +61,10 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm latest pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
- _, ec2, podid2 := podmanTest.CreatePod("pod2")
+ _, ec2, podid2 := podmanTest.CreatePod(map[string][]string{"--name": {"pod2"}})
Expect(ec2).To(Equal(0))
latest := "--latest"
@@ -83,7 +83,7 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm removes a pod with a container", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
_, ec2, _ := podmanTest.RunLsContainerInPod("", podid)
@@ -99,7 +99,7 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm -f does remove a running container", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -117,10 +117,10 @@ var _ = Describe("Podman pod rm", func() {
It("podman pod rm -a doesn't remove a running container", func() {
fmt.Printf("To start, there are %d pods\n", podmanTest.NumberOfPods())
- _, ec, podid1 := podmanTest.CreatePod("")
+ _, ec, podid1 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
- _, ec, _ = podmanTest.CreatePod("")
+ _, ec, _ = podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
fmt.Printf("Started %d pods\n", podmanTest.NumberOfPods())
@@ -154,13 +154,13 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman pod rm -fa removes everything", func() {
- _, ec, podid1 := podmanTest.CreatePod("")
+ _, ec, podid1 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
- _, ec, podid2 := podmanTest.CreatePod("")
+ _, ec, podid2 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
- _, ec, _ = podmanTest.CreatePod("")
+ _, ec, _ = podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid1)
@@ -199,7 +199,7 @@ var _ = Describe("Podman pod rm", func() {
})
It("podman rm bogus pod and a running pod", func() {
- _, ec, podid1 := podmanTest.CreatePod("")
+ _, ec, podid1 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", podid1)
@@ -217,7 +217,7 @@ var _ = Describe("Podman pod rm", func() {
It("podman rm --ignore bogus pod and a running pod", func() {
- _, ec, podid1 := podmanTest.CreatePod("")
+ _, ec, podid1 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", podid1)
diff --git a/test/e2e/pod_start_test.go b/test/e2e/pod_start_test.go
index 63a915548..e14796ab3 100644
--- a/test/e2e/pod_start_test.go
+++ b/test/e2e/pod_start_test.go
@@ -10,6 +10,7 @@ import (
. "github.com/containers/podman/v2/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gexec"
)
var _ = Describe("Podman pod start", func() {
@@ -43,7 +44,7 @@ var _ = Describe("Podman pod start", func() {
})
It("podman pod start single empty pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"pod", "start", podid})
@@ -52,7 +53,7 @@ var _ = Describe("Podman pod start", func() {
})
It("podman pod start single pod by name", func() {
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "ls"})
@@ -65,14 +66,14 @@ var _ = Describe("Podman pod start", func() {
})
It("podman pod start multiple pods", func() {
- _, ec, podid1 := podmanTest.CreatePod("foobar99")
+ _, ec, podid1 := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec2, podid2 := podmanTest.CreatePod("foobar100")
+ _, ec2, podid2 := podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec2).To(Equal(0))
session = podmanTest.Podman([]string{"create", "--pod", "foobar100", ALPINE, "top"})
@@ -85,15 +86,45 @@ var _ = Describe("Podman pod start", func() {
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
})
+ It("multiple pods in conflict", func() {
+ podName := []string{"Pod_" + RandomString(10), "Pod_" + RandomString(10)}
+
+ pod, _, podid1 := podmanTest.CreatePod(map[string][]string{
+ "--infra": {"true"},
+ "--name": {podName[0]},
+ "--publish": {"127.0.0.1:8080:80"},
+ })
+ Expect(pod).To(Exit(0))
+
+ session := podmanTest.Podman([]string{"create", "--pod", podName[0], ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+
+ pod, _, podid2 := podmanTest.CreatePod(map[string][]string{
+ "--infra": {"true"},
+ "--name": {podName[1]},
+ "--publish": {"127.0.0.1:8080:80"},
+ })
+ Expect(pod).To(Exit(0))
+
+ session = podmanTest.Podman([]string{"create", "--pod", podName[1], ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+
+ session = podmanTest.Podman([]string{"pod", "start", podid1, podid2})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(125))
+ })
+
It("podman pod start all pods", func() {
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, _ = podmanTest.CreatePod("foobar100")
+ _, ec, _ = podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec).To(Equal(0))
session = podmanTest.Podman([]string{"create", "--pod", "foobar100", ALPINE, "top"})
@@ -107,14 +138,14 @@ var _ = Describe("Podman pod start", func() {
})
It("podman pod start latest pod", func() {
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, _ = podmanTest.CreatePod("foobar100")
+ _, ec, _ = podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec).To(Equal(0))
session = podmanTest.Podman([]string{"create", "--pod", "foobar100", ALPINE, "top"})
@@ -132,7 +163,7 @@ var _ = Describe("Podman pod start", func() {
})
It("podman pod start multiple pods with bogus", func() {
- _, ec, podid := podmanTest.CreatePod("foobar99")
+ _, ec, podid := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"create", "--pod", "foobar99", ALPINE, "top"})
diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go
index 1709b4f81..073d4752b 100644
--- a/test/e2e/pod_stats_test.go
+++ b/test/e2e/pod_stats_test.go
@@ -50,7 +50,7 @@ var _ = Describe("Podman pod stats", func() {
})
It("podman stats on a specific running pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -67,7 +67,7 @@ var _ = Describe("Podman pod stats", func() {
})
It("podman stats on a specific running pod with shortID", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -84,7 +84,7 @@ var _ = Describe("Podman pod stats", func() {
})
It("podman stats on a specific running pod with name", func() {
- _, ec, podid := podmanTest.CreatePod("test")
+ _, ec, podid := podmanTest.CreatePod(map[string][]string{"--name": {"test"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -101,7 +101,7 @@ var _ = Describe("Podman pod stats", func() {
})
It("podman stats on running pods", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -118,7 +118,7 @@ var _ = Describe("Podman pod stats", func() {
})
It("podman stats on all pods", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -135,7 +135,7 @@ var _ = Describe("Podman pod stats", func() {
})
It("podman stats with json output", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -152,7 +152,7 @@ var _ = Describe("Podman pod stats", func() {
Expect(stats.IsJSONOutputValid()).To(BeTrue())
})
It("podman stats with GO template", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -164,7 +164,7 @@ var _ = Describe("Podman pod stats", func() {
})
It("podman stats with invalid GO template", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
diff --git a/test/e2e/pod_stop_test.go b/test/e2e/pod_stop_test.go
index 4eb897786..30a5632d0 100644
--- a/test/e2e/pod_stop_test.go
+++ b/test/e2e/pod_stop_test.go
@@ -47,7 +47,7 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman stop bogus pod and a running pod", func() {
- _, ec, podid1 := podmanTest.CreatePod("")
+ _, ec, podid1 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", podid1)
@@ -61,7 +61,7 @@ var _ = Describe("Podman pod stop", func() {
It("podman stop --ignore bogus pod and a running pod", func() {
- _, ec, podid1 := podmanTest.CreatePod("")
+ _, ec, podid1 := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("test1", podid1)
@@ -78,7 +78,7 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop single empty pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"pod", "stop", podid})
@@ -87,7 +87,7 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop single pod by name", func() {
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
@@ -101,14 +101,14 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop multiple pods", func() {
- _, ec, podid1 := podmanTest.CreatePod("foobar99")
+ _, ec, podid1 := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec2, podid2 := podmanTest.CreatePod("foobar100")
+ _, ec2, podid2 := podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec2).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", "foobar100")
@@ -122,14 +122,14 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop all pods", func() {
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, _ = podmanTest.CreatePod("foobar100")
+ _, ec, _ = podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", "foobar100")
@@ -143,14 +143,14 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop latest pod", func() {
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- _, ec, _ = podmanTest.CreatePod("foobar100")
+ _, ec, _ = podmanTest.CreatePod(map[string][]string{"--name": {"foobar100"}})
Expect(ec).To(Equal(0))
session = podmanTest.RunTopContainerInPod("", "foobar100")
@@ -168,7 +168,7 @@ var _ = Describe("Podman pod stop", func() {
})
It("podman pod stop multiple pods with bogus", func() {
- _, ec, podid1 := podmanTest.CreatePod("foobar99")
+ _, ec, podid1 := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", "foobar99")
diff --git a/test/e2e/pod_top_test.go b/test/e2e/pod_top_test.go
index 9e3570360..e191b44fc 100644
--- a/test/e2e/pod_top_test.go
+++ b/test/e2e/pod_top_test.go
@@ -47,7 +47,7 @@ var _ = Describe("Podman top", func() {
})
It("podman pod top on non-running pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"top", podid})
@@ -56,7 +56,7 @@ var _ = Describe("Podman top", func() {
})
It("podman pod top on pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"run", "-d", "--pod", podid, ALPINE, "top", "-d", "2"})
@@ -73,7 +73,7 @@ var _ = Describe("Podman top", func() {
})
It("podman pod top with options", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"run", "-d", "--pod", podid, ALPINE, "top", "-d", "2"})
@@ -87,7 +87,7 @@ var _ = Describe("Podman top", func() {
})
It("podman pod top on pod invalid options", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"run", "-d", "--pod", podid, ALPINE, "top", "-d", "2"})
@@ -104,7 +104,7 @@ var _ = Describe("Podman top", func() {
})
It("podman pod top on pod with containers in same pid namespace", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"run", "-d", "--pod", podid, ALPINE, "top", "-d", "2"})
@@ -123,7 +123,7 @@ var _ = Describe("Podman top", func() {
})
It("podman pod top on pod with containers in different namespace", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.Podman([]string{"run", "-d", "--pod", podid, ALPINE, "top", "-d", "2"})
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 13701fc3b..1b3dca7b7 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -389,7 +389,7 @@ var _ = Describe("Podman ps", func() {
})
It("podman --pod", func() {
- _, ec, podid := podmanTest.CreatePod("")
+ _, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podid)
@@ -406,7 +406,7 @@ var _ = Describe("Podman ps", func() {
It("podman --pod with a non-empty pod name", func() {
podName := "testPodName"
- _, ec, podid := podmanTest.CreatePod(podName)
+ _, ec, podid := podmanTest.CreatePod(map[string][]string{"--name": {podName}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("", podName)
diff --git a/test/e2e/restart_test.go b/test/e2e/restart_test.go
index 584ccd22b..76362dcbf 100644
--- a/test/e2e/restart_test.go
+++ b/test/e2e/restart_test.go
@@ -197,10 +197,10 @@ var _ = Describe("Podman restart", func() {
Expect(restartTime.OutputToStringArray()[1]).To(Not(Equal(startTime.OutputToStringArray()[1])))
})
- It("Podman restart a container in a pod and hosts shouln't duplicated", func() {
+ It("Podman restart a container in a pod and hosts should not duplicated", func() {
// Fixes: https://github.com/containers/podman/issues/8921
- _, ec, _ := podmanTest.CreatePod("foobar99")
+ _, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"foobar99"}})
Expect(ec).To(Equal(0))
session := podmanTest.RunTopContainerInPod("host-restart-test", "foobar99")
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index ebea2132a..676f24e5d 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -376,6 +376,13 @@ var _ = Describe("Podman run networking", func() {
Expect(session.ExitCode()).To(Equal(0))
})
+ It("podman run slirp4netns network with mtu", func() {
+ session := podmanTest.Podman([]string{"run", "--network", "slirp4netns:mtu=9000", ALPINE, "ip", "addr"})
+ session.Wait(30)
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring("mtu 9000"))
+ })
+
It("podman run slirp4netns network with different cidr", func() {
slirp4netnsHelp := SystemExec("slirp4netns", []string{"--help"})
Expect(slirp4netnsHelp.ExitCode()).To(Equal(0))
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 7c74cea78..bc89b59de 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -110,7 +110,7 @@ var _ = Describe("Podman run with volumes", func() {
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(ContainSubstring(dest + " ro"))
- session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",shared", ALPINE, "grep", dest, "/proc/self/mountinfo"})
+ session = podmanTest.Podman([]string{"run", "--rm", "--mount", mount + ",consistency=delegated,shared", ALPINE, "grep", dest, "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
found, matches := session.GrepString(dest)
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index dcf1da370..98e34238e 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -608,6 +608,19 @@ json-file | f
# a subdir of a volume.
run_podman run --rm --workdir /IamNotOntheImage -v $testdir/content:/IamNotOntheImage/foo $IMAGE cat foo
is "$output" "$randomcontent" "cat random content"
+
+ # Make sure that running on a read-only rootfs works (#9230).
+ if ! is_rootless && ! is_remote; then
+ # image mount is hard to test as a rootless user
+ # and does not work remotely
+ run_podman image mount $IMAGE
+ romount="$output"
+
+ run_podman run --rm --rootfs $romount echo "Hello world"
+ is "$output" "Hello world"
+
+ run_podman image unmount $IMAGE
+ fi
}
# vim: filetype=sh
diff --git a/test/utils/utils.go b/test/utils/utils.go
index f21584537..6790f31cd 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -467,11 +467,14 @@ func Containerized() bool {
return false
}
+func init() {
+ rand.Seed(GinkgoRandomSeed())
+}
+
var randomLetters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
// RandomString returns a string of given length composed of random characters
func RandomString(n int) string {
- rand.Seed(GinkgoRandomSeed())
b := make([]rune, n)
for i := range b {