summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/apiv2/10-images.at30
-rw-r--r--test/apiv2/12-imagesMore.at10
-rw-r--r--test/apiv2/20-containers.at19
-rw-r--r--test/apiv2/23-containersArchive.at3
-rw-r--r--test/apiv2/26-containersWait.at39
-rw-r--r--test/apiv2/40-pods.at16
-rw-r--r--test/apiv2/70-short-names.at16
-rw-r--r--test/apiv2/README.md12
-rw-r--r--test/apiv2/python/rest_api/test_v2_0_0_container.py2
-rwxr-xr-xtest/apiv2/test-apiv243
-rwxr-xr-xtest/buildah-bud/apply-podman-deltas4
-rw-r--r--test/buildah-bud/buildah-tests.diff18
-rw-r--r--test/e2e/build/Containerfile.userns-auto2
-rw-r--r--test/e2e/common_test.go2
-rw-r--r--test/e2e/events_test.go16
-rw-r--r--test/e2e/generate_kube_test.go51
-rw-r--r--test/e2e/generate_systemd_test.go71
-rw-r--r--test/e2e/network_connect_disconnect_test.go12
-rw-r--r--test/e2e/play_kube_test.go88
-rw-r--r--test/e2e/pod_inspect_test.go17
-rw-r--r--test/e2e/restart_test.go2
-rw-r--r--test/e2e/run_cpu_test.go16
-rw-r--r--test/e2e/run_staticip_test.go7
-rw-r--r--test/e2e/run_test.go14
-rw-r--r--test/e2e/run_userns_test.go40
-rw-r--r--test/e2e/save_test.go3
-rw-r--r--test/e2e/secret_test.go16
-rw-r--r--test/e2e/update_test.go200
-rw-r--r--test/system/001-basic.bats8
-rw-r--r--test/system/090-events.bats24
-rw-r--r--test/system/150-login.bats2
-rw-r--r--test/system/220-healthcheck.bats96
-rw-r--r--test/system/250-systemd.bats91
-rw-r--r--test/system/255-auto-update.bats103
-rw-r--r--test/system/280-update.bats130
-rw-r--r--test/system/500-networking.bats4
-rw-r--r--test/system/710-kube.bats11
-rw-r--r--test/system/helpers.bash54
-rw-r--r--test/system/helpers.systemd.bash14
39 files changed, 1111 insertions, 195 deletions
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index 4fd954e37..3ffc6f738 100644
--- a/test/apiv2/10-images.at
+++ b/test/apiv2/10-images.at
@@ -227,16 +227,36 @@ t GET libpod/images/quay.io/libpod/busybox:latest/exists 204
CONTAINERFILE_WITH_ERR_TAR="${TMPD}/containerfile.tar"
cat > $TMPD/containerfile << EOF
-FROM quay.io/fedora/fedora
+FROM $IMAGE
RUN echo 'some error' >&2
EOF
tar --format=posix -C $TMPD -cvf ${CONTAINERFILE_WITH_ERR_TAR} containerfile &> /dev/null
-t POST "build?q=1&dockerfile=containerfile" $CONTAINERFILE_WITH_ERR_TAR 200
-response_output=$(cat "$WORKDIR/curl.result.out")
-if [[ ${response_output} == *"some error"* ]];then
- _show_ok 0 "compat quiet build" "~ $response_output" "found output from stderr in API"
+t POST "/build?q=1&dockerfile=containerfile" $CONTAINERFILE_WITH_ERR_TAR 200
+if [[ $output == *"some error"* ]];then
+ _show_ok 0 "compat quiet build" "[should not contain 'some error']" "$output"
+else
+ _show_ok 1 "compat quiet build"
fi
cleanBuildTest
+# compat API vs libpod API event differences:
+# on image removal, libpod produces 'remove' events.
+# compat produces 'delete' events.
+podman image build -t test:test -<<EOF
+from $IMAGE
+EOF
+
+START=$(date +%s)
+
+t DELETE libpod/images/test:test 200
+# HACK HACK HACK There is a race around events being added to the journal
+# This sleep seems to avoid the race.
+# If it fails and begins to flake, investigate a retry loop.
+sleep 1
+t GET "libpod/events?stream=false&since=$START" 200 \
+ 'select(.status | contains("remove")).Action=remove'
+t GET "events?stream=false&since=$START" 200 \
+ 'select(.status | contains("delete")).Action=delete'
+
# vim: filetype=sh
diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at
index be56152f1..eb58b8377 100644
--- a/test/apiv2/12-imagesMore.at
+++ b/test/apiv2/12-imagesMore.at
@@ -3,9 +3,6 @@
# Tests for more image-related endpoints
#
-red='\e[31m'
-nc='\e[0m'
-
start_registry
podman pull -q $IMAGE
@@ -63,7 +60,9 @@ podman pull -q $IMAGE
# test podman image SCP
# ssh needs to work so we can validate that the failure is past argument parsing
-podman system connection add --default test ssh://$USER@localhost/run/user/$MYUID/podman/podman.sock
+conn=apiv2test-temp-connection
+podman system connection add --default $conn \
+ ssh://$USER@localhost/run/user/$UID/podman/podman.sock
# should fail but need to check the output...
# status 125 here means that the save/load fails due to
# cirrus weirdness with exec.Command. All of the args have been parsed successfully.
@@ -72,4 +71,7 @@ t POST "libpod/images/scp/$IMAGE?destination=QA::" 500 \
t DELETE libpod/images/$IMAGE 200 \
.ExitCode=0
+# Clean up
+podman system connection rm $conn
+
stop_registry
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index 655462f16..9ace46b8b 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -309,7 +309,9 @@ t POST containers/create Image=${MultiTagName} 201 \
.Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
- .Image=${MultiTagName}
+ .Config.Image=${MultiTagName} \
+ .Image~sha256:[0-9a-f]\\{64\\}
+
t DELETE containers/$cid 204
t DELETE images/${MultiTagName} 200
# vim: filetype=sh
@@ -545,6 +547,21 @@ t GET libpod/containers/$cname/json 200 \
.ImageName=$IMAGE \
.Name=$cname
+if root; then
+ podman run -dt --name=updateCtr alpine
+ echo '{"Memory":{"Limit":500000}, "CPU":{"Shares":123}}' >${TMPD}/update.json
+ t POST libpod/containers/updateCtr/update ${TMPD}/update.json 201
+
+ # Verify
+ echo '{ "AttachStdout":true,"Cmd":["cat","/sys/fs/cgroup/cpu.weight"]}' >${TMPD}/exec.json
+ t POST containers/updateCtr/exec ${TMPD}/exec.json 201 .Id~[0-9a-f]\\{64\\}
+ eid=$(jq -r '.Id' <<<"$output")
+ # 002 is the byte length
+ t POST exec/$eid/start 200 $'\001\0025'
+
+ podman rm -f updateCtr
+fi
+
rm -rf $TMPD
podman container rm -fa
diff --git a/test/apiv2/23-containersArchive.at b/test/apiv2/23-containersArchive.at
index 3ff4465b9..c1b936e3a 100644
--- a/test/apiv2/23-containersArchive.at
+++ b/test/apiv2/23-containersArchive.at
@@ -3,9 +3,6 @@
# test more container-related endpoints
#
-red='\e[31m'
-nc='\e[0m'
-
podman pull $IMAGE &>/dev/null
# Ensure clean slate
diff --git a/test/apiv2/26-containersWait.at b/test/apiv2/26-containersWait.at
index 55bcd4592..41938d567 100644
--- a/test/apiv2/26-containersWait.at
+++ b/test/apiv2/26-containersWait.at
@@ -3,9 +3,6 @@
# test more container-related endpoints
#
-red='\e[31m'
-nc='\e[0m'
-
podman pull "${IMAGE}" &>/dev/null
# Ensure clean slate
@@ -21,29 +18,29 @@ t POST "containers/${CTR}/wait?condition=non-existent-cond" 400
t POST "containers/${CTR}/wait?condition=not-running" 200
+# Test waiting for EXIT (need to start a background trigger first)
+(sleep 2;podman start "${CTR}") &
+child_pid=$!
+
+# This will block until the background job completes
t POST "containers/${CTR}/wait?condition=next-exit" 200 \
.StatusCode=0 \
- .Error=null &
-child_pid=$!
-podman start "${CTR}"
+ .Error=null
wait "${child_pid}"
-
-# check if headers are sent in advance before body
-WAIT_TEST_ERROR=""
-curl -I -X POST "http://$HOST:$PORT/containers/${CTR}/wait?condition=next-exit" &> "/dev/null" &
-child_pid=$!
-sleep 0.5
-if kill -2 "${child_pid}" 2> "/dev/null"; then
- echo -e "${red}NOK: Failed to get response headers immediately.${nc}" 1>&2;
- WAIT_TEST_ERROR="1"
+# Test that headers are sent before body. (We should actually never get a body)
+APIV2_TEST_EXPECT_TIMEOUT=2 t POST "containers/${CTR}/wait?condition=next-exit" 999
+like "$(<$WORKDIR/curl.headers.out)" ".*HTTP.* 200 OK.*" \
+ "Received headers from /wait"
+if [[ -e $WORKDIR/curl.result.out ]]; then
+ _show_ok 0 "UNEXPECTED: curl on /wait returned results"
fi
-t POST "containers/${CTR}/wait?condition=removed" 200 &
+# Test waiting for REMOVE. Like above, start a background trigger.
+(sleep 2;podman container rm "${CTR}") &
child_pid=$!
-podman container rm "${CTR}"
-wait "${child_pid}"
-if [[ "${WAIT_TEST_ERROR}" ]] ; then
- exit 1;
-fi
+t POST "containers/${CTR}/wait?condition=removed" 200 \
+ .StatusCode=0 \
+ .Error=null
+wait "${child_pid}"
diff --git a/test/apiv2/40-pods.at b/test/apiv2/40-pods.at
index d21b3d1a9..0e0f1cb18 100644
--- a/test/apiv2/40-pods.at
+++ b/test/apiv2/40-pods.at
@@ -134,23 +134,17 @@ t GET libpod/pods/json?filters='{"label":["testl' 400 \
t DELETE libpod/pods/foo 200
t DELETE "libpod/pods/foo (pod has already been deleted)" 404
-t_timeout 5 GET "libpod/pods/stats?stream=true&delay=1" 200
+# Expect this to time out
+APIV2_TEST_EXPECT_TIMEOUT=5 t GET "libpod/pods/stats?stream=true&delay=1" 999
podman pod create --name=specgen
TMPD=$(mktemp -d podman-apiv2-test.build.XXXXXXXX)
-podman generate spec -f ${TMPD}/input.txt -c specgen
+podman generate spec -f ${TMPD}/myspec.json -c specgen
-curl -XPOST -o ${TMPD}/response.txt --dump-header ${TMPD}/headers.txt -H content-type:application/json http://$HOST:$PORT/v4.0.0/libpod/pods/create -d "@${TMPD}/input.txt"
-
-if ! grep -q '201 Created' "${TMPD}/headers.txt"; then
- cat "${TMPD}/headers.txt"
- cat "${TMPD}/response.txt"
- echo -e "${red}NOK: pod create failed"
- rm -rf $TMPD
- exit 1
-fi
+t POST libpod/pods/create ${TMPD}/myspec.json 201 \
+ .Id~[0-9a-f]\\{64\\}
rm -rf $TMPD
diff --git a/test/apiv2/70-short-names.at b/test/apiv2/70-short-names.at
index bd7f8e7bd..952dd2ad1 100644
--- a/test/apiv2/70-short-names.at
+++ b/test/apiv2/70-short-names.at
@@ -9,7 +9,7 @@ t POST "images/create?fromImage=quay.io/libpod/alpine:latest" 200 .error~null .s
# 14291 - let a short-name resolve to a *local* non Docker-Hub image.
t POST containers/create Image=alpine 201 .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
-t GET containers/$cid/json 200 .Image="quay.io/libpod/alpine:latest"
+t GET containers/$cid/json 200 .Config.Image="quay.io/libpod/alpine:latest" .Image~sha256:[0-9a-f]\\{64\\}
podman rm -f $cid
########## TAG
@@ -33,18 +33,8 @@ RUN touch /foo
EOF
tar --format=posix -C $TMPD -cvf ${CONTAINERFILE_TAR} containerfile &> /dev/null
- curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \
- -H "content-type: application/x-tar" \
- --dump-header "${TMPD}/headers.txt" \
- -o "${TMPD}/response.txt" \
- "http://$HOST:$PORT/build?dockerfile=containerfile&t=$tag" &> /dev/null
-
- if ! grep -q '200 OK' "${TMPD}/headers.txt"; then
- cat "${TMPD}/headers.txt"
- cat "${TMPD}/response.txt"
- echo -e "${red}NOK: Image build from tar failed response was not 200 OK (application/x-tar)"
- exit 1
- fi
+ t POST "/build?dockerfile=containerfile&t=$tag" $CONTAINERFILE_TAR 200 \
+ .stream~".*Successfully tagged .*"
rm -rf $TMPD
t DELETE "images/$fqn" 200
diff --git a/test/apiv2/README.md b/test/apiv2/README.md
index 63d1f5b13..712124d1b 100644
--- a/test/apiv2/README.md
+++ b/test/apiv2/README.md
@@ -46,6 +46,9 @@ with POST parameters if present, and compares return status and
| +----------- POST params
+--------------------------------- note the missing slash
+Never, ever, ever, seriously _EVER_ `exit` from a test. Just don't.
+That skips cleanup, and leaves the system in a broken state.
+
Notes:
* If the endpoint has a leading slash (`/_ping`), `t` leaves it unchanged.
@@ -61,14 +64,19 @@ of POST parameters in the form 'key=value', separated by spaces:
`t` will convert the param list to JSON form for passing to the server.
A numeric status code terminates processing of POST parameters.
** As a special case, when one POST argument is a string ending in `.tar`,
-`t` will invoke `curl` with `--data-binary @PATH` and
-set `Content-type: application/x-tar`. This is useful for `build` endpoints.
+`.yaml`, or `.json`, `t` will invoke `curl` with `--data-binary @PATH` and
+set `Content-type` as appropriate. This is useful for `build` endpoints.
(To override `Content-type`, simply pass along an extra string argument
matching `application/*`):
t POST myentrypoint /mytmpdir/myfile.tar application/foo 400
+** Like above, when using PUT, `t` does `--upload-time` instead of
+`--data-binary`
* The final arguments are one or more expected string results. If an
argument starts with a dot, `t` will invoke `jq` on the output to
fetch that field, and will compare it to the right-hand side of
the argument. If the separator is `=` (equals), `t` will require
an exact match; if `~` (tilde), `t` will use `expr` to compare.
+
+* If your test expects `curl` to time out:
+ APIV2_TEST_EXPECT_TIMEOUT=5 t POST /foo 999
diff --git a/test/apiv2/python/rest_api/test_v2_0_0_container.py b/test/apiv2/python/rest_api/test_v2_0_0_container.py
index a6cd93a1a..25596a9b7 100644
--- a/test/apiv2/python/rest_api/test_v2_0_0_container.py
+++ b/test/apiv2/python/rest_api/test_v2_0_0_container.py
@@ -359,8 +359,6 @@ class ContainerTestCase(APITestCase):
self.assertEqual(2000, out["HostConfig"]["MemorySwap"])
self.assertEqual(1000, out["HostConfig"]["Memory"])
-
-
def execute_process(cmd):
return subprocess.run(
cmd,
diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2
index 0eb2d1b30..aca7db0dd 100755
--- a/test/apiv2/test-apiv2
+++ b/test/apiv2/test-apiv2
@@ -23,8 +23,6 @@ REGISTRY_IMAGE="${PODMAN_TEST_IMAGE_REGISTRY}/${PODMAN_TEST_IMAGE_USER}/registry
###############################################################################
# BEGIN setup
-USER=$PODMAN_ROOTLESS_USER
-MYUID=$PODMAN_ROOTLESS_UID
TMPDIR=${TMPDIR:-/tmp}
WORKDIR=$(mktemp --tmpdir -d $ME.tmp.XXXXXX)
@@ -56,9 +54,6 @@ fi
# Path to podman binary
PODMAN_BIN=${PODMAN:-${CONTAINERS_HELPER_BINARY_DIR}/podman}
-# Timeout for streamed responses
-CURL_TIMEOUT=0
-
# Cleanup handlers
clean_up_server() {
if [ -n "$service_pid" ]; then
@@ -221,21 +216,6 @@ function jsonify() {
}
#######
-# t_timeout # Timeout wrapper for test helper
-#######
-function t_timeout() {
- CURL_TIMEOUT=$1; shift
- local min_runtime=$((CURL_TIMEOUT - 1))
- start=`date +%s`
- t $@
- local end=`date +%s`
- local runtime=$((end-start))
- if ! [[ "$runtime" -ge "$min_runtime" ]]; then
- die "Error: Streaming time should be greater or equal to '$min_runtime'"
- fi
-}
-
-#######
# t # Main test helper
#######
function t() {
@@ -246,11 +226,6 @@ function t() {
local testname="$method $path"
- if [[ $CURL_TIMEOUT != 0 ]]; then
- local c_timeout=$CURL_TIMEOUT
- curl_args+=("-m $CURL_TIMEOUT")
- CURL_TIMEOUT=0 # 'consume' timeout
- fi
# POST and PUT requests may be followed by one or more key=value pairs.
# Slurp the command line until we see a 3-digit status code.
if [[ $method = "POST" || $method == "PUT" || $method = "DELETE" ]]; then
@@ -312,6 +287,11 @@ function t() {
curl_args+=("--head")
fi
+ # If this is set, we're *expecting* curl to time out
+ if [[ -n "$APIV2_TEST_EXPECT_TIMEOUT" ]]; then
+ curl_args+=("-m" $APIV2_TEST_EXPECT_TIMEOUT)
+ fi
+
local expected_code=$1; shift
# Log every action we do
@@ -327,8 +307,19 @@ function t() {
--write-out '%{http_code}^%{content_type}^%{time_total}' \
-o $WORKDIR/curl.result.out "$url"); rc=$?; } || :
+ # Special case: this means we *expect and want* a timeout
+ if [[ -n "$APIV2_TEST_EXPECT_TIMEOUT" ]]; then
+ # Hardcoded. See curl(1) for list of exit codes
+ if [[ $rc -eq 28 ]]; then
+ _show_ok 1 "$testname: curl timed out (expected)"
+ else
+ _show_ok 0 "$testname: expected curl to time out; it did not"
+ fi
+ return
+ fi
+
# Any error from curl is instant bad news, from which we can't recover
- if [[ $rc -ne 0 ]] && [[ $c_timeout -eq 0 ]]; then
+ if [[ $rc -ne 0 ]]; then
die "curl failure ($rc) on $url - cannot continue"
fi
diff --git a/test/buildah-bud/apply-podman-deltas b/test/buildah-bud/apply-podman-deltas
index 8ce58b06d..999f36bf9 100755
--- a/test/buildah-bud/apply-podman-deltas
+++ b/test/buildah-bud/apply-podman-deltas
@@ -235,6 +235,10 @@ skip_if_remote "envariables do not automatically work with -remote." \
skip_if_remote "FIXME FIXME FIXME: does this test make sense in remote?" \
"build-test with OCI prestart hook"
+# 2022-08-17 buildah PR 4190
+skip_if_remote "Explicit request in buildah PR 4190 to skip this on remote" \
+ "build: test race in updating image name while performing parallel commits"
+
###############################################################################
# BEGIN tests which are skipped due to actual podman or podman-remote bugs.
diff --git a/test/buildah-bud/buildah-tests.diff b/test/buildah-bud/buildah-tests.diff
index 399042240..bf119421e 100644
--- a/test/buildah-bud/buildah-tests.diff
+++ b/test/buildah-bud/buildah-tests.diff
@@ -1,4 +1,4 @@
-From 6508e3df2a129554fdf8336d8a6f0cdcc6fd4832 Mon Sep 17 00:00:00 2001
+From d22e44c8fb1c87afb90391188733f7ce8fea005d Mon Sep 17 00:00:00 2001
From: Ed Santiago <santiago@redhat.com>
Date: Tue, 9 Feb 2021 17:28:05 -0700
Subject: [PATCH] tweaks for running buildah tests under podman
@@ -9,10 +9,10 @@ Signed-off-by: Ed Santiago <santiago@redhat.com>
1 file changed, 67 insertions(+), 3 deletions(-)
diff --git a/tests/helpers.bash b/tests/helpers.bash
-index e3087063..178a486e 100644
+index 8cb93c3a..72c1c797 100644
--- a/tests/helpers.bash
+++ b/tests/helpers.bash
-@@ -51,6 +51,23 @@ EOF
+@@ -52,6 +52,23 @@ EOF
ROOTDIR_OPTS="--root ${TEST_SCRATCH_DIR}/root --runroot ${TEST_SCRATCH_DIR}/runroot --storage-driver ${STORAGE_DRIVER}"
BUILDAH_REGISTRY_OPTS="--registries-conf ${TEST_SOURCES}/registries.conf --registries-conf-dir ${TEST_SCRATCH_DIR}/registries.d --short-name-alias-conf ${TEST_SCRATCH_DIR}/cache/shortnames.conf"
PODMAN_REGISTRY_OPTS="--registries-conf ${TEST_SOURCES}/registries.conf"
@@ -36,7 +36,7 @@ index e3087063..178a486e 100644
}
function starthttpd() {
-@@ -94,6 +111,12 @@ function teardown_tests() {
+@@ -95,6 +112,12 @@ function teardown_tests() {
stop_git_daemon
stop_registry
@@ -49,7 +49,7 @@ index e3087063..178a486e 100644
# Workaround for #1991 - buildah + overlayfs leaks mount points.
# Many tests leave behind /var/tmp/.../root/overlay and sub-mounts;
# let's find those and clean them up, otherwise 'rm -rf' fails.
-@@ -186,6 +209,10 @@ function podman() {
+@@ -187,6 +210,10 @@ function podman() {
command ${PODMAN_BINARY:-podman} ${PODMAN_REGISTRY_OPTS} ${ROOTDIR_OPTS} "$@"
}
@@ -60,7 +60,7 @@ index e3087063..178a486e 100644
# There are various scenarios where we would like to execute `tests` as rootless user, however certain commands like `buildah mount`
# do not work in rootless session since a normal user cannot mount a filesystem unless they're in a user namespace along with its
# own mount namespace. In order to run such specific commands from a rootless session we must perform `buildah unshare`.
-@@ -247,8 +274,36 @@ function run_buildah() {
+@@ -248,8 +275,36 @@ function run_buildah() {
--retry) retry=3; shift;; # retry network flakes
esac
@@ -98,7 +98,7 @@ index e3087063..178a486e 100644
# If session is rootless and `buildah mount` is invoked, perform unshare,
# since normal user cannot mount a filesystem unless they're in a user namespace along with its own mount namespace.
-@@ -262,8 +317,8 @@ function run_buildah() {
+@@ -263,8 +318,8 @@ function run_buildah() {
retry=$(( retry - 1 ))
# stdout is only emitted upon error; this echo is to help a debugger
@@ -109,7 +109,7 @@ index e3087063..178a486e 100644
# without "quotes", multiple lines are glommed together into one
if [ -n "$output" ]; then
echo "$output"
-@@ -595,6 +650,15 @@ function skip_if_no_docker() {
+@@ -596,6 +651,15 @@ function skip_if_no_docker() {
fi
}
@@ -126,5 +126,5 @@ index e3087063..178a486e 100644
daemondir=${TEST_SCRATCH_DIR}/git-daemon
mkdir -p ${daemondir}/repo
--
-2.35.3
+2.36.1
diff --git a/test/e2e/build/Containerfile.userns-auto b/test/e2e/build/Containerfile.userns-auto
new file mode 100644
index 000000000..921610982
--- /dev/null
+++ b/test/e2e/build/Containerfile.userns-auto
@@ -0,0 +1,2 @@
+FROM alpine
+RUN cat /proc/self/uid_map
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 2d7c47a7f..8fe89f32e 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -571,7 +571,7 @@ func (s *PodmanSessionIntegration) InspectContainerToJSON() []define.InspectCont
func (s *PodmanSessionIntegration) InspectPodToJSON() define.InspectPodData {
var i define.InspectPodData
err := jsoniter.Unmarshal(s.Out.Contents(), &i)
- Expect(err).To(BeNil())
+ Expect(err).ToNot(HaveOccurred())
return i
}
diff --git a/test/e2e/events_test.go b/test/e2e/events_test.go
index 528fa143d..d54265558 100644
--- a/test/e2e/events_test.go
+++ b/test/e2e/events_test.go
@@ -42,10 +42,7 @@ var _ = Describe("Podman events", func() {
// Perhaps a future version of this test would put events in a go func and send output back over a channel
// while events occur.
- // These tests are only known to work on Fedora ATM. Other distributions
- // will be skipped.
It("podman events", func() {
- SkipIfNotFedora()
_, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"events", "--stream=false"})
@@ -54,7 +51,6 @@ var _ = Describe("Podman events", func() {
})
It("podman events with an event filter", func() {
- SkipIfNotFedora()
_, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"events", "--stream=false", "--filter", "event=start"})
@@ -81,7 +77,6 @@ var _ = Describe("Podman events", func() {
})
It("podman events with a type and filter container=id", func() {
- SkipIfNotFedora()
_, ec, cid := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"events", "--stream=false", "--filter", "type=pod", "--filter", fmt.Sprintf("container=%s", cid)})
@@ -91,7 +86,6 @@ var _ = Describe("Podman events", func() {
})
It("podman events with a type", func() {
- SkipIfNotFedora()
setup := podmanTest.Podman([]string{"run", "-dt", "--pod", "new:foobarpod", ALPINE, "top"})
setup.WaitWithDefaultTimeout()
stop := podmanTest.Podman([]string{"pod", "stop", "foobarpod"})
@@ -110,7 +104,6 @@ var _ = Describe("Podman events", func() {
})
It("podman events --since", func() {
- SkipIfNotFedora()
_, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"events", "--stream=false", "--since", "1m"})
@@ -119,7 +112,6 @@ var _ = Describe("Podman events", func() {
})
It("podman events --until", func() {
- SkipIfNotFedora()
_, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
result := podmanTest.Podman([]string{"events", "--stream=false", "--until", "1h"})
@@ -128,7 +120,6 @@ var _ = Describe("Podman events", func() {
})
It("podman events format", func() {
- SkipIfNotFedora()
_, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
@@ -153,6 +144,13 @@ var _ = Describe("Podman events", func() {
event = events.Event{}
err = json.Unmarshal([]byte(jsonArr[0]), &event)
Expect(err).ToNot(HaveOccurred())
+
+ test = podmanTest.Podman([]string{"events", "--stream=false", "--filter=type=container", "--format", "ID: {{.ID}}"})
+ test.WaitWithDefaultTimeout()
+ Expect(test).To(Exit(0))
+ arr := test.OutputToStringArray()
+ Expect(len(arr)).To(BeNumerically(">", 1))
+ Expect(arr[0]).To(MatchRegexp("ID: [a-fA-F0-9]{64}"))
})
It("podman events --until future", func() {
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index e7ceaf2d2..d8308aeea 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -3,6 +3,7 @@ package integration
import (
"io/ioutil"
"os"
+ "os/user"
"path/filepath"
"strconv"
"strings"
@@ -71,6 +72,10 @@ var _ = Describe("Podman generate kube", func() {
Expect(pod.Spec.Containers[0]).To(HaveField("WorkingDir", ""))
Expect(pod.Spec.Containers[0].Env).To(BeNil())
Expect(pod).To(HaveField("Name", "top-pod"))
+ enableServiceLinks := false
+ Expect(pod.Spec).To(HaveField("EnableServiceLinks", &enableServiceLinks))
+ automountServiceAccountToken := false
+ Expect(pod.Spec).To(HaveField("AutomountServiceAccountToken", &automountServiceAccountToken))
numContainers := 0
for range pod.Spec.Containers {
@@ -165,6 +170,10 @@ var _ = Describe("Podman generate kube", func() {
err := yaml.Unmarshal(kube.Out.Contents(), pod)
Expect(err).To(BeNil())
Expect(pod.Spec).To(HaveField("HostNetwork", false))
+ enableServiceLinks := false
+ Expect(pod.Spec).To(HaveField("EnableServiceLinks", &enableServiceLinks))
+ automountServiceAccountToken := false
+ Expect(pod.Spec).To(HaveField("AutomountServiceAccountToken", &automountServiceAccountToken))
numContainers := 0
for range pod.Spec.Containers {
@@ -262,6 +271,39 @@ var _ = Describe("Podman generate kube", func() {
Expect(numContainers).To(Equal(1))
})
+ It("podman generate kube on pod with user namespace", func() {
+ u, err := user.Current()
+ Expect(err).To(BeNil())
+ name := u.Name
+ if name == "root" {
+ name = "containers"
+ }
+ content, err := ioutil.ReadFile("/etc/subuid")
+ if err != nil {
+ Skip("cannot read /etc/subuid")
+ }
+ if !strings.Contains(string(content), name) {
+ Skip("cannot find mappings for the current user")
+ }
+ podSession := podmanTest.Podman([]string{"pod", "create", "--name", "testPod", "--userns=auto"})
+ podSession.WaitWithDefaultTimeout()
+ Expect(podSession).Should(Exit(0))
+
+ session := podmanTest.Podman([]string{"create", "--name", "topcontainer", "--pod", "testPod", ALPINE, "top"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ kube := podmanTest.Podman([]string{"generate", "kube", "testPod"})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ pod := new(v1.Pod)
+ err = yaml.Unmarshal(kube.Out.Contents(), pod)
+ Expect(err).To(BeNil())
+ expected := false
+ Expect(pod.Spec).To(HaveField("HostUsers", &expected))
+ })
+
It("podman generate kube on pod with host network", func() {
podSession := podmanTest.Podman([]string{"pod", "create", "--name", "testHostNetwork", "--network", "host"})
podSession.WaitWithDefaultTimeout()
@@ -497,7 +539,7 @@ var _ = Describe("Podman generate kube", func() {
Expect(podSession).Should(Exit(0))
ctr1Name := "ctr1"
- ctr1Session := podmanTest.Podman([]string{"create", "--name", ctr1Name, "--pod", podName, "--memory", "10Mi", ALPINE, "top"})
+ ctr1Session := podmanTest.Podman([]string{"create", "--name", ctr1Name, "--pod", podName, "--memory", "10M", ALPINE, "top"})
ctr1Session.WaitWithDefaultTimeout()
Expect(ctr1Session).Should(Exit(0))
@@ -550,6 +592,11 @@ var _ = Describe("Podman generate kube", func() {
It("podman generate kube on pod with ports", func() {
podName := "test"
+
+ lock4 := GetPortLock("4000")
+ defer lock4.Unlock()
+ lock5 := GetPortLock("5000")
+ defer lock5.Unlock()
podSession := podmanTest.Podman([]string{"pod", "create", "--name", podName, "-p", "4000:4000", "-p", "5000:5000"})
podSession.WaitWithDefaultTimeout()
Expect(podSession).Should(Exit(0))
@@ -710,7 +757,7 @@ var _ = Describe("Podman generate kube", func() {
pod := new(v1.Pod)
err = yaml.Unmarshal(b, pod)
Expect(err).To(BeNil())
- Expect(pod.Annotations).To(HaveKeyWithValue(define.BindMountPrefix+vol1, HaveSuffix("z")))
+ Expect(pod.Annotations).To(HaveKeyWithValue(define.BindMountPrefix, vol1+":"+"z"))
rm := podmanTest.Podman([]string{"pod", "rm", "-t", "0", "-f", "test1"})
rm.WaitWithDefaultTimeout()
diff --git a/test/e2e/generate_systemd_test.go b/test/e2e/generate_systemd_test.go
index 45a2f1f86..f47abbc13 100644
--- a/test/e2e/generate_systemd_test.go
+++ b/test/e2e/generate_systemd_test.go
@@ -600,4 +600,75 @@ var _ = Describe("Podman generate systemd", func() {
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring(" --label key={{someval}}"))
})
+
+ It("podman generate systemd --env", func() {
+ session := podmanTest.RunTopContainer("test")
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"generate", "systemd", "--env", "foo=bar", "-e", "hoge=fuga", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("Environment=foo=bar"))
+ Expect(session.OutputToString()).To(ContainSubstring("Environment=hoge=fuga"))
+
+ session = podmanTest.Podman([]string{"generate", "systemd", "--env", "=bar", "-e", "hoge=fuga", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(125))
+ Expect(session.ErrorToString()).To(ContainSubstring("invalid environment variable"))
+
+ // Use -e/--env option with --new option
+ session = podmanTest.Podman([]string{"generate", "systemd", "--env", "foo=bar", "-e", "hoge=fuga", "--new", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("Environment=foo=bar"))
+ Expect(session.OutputToString()).To(ContainSubstring("Environment=hoge=fuga"))
+
+ session = podmanTest.Podman([]string{"generate", "systemd", "--env", "foo=bar", "-e", "=fuga", "--new", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(125))
+ Expect(session.ErrorToString()).To(ContainSubstring("invalid environment variable"))
+
+ // Escape systemd arguments
+ session = podmanTest.Podman([]string{"generate", "systemd", "--env", "BAR=my test", "-e", "USER=%a", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("\"BAR=my test\""))
+ Expect(session.OutputToString()).To(ContainSubstring("USER=%%a"))
+
+ session = podmanTest.Podman([]string{"generate", "systemd", "--env", "BAR=my test", "-e", "USER=%a", "--new", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("\"BAR=my test\""))
+ Expect(session.OutputToString()).To(ContainSubstring("USER=%%a"))
+
+ // Specify the environment variables without a value
+ os.Setenv("FOO1", "BAR1")
+ os.Setenv("FOO2", "BAR2")
+ os.Setenv("FOO3", "BAR3")
+ defer os.Unsetenv("FOO1")
+ defer os.Unsetenv("FOO2")
+ defer os.Unsetenv("FOO3")
+
+ session = podmanTest.Podman([]string{"generate", "systemd", "--env", "FOO1", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("BAR1"))
+ Expect(session.OutputToString()).NotTo(ContainSubstring("BAR2"))
+ Expect(session.OutputToString()).NotTo(ContainSubstring("BAR3"))
+
+ session = podmanTest.Podman([]string{"generate", "systemd", "--env", "FOO*", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("BAR1"))
+ Expect(session.OutputToString()).To(ContainSubstring("BAR2"))
+ Expect(session.OutputToString()).To(ContainSubstring("BAR3"))
+
+ session = podmanTest.Podman([]string{"generate", "systemd", "--env", "FOO*", "--new", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("BAR1"))
+ Expect(session.OutputToString()).To(ContainSubstring("BAR2"))
+ Expect(session.OutputToString()).To(ContainSubstring("BAR3"))
+ })
})
diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go
index ece1b519d..30a5c6482 100644
--- a/test/e2e/network_connect_disconnect_test.go
+++ b/test/e2e/network_connect_disconnect_test.go
@@ -157,7 +157,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
Expect(con.ErrorToString()).To(ContainSubstring(`"slirp4netns" is not supported: invalid network mode`))
})
- It("podman connect on a container that already is connected to the network should error", func() {
+ It("podman connect on a container that already is connected to the network should error after init", func() {
netName := "aliasTest" + stringid.GenerateNonCryptoID()
session := podmanTest.Podman([]string{"network", "create", netName})
session.WaitWithDefaultTimeout()
@@ -177,7 +177,15 @@ var _ = Describe("Podman network connect and disconnect", func() {
con := podmanTest.Podman([]string{"network", "connect", netName, "test"})
con.WaitWithDefaultTimeout()
- Expect(con).Should(ExitWithError())
+ Expect(con).Should(Exit(0))
+
+ init := podmanTest.Podman([]string{"init", "test"})
+ init.WaitWithDefaultTimeout()
+ Expect(init).Should(Exit(0))
+
+ con2 := podmanTest.Podman([]string{"network", "connect", netName, "test"})
+ con2.WaitWithDefaultTimeout()
+ Expect(con2).Should(ExitWithError())
})
It("podman network connect", func() {
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 1b4eefd45..baa74cb51 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -380,6 +380,9 @@ spec:
restartPolicy: {{ .RestartPolicy }}
hostname: {{ .Hostname }}
hostNetwork: {{ .HostNetwork }}
+{{ if .HostUsers }}
+ hostUsers: {{ .HostUsers }}
+{{ end }}
hostAliases:
{{ range .HostAliases }}
- hostnames:
@@ -509,6 +512,9 @@ spec:
volumes:
{{ range . }}
- name: {{ .Name }}
+ {{- if (eq .VolumeType "EmptyDir") }}
+ emptyDir: {}
+ {{- end }}
{{- if (eq .VolumeType "HostPath") }}
hostPath:
path: {{ .HostPath.Path }}
@@ -841,6 +847,7 @@ type Pod struct {
RestartPolicy string
Hostname string
HostNetwork bool
+ HostUsers *bool
HostAliases []HostAlias
Ctrs []*Ctr
InitCtrs []*Ctr
@@ -965,6 +972,12 @@ func withHostNetwork() podOption {
}
}
+func withHostUsers(val bool) podOption {
+ return func(pod *Pod) {
+ pod.HostUsers = &val
+ }
+}
+
// Deployment describes the options a kube yaml can be configured at deployment level
type Deployment struct {
Name string
@@ -1242,12 +1255,15 @@ type ConfigMap struct {
Optional bool
}
+type EmptyDir struct{}
+
type Volume struct {
VolumeType string
Name string
HostPath
PersistentVolumeClaim
ConfigMap
+ EmptyDir
}
// getHostPathVolume takes a type and a location for a HostPath
@@ -1289,6 +1305,14 @@ func getConfigMapVolume(vName string, items []map[string]string, optional bool)
}
}
+func getEmptyDirVolume() *Volume {
+ return &Volume{
+ VolumeType: "EmptyDir",
+ Name: defaultVolName,
+ EmptyDir: EmptyDir{},
+ }
+}
+
type Env struct {
Name string
Value string
@@ -2482,7 +2506,7 @@ spec:
It("podman play kube test with network portbindings", func() {
ip := "127.0.0.100"
- port := "5000"
+ port := "8087"
ctr := getCtr(withHostIP(ip, port), withImage(BB))
pod := getPod(withCtr(ctr))
@@ -2496,7 +2520,7 @@ spec:
inspect := podmanTest.Podman([]string{"port", getCtrNameInPod(pod)})
inspect.WaitWithDefaultTimeout()
Expect(inspect).Should(Exit(0))
- Expect(inspect.OutputToString()).To(Equal("5000/tcp -> 127.0.0.100:5000"))
+ Expect(inspect.OutputToString()).To(Equal("8087/tcp -> 127.0.0.100:8087"))
})
It("podman play kube test with nonexistent empty HostPath type volume", func() {
@@ -2762,6 +2786,43 @@ VOLUME %s`, ALPINE, hostPathDir+"/")
Expect(kube).Should(Exit(0))
})
+ It("podman play kube with emptyDir volume", func() {
+ podName := "test-pod"
+ ctrName1 := "vol-test-ctr"
+ ctrName2 := "vol-test-ctr-2"
+ ctr1 := getCtr(withVolumeMount("/test-emptydir", false), withImage(BB), withName(ctrName1))
+ ctr2 := getCtr(withVolumeMount("/test-emptydir-2", false), withImage(BB), withName(ctrName2))
+ pod := getPod(withPodName(podName), withVolume(getEmptyDirVolume()), withCtr(ctr1), withCtr(ctr2))
+ err = generateKubeYaml("pod", pod, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube := podmanTest.Podman([]string{"play", "kube", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ emptyDirCheck1 := podmanTest.Podman([]string{"exec", podName + "-" + ctrName1, "ls", "/test-emptydir"})
+ emptyDirCheck1.WaitWithDefaultTimeout()
+ Expect(emptyDirCheck1).Should(Exit(0))
+
+ emptyDirCheck2 := podmanTest.Podman([]string{"exec", podName + "-" + ctrName2, "ls", "/test-emptydir-2"})
+ emptyDirCheck2.WaitWithDefaultTimeout()
+ Expect(emptyDirCheck2).Should(Exit(0))
+
+ volList1 := podmanTest.Podman([]string{"volume", "ls", "-q"})
+ volList1.WaitWithDefaultTimeout()
+ Expect(volList1).Should(Exit(0))
+ Expect(volList1.OutputToString()).To(Equal(defaultVolName))
+
+ remove := podmanTest.Podman([]string{"pod", "rm", "-f", podName})
+ remove.WaitWithDefaultTimeout()
+ Expect(remove).Should(Exit(0))
+
+ volList2 := podmanTest.Podman([]string{"volume", "ls", "-q"})
+ volList2.WaitWithDefaultTimeout()
+ Expect(volList2).Should(Exit(0))
+ Expect(volList2.OutputToString()).To(Equal(""))
+ })
+
It("podman play kube applies labels to pods", func() {
var numReplicas int32 = 5
expectedLabelKey := "key1"
@@ -3732,8 +3793,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
Expect((inspect.InspectContainerToJSON()[0]).HostConfig.LogConfig.Tag).To(Equal("{{.ImageName}}"))
})
- // Check that --userns=auto creates a user namespace
- It("podman play kube --userns=auto", func() {
+ It("podman play kube using a user namespace", func() {
u, err := user.Current()
Expect(err).To(BeNil())
name := u.Name
@@ -3780,6 +3840,26 @@ ENV OPENJ9_JAVA_OPTIONS=%q
usernsInCtr.WaitWithDefaultTimeout()
Expect(usernsInCtr).Should(Exit(0))
Expect(string(usernsInCtr.Out.Contents())).To(Not(Equal(string(initialUsernsConfig))))
+
+ // Now try with hostUsers in the pod spec
+ for _, hostUsers := range []bool{true, false} {
+ pod = getPod(withHostUsers(hostUsers))
+ err = generateKubeYaml("pod", pod, kubeYaml)
+ Expect(err).To(BeNil())
+
+ kube = podmanTest.PodmanNoCache([]string{"play", "kube", "--replace", kubeYaml})
+ kube.WaitWithDefaultTimeout()
+ Expect(kube).Should(Exit(0))
+
+ usernsInCtr = podmanTest.Podman([]string{"exec", getCtrNameInPod(pod), "cat", "/proc/self/uid_map"})
+ usernsInCtr.WaitWithDefaultTimeout()
+ Expect(usernsInCtr).Should(Exit(0))
+ if hostUsers {
+ Expect(string(usernsInCtr.Out.Contents())).To(Equal(string(initialUsernsConfig)))
+ } else {
+ Expect(string(usernsInCtr.Out.Contents())).To(Not(Equal(string(initialUsernsConfig))))
+ }
+ }
})
// Check the block devices are exposed inside container
diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go
index 351317cc5..cefdee40a 100644
--- a/test/e2e/pod_inspect_test.go
+++ b/test/e2e/pod_inspect_test.go
@@ -118,4 +118,21 @@ var _ = Describe("Podman pod inspect", func() {
Expect(inspectOut.OutputToString()).To(ContainSubstring(macAddr))
})
+
+ It("podman inspect two pods", func() {
+ _, ec, podid1 := podmanTest.CreatePod(nil)
+ Expect(ec).To(Equal(0))
+
+ _, ec, podid2 := podmanTest.CreatePod(nil)
+ Expect(ec).To(Equal(0))
+
+ inspect := podmanTest.Podman([]string{"pod", "inspect", podid1, podid2})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect).Should(Exit(0))
+ Expect(inspect.OutputToString()).To(BeValidJSON())
+ podData := inspect.InspectPodArrToJSON()
+ Expect(podData).To(HaveLen(2))
+ Expect(podData[0]).To(HaveField("ID", podid1))
+ Expect(podData[1]).To(HaveField("ID", podid2))
+ })
})
diff --git a/test/e2e/restart_test.go b/test/e2e/restart_test.go
index dd0070f54..9df884292 100644
--- a/test/e2e/restart_test.go
+++ b/test/e2e/restart_test.go
@@ -228,7 +228,7 @@ var _ = Describe("Podman restart", func() {
Expect(beforeRestart.OutputToString()).To(Equal(afterRestart.OutputToString()))
})
- It("podman restart all stoped containers with --all", func() {
+ It("podman restart all stopped containers with --all", func() {
session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
diff --git a/test/e2e/run_cpu_test.go b/test/e2e/run_cpu_test.go
index e57eb3b26..19bb735ff 100644
--- a/test/e2e/run_cpu_test.go
+++ b/test/e2e/run_cpu_test.go
@@ -138,4 +138,20 @@ var _ = Describe("Podman run cpu", func() {
result.WaitWithDefaultTimeout()
Expect(result).To(ExitWithError())
})
+
+ It("podman run invalid cpu-rt-period with cgroupsv2", func() {
+ SkipIfCgroupV1("testing options that only work in cgroup v2")
+ result := podmanTest.Podman([]string{"run", "--rm", "--cpu-rt-period=5000", ALPINE, "ls"})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(result.ErrorToString()).To(ContainSubstring("Realtime period not supported on cgroups V2 systems"))
+ })
+
+ It("podman run invalid cpu-rt-runtime with cgroupsv2", func() {
+ SkipIfCgroupV1("testing options that only work in cgroup v2")
+ result := podmanTest.Podman([]string{"run", "--rm", "--cpu-rt-runtime=5000", ALPINE, "ls"})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(result.ErrorToString()).To(ContainSubstring("Realtime runtime not supported on cgroups V2 systems"))
+ })
})
diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go
index 8207f6d0b..12783cd29 100644
--- a/test/e2e/run_staticip_test.go
+++ b/test/e2e/run_staticip_test.go
@@ -105,6 +105,13 @@ var _ = Describe("Podman run with --ip flag", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ // We need to set "no_proxy" in proxy environment
+ if env, found := os.LookupEnv("no_proxy"); found {
+ defer os.Setenv("no_proxy", env)
+ } else {
+ defer os.Unsetenv("no_proxy")
+ }
+ os.Setenv("no_proxy", ip)
for retries := 20; retries > 0; retries-- {
response, err := http.Get(fmt.Sprintf("http://%s", ip))
if err == nil && response.StatusCode == http.StatusOK {
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 1f6b6fa3d..3b10fdff3 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -945,7 +945,7 @@ echo -n %s >%s
session := podmanTest.Podman([]string{"run", "--rm", "--user=1234", ALPINE, "id"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- Expect(session.OutputToString()).To(Equal("uid=1234(1234) gid=0(root)"))
+ Expect(session.OutputToString()).To(Equal("uid=1234(1234) gid=0(root) groups=0(root)"))
})
It("podman run with user (integer, in /etc/passwd)", func() {
@@ -966,14 +966,14 @@ echo -n %s >%s
session := podmanTest.Podman([]string{"run", "--rm", "--user=mail:21", ALPINE, "id"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- Expect(session.OutputToString()).To(Equal("uid=8(mail) gid=21(ftp)"))
+ Expect(session.OutputToString()).To(Equal("uid=8(mail) gid=21(ftp) groups=21(ftp)"))
})
It("podman run with user:group (integer:groupname)", func() {
session := podmanTest.Podman([]string{"run", "--rm", "--user=8:ftp", ALPINE, "id"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- Expect(session.OutputToString()).To(Equal("uid=8(mail) gid=21(ftp)"))
+ Expect(session.OutputToString()).To(Equal("uid=8(mail) gid=21(ftp) groups=21(ftp)"))
})
It("podman run with user, verify caps dropped", func() {
@@ -984,6 +984,14 @@ echo -n %s >%s
Expect("0000000000000000").To(Equal(capEff[1]))
})
+ It("podman run with user, verify group added", func() {
+ session := podmanTest.Podman([]string{"run", "--rm", "--user=1000:1000", ALPINE, "grep", "Groups:", "/proc/self/status"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ groups := strings.Split(session.OutputToString(), " ")[1]
+ Expect("1000").To(Equal(groups))
+ })
+
It("podman run with attach stdin outputs container ID", func() {
session := podmanTest.Podman([]string{"run", "--attach", "stdin", ALPINE, "printenv"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go
index f247b2dac..016f67bf6 100644
--- a/test/e2e/run_userns_test.go
+++ b/test/e2e/run_userns_test.go
@@ -8,6 +8,7 @@ import (
"strings"
. "github.com/containers/podman/v4/test/utils"
+ "github.com/containers/storage"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
@@ -42,6 +43,33 @@ var _ = Describe("Podman UserNS support", func() {
})
+ // Note: Lot of tests for build with --userns=auto are already there in buildah
+ // but they are skipped in podman CI because bud tests are executed in rootfull
+ // environment ( where mappings for the `containers` user is not present in /etc/subuid )
+ // causing them to skip hence this is a redundant test for sanity to make sure
+ // we don't break this feature for podman-remote.
+ It("podman build with --userns=auto", func() {
+ u, err := user.Current()
+ Expect(err).To(BeNil())
+ name := u.Name
+ if name == "root" {
+ name = "containers"
+ }
+ content, err := ioutil.ReadFile("/etc/subuid")
+ if err != nil {
+ Skip("cannot read /etc/subuid")
+ }
+ if !strings.Contains(string(content), name) {
+ Skip("cannot find mappings for the current user")
+ }
+ session := podmanTest.Podman([]string{"build", "-f", "build/Containerfile.userns-auto", "-t", "test", "--userns=auto"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ // `1024` is the default size or length of the range of user IDs
+ // that is mapped between the two user namespaces by --userns=auto.
+ Expect(session.OutputToString()).To(ContainSubstring(fmt.Sprintf("%d", storage.AutoUserNsMinSize)))
+ })
+
It("podman uidmapping and gidmapping", func() {
session := podmanTest.Podman([]string{"run", "--uidmap=0:100:5000", "--gidmap=0:200:5000", "alpine", "echo", "hello"})
session.WaitWithDefaultTimeout()
@@ -85,6 +113,16 @@ var _ = Describe("Podman UserNS support", func() {
Expect(session).Should(Exit(0))
uid := fmt.Sprintf("%d", os.Geteuid())
Expect(session.OutputToString()).To(ContainSubstring(uid))
+
+ session = podmanTest.Podman([]string{"run", "--userns=keep-id:uid=10,gid=12", "alpine", "sh", "-c", "echo $(id -u):$(id -g)"})
+ session.WaitWithDefaultTimeout()
+ if os.Geteuid() == 0 {
+ Expect(session).Should(Exit(125))
+ return
+ }
+
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("10:12"))
})
It("podman --userns=keep-id check passwd", func() {
@@ -157,6 +195,8 @@ var _ = Describe("Podman UserNS support", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
l := session.OutputToString()
+ // `1024` is the default size or length of the range of user IDs
+ // that is mapped between the two user namespaces by --userns=auto.
Expect(l).To(ContainSubstring("1024"))
m[l] = l
}
diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go
index 94c363dd4..afb723a63 100644
--- a/test/e2e/save_test.go
+++ b/test/e2e/save_test.go
@@ -153,6 +153,9 @@ var _ = Describe("Podman save", func() {
defer os.Setenv("GNUPGHOME", origGNUPGHOME)
port := 5000
+ portlock := GetPortLock(strconv.Itoa(port))
+ defer portlock.Unlock()
+
session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", strings.Join([]string{strconv.Itoa(port), strconv.Itoa(port)}, ":"), REGISTRY_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
diff --git a/test/e2e/secret_test.go b/test/e2e/secret_test.go
index c6d5e6391..902f422bd 100644
--- a/test/e2e/secret_test.go
+++ b/test/e2e/secret_test.go
@@ -200,27 +200,33 @@ var _ = Describe("Podman secret", func() {
list := podmanTest.Podman([]string{"secret", "ls", "--filter", fmt.Sprintf("name=%s", secret1)})
list.WaitWithDefaultTimeout()
Expect(list).Should(Exit(0))
- Expect(list.OutputToStringArray()).To(HaveLen(2), ContainSubstring(secret1))
+ Expect(list.OutputToStringArray()).To(HaveLen(2))
+ Expect(list.OutputToStringArray()[1]).To(ContainSubstring(secret1))
list = podmanTest.Podman([]string{"secret", "ls", "--filter", fmt.Sprintf("name=%s", secret2)})
list.WaitWithDefaultTimeout()
Expect(list).Should(Exit(0))
- Expect(list.OutputToStringArray()).To(HaveLen(2), ContainSubstring(secret2))
+ Expect(list.OutputToStringArray()).To(HaveLen(2))
+ Expect(list.OutputToStringArray()[1]).To(ContainSubstring(secret2))
list = podmanTest.Podman([]string{"secret", "ls", "--filter", fmt.Sprintf("id=%s", secrID1)})
list.WaitWithDefaultTimeout()
Expect(list).Should(Exit(0))
- Expect(list.OutputToStringArray()).To(HaveLen(2), ContainSubstring(secrID1))
+ Expect(list.OutputToStringArray()).To(HaveLen(2))
+ Expect(list.OutputToStringArray()[1]).To(ContainSubstring(secrID1))
list = podmanTest.Podman([]string{"secret", "ls", "--filter", fmt.Sprintf("id=%s", secrID2)})
list.WaitWithDefaultTimeout()
Expect(list).Should(Exit(0))
- Expect(list.OutputToStringArray()).To(HaveLen(2), ContainSubstring(secrID2))
+ Expect(list.OutputToStringArray()).To(HaveLen(2))
+ Expect(list.OutputToStringArray()[1]).To(ContainSubstring(secrID2))
list = podmanTest.Podman([]string{"secret", "ls", "--filter", fmt.Sprintf("name=%s,name=%s", secret1, secret2)})
list.WaitWithDefaultTimeout()
Expect(list).Should(Exit(0))
- Expect(list.OutputToStringArray()).To(HaveLen(3), ContainSubstring(secret1), ContainSubstring(secret2))
+ Expect(list.OutputToStringArray()).To(HaveLen(3))
+ Expect(list.OutputToString()).To(ContainSubstring(secret1))
+ Expect(list.OutputToString()).To(ContainSubstring(secret2))
})
It("podman secret ls with Go template", func() {
diff --git a/test/e2e/update_test.go b/test/e2e/update_test.go
new file mode 100644
index 000000000..97dadd04c
--- /dev/null
+++ b/test/e2e/update_test.go
@@ -0,0 +1,200 @@
+package integration
+
+import (
+ "github.com/containers/common/pkg/cgroupv2"
+ . "github.com/containers/podman/v4/test/utils"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gexec"
+)
+
+var _ = Describe("Podman update", func() {
+ var (
+ tempdir string
+ err error
+ podmanTest *PodmanTestIntegration
+ )
+
+ BeforeEach(func() {
+ tempdir, err = CreateTempDirInTempDir()
+ Expect(err).To(BeNil())
+ podmanTest = PodmanTestCreate(tempdir)
+ podmanTest.Setup()
+ })
+
+ AfterEach(func() {
+ podmanTest.Cleanup()
+ f := CurrentGinkgoTestDescription()
+ processTestResult(f)
+
+ })
+
+ It("podman update container all options v1", func() {
+ SkipIfCgroupV2("testing flags that only work in cgroup v1")
+ SkipIfRootless("many of these handlers are not enabled while rootless in CI")
+ session := podmanTest.Podman([]string{"run", "-dt", ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ ctrID := session.OutputToString()
+
+ commonArgs := []string{
+ "update",
+ "--cpus", "5",
+ "--cpuset-cpus", "0",
+ "--cpu-shares", "123",
+ "--cpuset-mems", "0",
+ "--memory", "1G",
+ "--memory-swap", "2G",
+ "--memory-reservation", "2G",
+ "--memory-swappiness", "50", ctrID}
+
+ session = podmanTest.Podman(commonArgs)
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // checking cpu quota from --cpus
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("500000"))
+
+ // checking cpuset-cpus
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/cpuset/cpuset.cpus"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(Equal("0"))
+
+ // checking cpuset-mems
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/cpuset/cpuset.mems"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(Equal("0"))
+
+ // checking memory limit
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/memory/memory.limit_in_bytes"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("1073741824"))
+
+ // checking memory-swap
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("2147483648"))
+
+ // checking cpu-shares
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/cpu/cpu.shares"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("123"))
+
+ })
+
+ It("podman update container all options v2", func() {
+ SkipIfCgroupV1("testing flags that only work in cgroup v2")
+ SkipIfRootless("many of these handlers are not enabled while rootless in CI")
+ session := podmanTest.Podman([]string{"run", "-dt", ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ ctrID := session.OutputToString()
+
+ commonArgs := []string{
+ "update",
+ "--cpus", "5",
+ "--cpuset-cpus", "0",
+ "--cpu-shares", "123",
+ "--cpuset-mems", "0",
+ "--memory", "1G",
+ "--memory-swap", "2G",
+ "--memory-reservation", "2G",
+ "--blkio-weight", "123",
+ "--device-read-bps", "/dev/zero:10mb",
+ "--device-write-bps", "/dev/zero:10mb",
+ "--device-read-iops", "/dev/zero:1000",
+ "--device-write-iops", "/dev/zero:1000",
+ ctrID}
+
+ session = podmanTest.Podman(commonArgs)
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ ctrID = session.OutputToString()
+
+ // checking cpu quota and period
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/cpu.max"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("500000"))
+
+ // checking blkio weight
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/io.bfq.weight"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("123"))
+
+ // checking device-read/write-bps/iops
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/io.max"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("rbps=10485760 wbps=10485760 riops=1000 wiops=1000"))
+
+ // checking cpuset-cpus
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/cpuset.cpus"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(Equal("0"))
+
+ // checking cpuset-mems
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/cpuset.mems"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(Equal("0"))
+
+ // checking memory limit
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/memory.max"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("1073741824"))
+
+ // checking memory-swap
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/memory.swap.max"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("1073741824"))
+
+ // checking cpu-shares
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/cpu.weight"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("5"))
+ })
+
+ It("podman update keep original resources if not overridden", func() {
+ SkipIfRootless("many of these handlers are not enabled while rootless in CI")
+ session := podmanTest.Podman([]string{"run", "-dt", "--cpus", "5", ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{
+ "update",
+ "--memory", "1G",
+ session.OutputToString(),
+ })
+
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ ctrID := session.OutputToString()
+
+ if v2, _ := cgroupv2.Enabled(); v2 {
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/cpu.max"})
+ } else {
+ session = podmanTest.Podman([]string{"exec", "-it", ctrID, "cat", "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"})
+ }
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("500000"))
+ })
+})
diff --git a/test/system/001-basic.bats b/test/system/001-basic.bats
index 584511388..e3302bec3 100644
--- a/test/system/001-basic.bats
+++ b/test/system/001-basic.bats
@@ -29,6 +29,12 @@ function setup() {
local built=$(expr "$output" : ".*Built: \+\(.*\)" | head -n1)
local built_t=$(date --date="$built" +%s)
assert "$built_t" -gt 1546300800 "Preposterous 'Built' time in podman version"
+
+ run_podman -v
+ is "$output" "podman.*version \+" "'Version line' in output"
+
+ run_podman --config foobar version
+ is "$output" ".*The --config flag is ignored by Podman. Exists for Docker compatibility\+" "verify warning for --config option"
}
@test "podman info" {
@@ -190,7 +196,9 @@ See 'podman version --help'" "podman version --remote"
run_podman --log-level=error info
run_podman --log-level=fatal info
run_podman --log-level=panic info
+ # docker compat
run_podman --debug info
+ run_podman -D info
run_podman 1 --debug --log-level=panic info
is "$output" "Setting --log-level and --debug is not allowed"
}
diff --git a/test/system/090-events.bats b/test/system/090-events.bats
index ceb53ae73..cd1bf327b 100644
--- a/test/system/090-events.bats
+++ b/test/system/090-events.bats
@@ -64,7 +64,7 @@ load helpers
run_podman --events-backend=file tag $IMAGE $tag
run_podman --events-backend=file untag $IMAGE $tag
run_podman --events-backend=file tag $IMAGE $tag
- run_podman --events-backend=file rmi $tag
+ run_podman --events-backend=file rmi -f $imageID
run_podman --events-backend=file events --stream=false --filter type=image --since $t0
is "$output" ".*image push $imageID dir:$pushedDir
@@ -74,7 +74,8 @@ load helpers
.*image tag $imageID $tag
.*image untag $imageID $tag:latest
.*image tag $imageID $tag
-.*image remove $imageID $tag.*" \
+.*image untag $imageID $tag:latest
+.*image remove $imageID $imageID" \
"podman events"
}
@@ -193,3 +194,22 @@ EOF
is "$(wc -l <$eventsFile)" "$(wc -l <<<$output)" "all events are returned"
is "${lines[-2]}" ".* log-rotation $eventsFile"
}
+
+# Prior to #15633, container labels would not appear in 'die' log events
+@test "events - labels included in container die" {
+ skip_if_remote "remote does not support --events-backend"
+ local cname=c$(random_string 15)
+ local lname=l$(random_string 10)
+ local lvalue="v$(random_string 10) $(random_string 5)"
+
+ run_podman 17 --events-backend=file run --rm \
+ --name=$cname \
+ --label=$lname="$lvalue" \
+ $IMAGE sh -c 'exit 17'
+ run_podman --events-backend=file events \
+ --filter=container=$cname \
+ --filter=status=died \
+ --stream=false \
+ --format="{{.Attributes.$lname}}"
+ assert "$output" = "$lvalue" "podman-events output includes container label"
+}
diff --git a/test/system/150-login.bats b/test/system/150-login.bats
index b57bb44ab..b85007f0b 100644
--- a/test/system/150-login.bats
+++ b/test/system/150-login.bats
@@ -122,7 +122,7 @@ function setup() {
--password-stdin \
$registry <<< "x${PODMAN_LOGIN_PASS}"
is "$output" \
- "Error: error logging into \"$registry\": invalid username/password" \
+ "Error: logging into \"$registry\": invalid username/password" \
'output from podman login'
}
diff --git a/test/system/220-healthcheck.bats b/test/system/220-healthcheck.bats
index c502ad669..00ec1dd79 100644
--- a/test/system/220-healthcheck.bats
+++ b/test/system/220-healthcheck.bats
@@ -20,44 +20,8 @@ function _check_health {
done
}
-
@test "podman healthcheck" {
- # Create an image with a healthcheck script; said script will
- # pass until the file /uh-oh gets created (by us, via exec)
- cat >${PODMAN_TMPDIR}/healthcheck <<EOF
-#!/bin/sh
-
-if test -e /uh-oh; then
- echo "Uh-oh on stdout!"
- echo "Uh-oh on stderr!" >&2
- exit 1
-else
- echo "Life is Good on stdout"
- echo "Life is Good on stderr" >&2
- exit 0
-fi
-EOF
-
- cat >${PODMAN_TMPDIR}/entrypoint <<EOF
-#!/bin/sh
-
-while :; do
- sleep 1
-done
-EOF
-
- cat >${PODMAN_TMPDIR}/Containerfile <<EOF
-FROM $IMAGE
-
-COPY healthcheck /healthcheck
-COPY entrypoint /entrypoint
-
-RUN chmod 755 /healthcheck /entrypoint
-
-CMD ["/entrypoint"]
-EOF
-
- run_podman build -t healthcheck_i ${PODMAN_TMPDIR}
+ _build_health_check_image healthcheck_i
# Run that healthcheck image.
run_podman run -d --name healthcheck_c \
@@ -66,6 +30,9 @@ EOF
--health-retries 3 \
healthcheck_i
+ run_podman inspect healthcheck_c --format "{{.Config.HealthcheckOnFailureAction}}"
+ is "$output" "none" "default on-failure action is none"
+
# We can't check for 'starting' because a 1-second interval is too
# short; it could run healthcheck before we get to our first check.
#
@@ -109,4 +76,59 @@ Log[-1].Output | \"Uh-oh on stdout!\\\nUh-oh on stderr!\"
run_podman rmi healthcheck_i
}
+@test "podman healthcheck --health-on-failure" {
+ run_podman 125 create --health-on-failure=kill $IMAGE
+ is "$output" "Error: cannot set on-failure action to kill without a health check"
+
+ ctr="healthcheck_c"
+ img="healthcheck_i"
+
+ for policy in none kill restart stop;do
+ if [[ $policy == "none" ]];then
+ # Do not remove the /uh-oh file for `none` as we want to
+ # demonstrate that no action was taken
+ _build_health_check_image $img
+ else
+ _build_health_check_image $img cleanfile
+ fi
+
+ # Run that healthcheck image.
+ run_podman run -d --name $ctr \
+ --health-cmd /healthcheck \
+ --health-on-failure=$policy \
+ $img
+
+ # healthcheck should succeed
+ run_podman healthcheck run $ctr
+
+ # Now cause the healthcheck to fail
+ run_podman exec $ctr touch /uh-oh
+
+ # healthcheck should now fail, with exit status 1 and 'unhealthy' output
+ run_podman 1 healthcheck run $ctr
+ # FIXME: #15691 - `healthcheck run` may emit an error log that the timer already exists
+ is "$output" ".*unhealthy.*" "output from 'podman healthcheck run'"
+
+ run_podman inspect $ctr --format "{{.State.Status}} {{.Config.HealthcheckOnFailureAction}}"
+ if [[ $policy == "restart" ]];then
+ # Container has been restarted and health check works again
+ is "$output" "running $policy" "container has been restarted"
+ run_podman healthcheck run $ctr
+ elif [[ $policy == "none" ]];then
+ # Container is still running and health check still broken
+ is "$output" "running $policy" "container continued running"
+ run_podman 1 healthcheck run $ctr
+ # FIXME: #15691 - `healthcheck run` may emit an error log that the timer already exists
+ is "$output" ".*unhealthy.*" "output from 'podman healthcheck run'"
+ else
+ # kill and stop yield the container into a non-running state
+ is "$output" ".* $policy" "container was stopped/killed"
+ assert "$output" != "running $policy"
+ fi
+
+ run_podman rm -f -t0 $ctr
+ run_podman rmi -f $img
+ done
+}
+
# vim: filetype=sh
diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats
index 9a91501dd..3f6296b36 100644
--- a/test/system/250-systemd.bats
+++ b/test/system/250-systemd.bats
@@ -33,7 +33,11 @@ function teardown() {
# Helper to start a systemd service running a container
function service_setup() {
- run_podman generate systemd --new $cname
+ run_podman generate systemd \
+ -e http_proxy -e HTTP_PROXY \
+ -e https_proxy -e HTTPS_PROXY \
+ -e no_proxy -e NO_PROXY \
+ --new $cname
echo "$output" > "$UNIT_FILE"
run_podman rm $cname
@@ -73,6 +77,11 @@ function service_cleanup() {
# These tests can fail in dev. environment because of SELinux.
# quick fix: chcon -t container_runtime_exec_t ./bin/podman
@test "podman generate - systemd - basic" {
+ # Flakes with "ActiveState=failed (expected =inactive)"
+ if is_ubuntu; then
+ skip "FIXME: 2022-09-01: requires conmon-2.1.4, ubuntu has 2.1.3"
+ fi
+
cname=$(random_string)
# See #7407 for --pull=always.
run_podman create --pull=always --name $cname --label "io.containers.autoupdate=registry" $IMAGE \
@@ -295,25 +304,68 @@ LISTEN_FDNAMES=listen_fdnames" | sort)
run_podman network rm -f $netname
}
-@test "podman-kube@.service template" {
- # If running from a podman source directory, build and use the source
- # version of the play-kube-@ unit file
- unit_name="podman-kube@.service"
- unit_file="contrib/systemd/system/${unit_name}"
- if [[ -e ${unit_file}.in ]]; then
- echo "# [Building & using $unit_name from source]" >&3
- # Force regenerating unit file (existing one may have /usr/bin path)
- rm -f $unit_file
- BINDIR=$(dirname $PODMAN) make $unit_file
- cp $unit_file $UNIT_DIR/$unit_name
- fi
+@test "podman create --health-on-failure=kill" {
+ img="healthcheck_i"
+ _build_health_check_image $img
+
+ cname=$(random_string)
+ run_podman create --name $cname \
+ --health-cmd /healthcheck \
+ --health-on-failure=kill \
+ --restart=on-failure \
+ $img
+
+ # run container in systemd unit
+ service_setup
+
+ run_podman container inspect $cname --format "{{.ID}}"
+ oldID="$output"
+
+ run_podman healthcheck run $cname
+
+ # Now cause the healthcheck to fail
+ run_podman exec $cname touch /uh-oh
+
+ # healthcheck should now fail, with exit status 1 and 'unhealthy' output
+ run_podman 1 healthcheck run $cname
+ is "$output" "unhealthy" "output from 'podman healthcheck run'"
+ # What is expected to happen now:
+ # 1) The container gets killed as the health check has failed
+ # 2) Systemd restarts the service as the restart policy is set to "on-failure"
+ # 3) The /uh-oh file is gone and $cname has another ID
+
+ # Wait at most 10 seconds for the service to be restarted
+ local timeout=10
+ while [[ $timeout -gt 1 ]]; do
+ run_podman '?' container inspect $cname
+ if [[ $status == 0 ]]; then
+ if [[ "$output" != "$oldID" ]]; then
+ break
+ fi
+ fi
+ sleep 1
+ let timeout=$timeout-1
+ done
+
+ run_podman healthcheck run $cname
+
+ # stop systemd container
+ service_cleanup
+ run_podman rmi -f $img
+}
+
+@test "podman-kube@.service template" {
+ install_kube_template
# Create the YAMl file
yaml_source="$PODMAN_TMPDIR/test.yaml"
cat >$yaml_source <<EOF
apiVersion: v1
kind: Pod
metadata:
+ annotations:
+ io.containers.autoupdate: "local"
+ io.containers.autoupdate/b: "registry"
labels:
app: test
name: test_pod
@@ -322,8 +374,11 @@ spec:
- command:
- top
image: $IMAGE
- name: test
- resources: {}
+ name: a
+ - command:
+ - top
+ image: $IMAGE
+ name: b
EOF
# Dispatch the YAML file
@@ -344,6 +399,12 @@ EOF
run_podman 125 container rm $service_container
is "$output" "Error: container .* is the service container of pod(s) .* and cannot be removed without removing the pod(s)"
+ # Add a simple `auto-update --dry-run` test here to avoid too much redundancy
+ # with 255-auto-update.bats
+ run_podman auto-update --dry-run --format "{{.Unit}},{{.Container}},{{.Image}},{{.Updated}},{{.Policy}}"
+ is "$output" ".*$service_name,.* (test_pod-a),$IMAGE,false,local.*" "global auto-update policy gets applied"
+ is "$output" ".*$service_name,.* (test_pod-b),$IMAGE,false,registry.*" "container-specified auto-update policy gets applied"
+
# Kill the pod and make sure the service is not running.
# The restart policy is set to "never" since there is no
# design yet for propagating exit codes up to the service
diff --git a/test/system/255-auto-update.bats b/test/system/255-auto-update.bats
index c6f9600b6..a106914fe 100644
--- a/test/system/255-auto-update.bats
+++ b/test/system/255-auto-update.bats
@@ -266,8 +266,6 @@ EOF
# Generate a healthy image that will run correctly.
run_podman build -t quay.io/libpod/$image -f $dockerfile1
- podman image inspect --format "{{.ID}}" $image
- oldID="$output"
generate_service $image local /runme --sdnotify=container noTag
_wait_service_ready container-$cname.service
@@ -277,7 +275,7 @@ EOF
# Generate an unhealthy image that will fail.
run_podman build -t quay.io/libpod/$image -f $dockerfile2
- podman image inspect --format "{{.ID}}" $image
+ run_podman image inspect --format "{{.ID}}" $image
newID="$output"
run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}"
@@ -375,6 +373,12 @@ After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/podman auto-update
+Environment="http_proxy=${http_proxy}"
+Environment="HTTP_PROXY=${HTTP_PROXY}"
+Environment="https_proxy=${https_proxy}"
+Environment="HTTPS_PROXY=${HTTPS_PROXY}"
+Environment="no_proxy=${no_proxy}"
+Environment="NO_PROXY=${NO_PROXY}"
[Install]
WantedBy=default.target
@@ -409,4 +413,97 @@ EOF
_confirm_update $cname $ori_image
}
+@test "podman-kube@.service template with rollback" {
+ # sdnotify fails with runc 1.0.0-3-dev2 on Ubuntu. Let's just
+ # assume that we work only with crun, nothing else.
+ # [copied from 260-sdnotify.bats]
+ runtime=$(podman_runtime)
+ if [[ "$runtime" != "crun" ]]; then
+ skip "this test only works with crun, not $runtime"
+ fi
+
+ install_kube_template
+
+ dockerfile1=$PODMAN_TMPDIR/Dockerfile.1
+ cat >$dockerfile1 <<EOF
+FROM quay.io/libpod/fedora:31
+RUN echo -e "#!/bin/sh\n\
+printenv NOTIFY_SOCKET; echo READY; systemd-notify --ready;\n\
+trap 'echo Received SIGTERM, finishing; exit' SIGTERM; echo WAITING; while :; do sleep 0.1; done" \
+>> /runme
+RUN chmod +x /runme
+EOF
+
+ dockerfile2=$PODMAN_TMPDIR/Dockerfile.2
+ cat >$dockerfile2 <<EOF
+FROM quay.io/libpod/fedora:31
+RUN echo -e "#!/bin/sh\n\
+exit 1" >> /runme
+RUN chmod +x /runme
+EOF
+ local_image=localhost/image:$(random_string 10)
+
+ # Generate a healthy image that will run correctly.
+ run_podman build -t $local_image -f $dockerfile1
+ run_podman image inspect --format "{{.ID}}" $local_image
+ oldID="$output"
+
+ # Create the YAMl file
+ yaml_source="$PODMAN_TMPDIR/test.yaml"
+ cat >$yaml_source <<EOF
+apiVersion: v1
+kind: Pod
+metadata:
+ annotations:
+ io.containers.autoupdate: "registry"
+ io.containers.autoupdate/b: "local"
+ io.containers.sdnotify/b: "container"
+ labels:
+ app: test
+ name: test_pod
+spec:
+ containers:
+ - command:
+ - top
+ image: $IMAGE
+ name: a
+ - command:
+ - /runme
+ image: $local_image
+ name: b
+EOF
+
+ # Dispatch the YAML file
+ service_name="podman-kube@$(systemd-escape $yaml_source).service"
+ systemctl start $service_name
+ systemctl is-active $service_name
+
+ # Make sure the containers are properly configured
+ run_podman auto-update --dry-run --format "{{.Unit}},{{.Container}},{{.Image}},{{.Updated}},{{.Policy}}"
+ is "$output" ".*$service_name,.* (test_pod-a),$IMAGE,false,registry.*" "global auto-update policy gets applied"
+ is "$output" ".*$service_name,.* (test_pod-b),$local_image,false,local.*" "container-specified auto-update policy gets applied"
+
+ # Generate a broken image that will fail.
+ run_podman build -t $local_image -f $dockerfile2
+ run_podman image inspect --format "{{.ID}}" $local_image
+ newID="$output"
+
+ assert "$oldID" != "$newID" "broken image really is a new one"
+
+ # Make sure container b sees the new image
+ run_podman auto-update --dry-run --format "{{.Unit}},{{.Container}},{{.Image}},{{.Updated}},{{.Policy}}"
+ is "$output" ".*$service_name,.* (test_pod-a),$IMAGE,false,registry.*" "global auto-update policy gets applied"
+ is "$output" ".*$service_name,.* (test_pod-b),$local_image,pending,local.*" "container b sees the new image"
+
+ # Now update and check for the rollback
+ run_podman auto-update --format "{{.Unit}},{{.Container}},{{.Image}},{{.Updated}},{{.Policy}}"
+ is "$output" ".*$service_name,.* (test_pod-a),$IMAGE,rolled back,registry.*" "container a was rolled back as the update of b failed"
+ is "$output" ".*$service_name,.* (test_pod-b),$local_image,rolled back,local.*" "container b was rolled back as its update has failed"
+
+ # Clean up
+ systemctl stop $service_name
+ run_podman rmi -f $(pause_image) $local_image $newID $oldID
+ rm -f $UNIT_DIR/$unit_name
+}
+
# vim: filetype=sh
diff --git a/test/system/280-update.bats b/test/system/280-update.bats
new file mode 100644
index 000000000..c7037c286
--- /dev/null
+++ b/test/system/280-update.bats
@@ -0,0 +1,130 @@
+#!/usr/bin/env bats -*- bats -*-
+#
+# Tests for podman update
+#
+
+load helpers
+
+LOOPDEVICE=
+
+function teardown() {
+ if [[ -n "$LOOPDEVICE" ]]; then
+ losetup -d $LOOPDEVICE
+ LOOPDEVICE=
+ fi
+ basic_teardown
+}
+
+
+@test "podman update - test all options" {
+
+ local cgv=1
+ if is_cgroupsv2; then
+ cgv=2;
+ fi
+
+ # Need a block device for blkio-weight-device testing
+ local pass_loop_device=
+ if ! is_rootless; then
+ if is_cgroupsv2; then
+ lofile=${PODMAN_TMPDIR}/disk.img
+ fallocate -l 1k ${lofile}
+ LOOPDEVICE=$(losetup --show -f $lofile)
+ pass_loop_device="--device $LOOPDEVICE"
+
+ # Get maj:min (tr needed because losetup seems to use %2d)
+ lomajmin=$(losetup -l --noheadings --output MAJ:MIN $LOOPDEVICE | tr -d ' ')
+ fi
+ fi
+
+ # Shortcuts to make the table narrower
+ local -a gig=(0 1073741824 2147483648 3221225472)
+ local devicemax="1:5 rbps=10485760 wbps=31457280 riops=2000 wiops=4000"
+ local mm=memory/memory
+
+ # Format:
+ # --<option> = <value> | rootless? | check: cgroups v1 | check: cgroups v2
+ #
+ # Requires very wide window to read. Sorry.
+ #
+ # FIXMEs:
+ # cpu-rt-period (cgv1 only, on cpu/cpu.rt_period_us) works on RHEL8 but not on Ubuntu
+ # cpu-rt-runtime (cgv1 only, on cpu/cpu.rt_runtime_us) fails: error setting cgroup config for procHooks ...
+ tests="
+cpu-shares = 512 | - | cpu/cpu.shares = 512 | cpu.weight = 20
+cpus = 5 | - | cpu/cpu.cfs_quota_us = 500000 | cpu.max = 500000 100000
+cpuset-cpus = 0 | - | cpuset/cpuset.cpus = 0 | cpuset.cpus = 0
+cpuset-mems = 0 | - | cpuset/cpuset.mems = 0 | cpuset.mems = 0
+
+memory = 1G | 2 | $mm.limit_in_bytes = ${gig[1]} | memory.max = ${gig[1]}
+memory-swap = 3G | 2 | $mm.memsw.limit_in_bytes = ${gig[3]} | memory.swap.max = ${gig[2]}
+memory-reservation = 400M | 2 | $mm.soft_limit_in_bytes = 419430400 | memory.low = 419430400
+
+blkio-weight = 321 | - | - | io.bfq.weight = default 321 $lomajmin 98
+blkio-weight-device = $LOOPDEVICE:98 | - | - | io.bfq.weight = default 321 $lomajmin 98
+
+device-read-bps = /dev/zero:10mb | - | - | io.max = $devicemax
+device-read-iops = /dev/zero:2000 | - | - | io.max = $devicemax
+device-write-bps = /dev/zero:30mb | - | - | io.max = $devicemax
+device-write-iops = /dev/zero:4000 | - | - | io.max = $devicemax
+"
+
+ # Run a container
+ run_podman run ${pass_loop_device} -d $IMAGE sleep infinity
+ cid="$output"
+
+ # Pass 1: read the table above, gather up the options applicable
+ # to this test environment (root/rootless, cgroups v1/v2)
+ local -a opts
+ local -A check
+ while read opt works_rootless cgv1 cgv2; do
+ if is_rootless; then
+ local skipping="skipping --$opt : does not work rootless"
+ if [[ $works_rootless = '-' ]]; then
+ echo "[ $skipping ]"
+ continue
+ fi
+ if [[ ! $works_rootless =~ $cgv ]]; then
+ echo "[ $skipping on cgroups v$cgv ]"
+ continue
+ fi
+ fi
+
+ tuple=$cgv1
+ if is_cgroupsv2; then
+ tuple=$cgv2
+ fi
+ if [[ $tuple = '-' ]]; then
+ echo "[ skipping --$opt : N/A on cgroups v$cgv ]"
+ continue
+ fi
+
+ # OK: setting is applicable. Preserve it. (First removing whitespace)
+ opt=${opt// /}
+ opts+=("--$opt")
+ check["--$opt"]=$tuple
+ done < <(parse_table "$tests")
+
+ # Now do the update in one fell swoop
+ run_podman update "${opts[@]}" $cid
+
+ # ...and check one by one
+ for opt in "${opts[@]}"; do
+ read path op expect <<<"${check[$opt]}"
+ run_podman exec $cid cat /sys/fs/cgroup/$path
+
+ # Magic echo of unquoted-output converts newlines to spaces;
+ # important for otherwise multiline blkio file.
+ updated="$(echo $output)"
+ assert "$updated" $op "$expect" "$opt ($path)"
+ done
+
+ # Clean up
+ run_podman rm -f -t0 $cid
+ if [[ -n "$LOOPDEVICE" ]]; then
+ losetup -d $LOOPDEVICE
+ LOOPDEVICE=
+ fi
+}
+
+# vim: filetype=sh
diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats
index 5da7523f3..862bc285c 100644
--- a/test/system/500-networking.bats
+++ b/test/system/500-networking.bats
@@ -61,9 +61,9 @@ load helpers
is "$output" "$random_2" "curl 127.0.0.1:/index2.txt"
# Verify http contents: wget from a second container
- run_podman run --rm --net=host $IMAGE wget -qO - $SERVER/index.txt
+ run_podman run --rm --net=host --http-proxy=false $IMAGE wget -qO - $SERVER/index.txt
is "$output" "$random_1" "podman wget /index.txt"
- run_podman run --rm --net=host $IMAGE wget -qO - $SERVER/index2.txt
+ run_podman run --rm --net=host --http-proxy=false $IMAGE wget -qO - $SERVER/index2.txt
is "$output" "$random_2" "podman wget /index2.txt"
# Tests #4889 - two-argument form of "podman ports" was broken
diff --git a/test/system/710-kube.bats b/test/system/710-kube.bats
index 58e42148a..c446ff65f 100644
--- a/test/system/710-kube.bats
+++ b/test/system/710-kube.bats
@@ -78,11 +78,6 @@ status | = | null
assert "$actual" $op "$expect" ".$key"
done < <(parse_table "$expect")
- if ! is_remote; then
- count=$(egrep -c "$kubernetes_63" <<<"$output")
- assert "$count" = 1 "1 instance of the Kubernetes-63-char warning"
- fi
-
run_podman rm $cname
}
@@ -157,12 +152,6 @@ status | = | {}
assert "$actual" $op "$expect" ".$key"
done < <(parse_table "$expect")
- # Why 4? Maybe two for each container?
- if ! is_remote; then
- count=$(egrep -c "$kubernetes_63" <<<"$output")
- assert "$count" = 4 "instances of the Kubernetes-63-char warning"
- fi
-
run_podman rm $cname1 $cname2
run_podman pod rm $pname
run_podman rmi $(pause_image)
diff --git a/test/system/helpers.bash b/test/system/helpers.bash
index f2eb3016c..b0d4b526a 100644
--- a/test/system/helpers.bash
+++ b/test/system/helpers.bash
@@ -894,5 +894,59 @@ function _podman_commands() {
awk '/^Available Commands:/{ok=1;next}/^Options:/{ok=0}ok { print $1 }' <<<"$output" | grep .
}
+###############################
+# _build_health_check_image # Builds a container image with a configured health check
+###############################
+#
+# The health check will fail once the /uh-oh file exists.
+#
+# First argument is the desired name of the image
+# Second argument, if present and non-null, forces removal of the /uh-oh file once the check failed; this way the container can be restarted
+#
+
+function _build_health_check_image {
+ local imagename="$1"
+ local cleanfile=""
+
+ if [[ ! -z "$2" ]]; then
+ cleanfile="rm -f /uh-oh"
+ fi
+ # Create an image with a healthcheck script; said script will
+ # pass until the file /uh-oh gets created (by us, via exec)
+ cat >${PODMAN_TMPDIR}/healthcheck <<EOF
+#!/bin/sh
+
+if test -e /uh-oh; then
+ echo "Uh-oh on stdout!"
+ echo "Uh-oh on stderr!" >&2
+ ${cleanfile}
+ exit 1
+else
+ echo "Life is Good on stdout"
+ echo "Life is Good on stderr" >&2
+ exit 0
+fi
+EOF
+
+ cat >${PODMAN_TMPDIR}/entrypoint <<EOF
+#!/bin/sh
+
+trap 'echo Received SIGTERM, finishing; exit' SIGTERM; echo WAITING; while :; do sleep 0.1; done
+EOF
+
+ cat >${PODMAN_TMPDIR}/Containerfile <<EOF
+FROM $IMAGE
+
+COPY healthcheck /healthcheck
+COPY entrypoint /entrypoint
+
+RUN chmod 755 /healthcheck /entrypoint
+
+CMD ["/entrypoint"]
+EOF
+
+ run_podman build -t $imagename ${PODMAN_TMPDIR}
+}
+
# END miscellaneous tools
###############################################################################
diff --git a/test/system/helpers.systemd.bash b/test/system/helpers.systemd.bash
index d9abc087d..afbab6e08 100644
--- a/test/system/helpers.systemd.bash
+++ b/test/system/helpers.systemd.bash
@@ -32,3 +32,17 @@ journalctl() {
systemd-run() {
command systemd-run $_DASHUSER "$@";
}
+
+install_kube_template() {
+ # If running from a podman source directory, build and use the source
+ # version of the play-kube-@ unit file
+ unit_name="podman-kube@.service"
+ unit_file="contrib/systemd/system/${unit_name}"
+ if [[ -e ${unit_file}.in ]]; then
+ echo "# [Building & using $unit_name from source]" >&3
+ # Force regenerating unit file (existing one may have /usr/bin path)
+ rm -f $unit_file
+ BINDIR=$(dirname $PODMAN) make $unit_file
+ cp $unit_file $UNIT_DIR/$unit_name
+ fi
+}