diff options
Diffstat (limited to 'test')
35 files changed, 689 insertions, 145 deletions
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at index 383c527b4..cfd6aab33 100644 --- a/test/apiv2/20-containers.at +++ b/test/apiv2/20-containers.at @@ -16,7 +16,12 @@ podman pull $ENV_WORKDIR_IMG &>/dev/null # Ensure clean slate podman rm -a -f &>/dev/null -t GET "libpod/containers/json (at start: clean slate)" 200 length=0 +t GET "libpod/containers/json (at start: clean slate)" 200 \ + "[]" \ + length=0 +# check content type: https://github.com/containers/podman/issues/14647 +response_headers=$(cat "$WORKDIR/curl.headers.out") +like "$response_headers" ".*Content-Type: application/json.*" "header does not contain application/json" # Regression test for #12904 (race condition in logging code) mytext="hi-there-$(random_string 15)" @@ -95,6 +100,17 @@ fi t DELETE libpod/containers/$cid 200 .[0].Id=$cid +# Issue #14676: make sure the stats show the memory limit specified for the container +if root; then + CTRNAME=ctr-with-limit + podman run --name $CTRNAME -d -m 512m -v /tmp:/tmp $IMAGE top + + t GET libpod/containers/$CTRNAME/stats?stream=false 200 \ + .memory_stats.limit=536870912 + + podman rm -f $CTRNAME +fi + # Issue #6799: it should be possible to start a container, even w/o args. t POST libpod/containers/create?name=test_noargs Image=${IMAGE} 201 \ .Id~[0-9a-f]\\{64\\} diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at index 4aad4563d..fcff26521 100644 --- a/test/apiv2/35-networks.at +++ b/test/apiv2/35-networks.at @@ -78,8 +78,8 @@ t GET networks?filters="{\"id\":[\"$network1_id\"]}" 200 \ .[0].Name=network1 \ .[0].Id=$network1_id # invalid filter -t GET networks?filters='{"dangling":["1"]}' 500 \ - .cause='invalid filter "dangling"' +t GET networks?filters='{"dangling":["true","0"]}' 500 \ + .cause="got more than one value for filter key \"dangling\"" # (#9293 with no networks the endpoint should return empty array instead of null) t GET networks?filters='{"name":["doesnotexists"]}' 200 \ "[]" diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2 index 8ecc2aa2d..25f648d93 100755 --- a/test/apiv2/test-apiv2 +++ b/test/apiv2/test-apiv2 @@ -380,6 +380,17 @@ function start_service() { die "Cannot start service on non-localhost ($HOST)" fi + # FIXME: EXPERIMENTAL: 2022-06-13: podman rootless needs a namespace. If + # system-service is the first podman command run (as is the case in CI) + # this will happen as a fork-exec, where the parent podman creates the + # namespace and the child is the server. Then, when stop_service() kills + # the parent, the child (server) happily stays alive and ruins subsequent + # tests that try to restart service with different settings. + # Workaround: run an unshare to get namespaces initialized. + if [[ $(id -u) != 0 ]]; then + $PODMAN_BIN unshare true + fi + $PODMAN_BIN \ --root $WORKDIR/server_root --syslog=true \ system service \ @@ -387,6 +398,7 @@ function start_service() { tcp:127.0.0.1:$PORT \ &> $WORKDIR/server.log & service_pid=$! + echo "# started service, pid $service_pid" wait_for_port $HOST $PORT } @@ -396,7 +408,14 @@ function stop_service() { if [[ -n $service_pid ]]; then kill $service_pid || : wait $service_pid || : + echo "# stopped service, pid $service_pid" fi + service_pid= + + if { exec 3<> /dev/tcp/$HOST/$PORT; } &>/dev/null; then + echo "# WARNING: stop_service: Service still running on port $PORT" + fi + } #################### @@ -468,6 +487,7 @@ function start_registry() { ${REGISTRY_IMAGE} wait_for_port localhost $REGISTRY_PORT 10 + echo "# started registry (auth=$auth) on port $PORT" } function stop_registry() { @@ -482,6 +502,7 @@ function stop_registry() { if [[ "$1" = "--cleanup" ]]; then podman $OPTS rmi -f -a fi + echo "# stopped registry on port $PORT" fi REGISTRY_PORT= diff --git a/test/buildah-bud/apply-podman-deltas b/test/buildah-bud/apply-podman-deltas index 50db0255e..0b691dd0e 100755 --- a/test/buildah-bud/apply-podman-deltas +++ b/test/buildah-bud/apply-podman-deltas @@ -61,7 +61,12 @@ function _skip() { local skip=$1; shift local reason=$1; shift - # All further arguments are test names + # All further arguments are test names. Make sure we're invoked with some! + if [[ -z "$*" ]]; then + echo "$ME: FATAL: Invalid use of '${FUNCNAME[1]}' at line ${BASH_LINENO[1]}: missing test-name argument(s)." >&2 + exit 1 + fi + for t in "$@"; do if fgrep -qx "@test \"$t\" {" $BUD; then $ECHO "@test \"$t\" : $skip \"$reason\"" @@ -150,13 +155,7 @@ errmsg "checking authfile: stat /tmp/nonexistent: no such file or directory" \ ############################################################################### # BEGIN tests that don't make sense under podman due to fundamental differences -# TODO -# Normally, when buildah exits 1 on error, podman exits 125. -# These tests are the exception. They exit 1 under podman. -skip "these tests exit 1 under podman, not 125" \ - "bud with --add-host" \ - "bud - invalid runtime flags test" - +# Fails with "Error: no context directory and no Containerfile specified" skip "does not work under podman" \ "bud without any arguments should succeed" @@ -167,8 +166,9 @@ skip "does not work under podman" \ skip "FIXME FIXME FIXME: argument-order incompatible with podman" \ "bud-squash-hardlinks" -skip "FIXME FIXME FIXME: this passes on Ed's laptop, fails in CI??" \ - "bud-multi-stage-nocache-nocommit" +# Fails with "Error: context must be a directory: /path/to/Dockerfile" +skip "podman-build fails with 'context must be a directory'" \ + "bud with specified context should succeed if context contains existing Dockerfile" ############################################################################### # BEGIN tests which are skipped because they make no sense under podman-remote @@ -220,8 +220,8 @@ skip_if_remote "--output option not implemented in podman-remote" \ # https://github.com/containers/podman/issues/14544 skip_if_remote "logfile not implemented on remote" "bud-logfile-with-split-logfile-by-platform" -# https://github.com/containers/podman/issues/14547 -skip_if_remote "omit-history not implemented on remote" "build-with-omit-history-to-true should not add history" +skip_if_remote "envariables do not automatically work with -remote." \ + "build proxy" ############################################################################### # BEGIN tests which are skipped due to actual podman or podman-remote bugs. @@ -235,10 +235,12 @@ skip_if_remote "FIXME FIXME FIXME: find a way to clean up their podman calls" \ "bud with run should not leave mounts behind cleanup test" \ "bud with custom files in /run/ should persist cleanup test" -skip_if_remote "Do envariables work with -remote? Please look into this." \ - "build proxy" +# Under podman-remote, the "Ignoring <stdin>:5:2: error: #error" message +# is never seen. (Not even as stdout/stderr on the server; Ed checked). +skip_if_remote "FIXME FIXME FIXME: 'Ignoring' warning is never seen" \ + "bud with preprocessor error" +# END tests which are skipped due to actual podman or podman-remote bugs. ############################################################################### -# Done. exit $RC diff --git a/test/buildah-bud/buildah-tests.diff b/test/buildah-bud/buildah-tests.diff index 6fa36d904..399042240 100644 --- a/test/buildah-bud/buildah-tests.diff +++ b/test/buildah-bud/buildah-tests.diff @@ -1,15 +1,15 @@ -From 8a8fa1a75e0fa3261263afbc8c2504feb430df6a Mon Sep 17 00:00:00 2001 +From 6508e3df2a129554fdf8336d8a6f0cdcc6fd4832 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 Signed-off-by: Ed Santiago <santiago@redhat.com> --- - tests/helpers.bash | 69 ++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 66 insertions(+), 3 deletions(-) + tests/helpers.bash | 70 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/tests/helpers.bash b/tests/helpers.bash -index e3087063..b3a8f5ee 100644 +index e3087063..178a486e 100644 --- a/tests/helpers.bash +++ b/tests/helpers.bash @@ -51,6 +51,23 @@ EOF @@ -60,13 +60,13 @@ index e3087063..b3a8f5ee 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,35 @@ function run_buildah() { +@@ -247,8 +274,36 @@ function run_buildah() { --retry) retry=3; shift;; # retry network flakes esac + local podman_or_buildah=${BUILDAH_BINARY} + local _opts="${ROOTDIR_OPTS} ${BUILDAH_REGISTRY_OPTS}" -+ if [[ $1 == "build" || $1 == "build-using-dockerfile" ]]; then ++ if [[ $1 == "build" || $1 == "build-using-dockerfile" || $1 == "bud" ]]; then + shift + # podman defaults to --layers=true; buildah to --false. + # If command line includes explicit --layers, leave it untouched, @@ -82,10 +82,11 @@ index e3087063..b3a8f5ee 100644 + _opts= + fi + -+ # podman always exits 125 where buildah exits 1 or 2 (or, in the -+ # case of git, 128, which is a bug in git, but I won't harp on that). ++ # Special case: there's one test that invokes git in such ++ # a way that it exits 128 (which IMO is a bug in git). ++ # podman exits 125 in that case. + case $expected_rc in -+ 1|2|128) expected_rc=125 ;; ++ 128) expected_rc=125 ;; + esac + fi + local cmd_basename=$(basename ${podman_or_buildah}) @@ -97,7 +98,7 @@ index e3087063..b3a8f5ee 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 +316,8 @@ function run_buildah() { +@@ -262,8 +317,8 @@ function run_buildah() { retry=$(( retry - 1 )) # stdout is only emitted upon error; this echo is to help a debugger @@ -108,7 +109,7 @@ index e3087063..b3a8f5ee 100644 # without "quotes", multiple lines are glommed together into one if [ -n "$output" ]; then echo "$output" -@@ -595,6 +649,15 @@ function skip_if_no_docker() { +@@ -595,6 +650,15 @@ function skip_if_no_docker() { fi } @@ -125,5 +126,5 @@ index e3087063..b3a8f5ee 100644 daemondir=${TEST_SCRATCH_DIR}/git-daemon mkdir -p ${daemondir}/repo -- -2.35.1 +2.35.3 diff --git a/test/buildah-bud/run-buildah-bud-tests b/test/buildah-bud/run-buildah-bud-tests index eb8de5618..4ff062496 100755 --- a/test/buildah-bud/run-buildah-bud-tests +++ b/test/buildah-bud/run-buildah-bud-tests @@ -93,6 +93,12 @@ fi # From here on out, any error is fatal set -e +# Run sudo early, to refresh the credentials cache. This is a NOP under CI, +# but might be appreciated by developers who run this script, step away +# during the git-checkout-buildah step, then come back twenty minutes later +# to an expired sudo prompt and no tests have run. +sudo --validate + # Before pulling buildah (while still cd'ed to podman repo), try to determine # if this is a PR, and if so if it's a revendoring of buildah. We use this to # try to offer a helpful hint on failure. diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index 1da199714..1fa67e9ba 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -23,10 +23,31 @@ import ( func getRunString(input []string) []string { // CRIU does not work with seccomp correctly on RHEL7 : seccomp=unconfined - runString := []string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", "--ip", GetRandomIPAddress()} + runString := []string{"run", "--security-opt", "seccomp=unconfined", "-d", "--ip", GetRandomIPAddress()} return append(runString, input...) } +// FIXME FIXME FIXME: workaround for #14653, please remove this function +// and all calls to it once that bug is fixed. +func fixmeFixme14653(podmanTest *PodmanTestIntegration, cid string) { + if !IsRemote() { + // Race condition only affects podman-remote + return + } + + // Wait for container to truly go away + for i := 0; i < 5; i++ { + ps := podmanTest.Podman([]string{"container", "exists", cid}) + ps.WaitWithDefaultTimeout() + if ps.ExitCode() == 1 { + // yay, it's gone + return + } + time.Sleep(time.Second) + } + // Fall through. Container still exists, but return anyway. +} + var _ = Describe("Podman checkpoint", func() { var ( tempdir string @@ -478,6 +499,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -530,6 +552,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -548,6 +571,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -566,6 +590,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -584,6 +609,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -645,6 +671,7 @@ var _ = Describe("Podman checkpoint", func() { result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -694,6 +721,7 @@ var _ = Describe("Podman checkpoint", func() { result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -735,6 +763,7 @@ var _ = Describe("Podman checkpoint", func() { result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -772,6 +801,7 @@ var _ = Describe("Podman checkpoint", func() { result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -821,6 +851,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -890,6 +921,7 @@ var _ = Describe("Podman checkpoint", func() { result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", checkpointFileName}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -1044,6 +1076,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -1140,6 +1173,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).To(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) Expect(podmanTest.NumberOfContainers()).To(Equal(1)) @@ -1252,6 +1286,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -1296,6 +1331,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -1489,6 +1525,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -1573,6 +1610,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) @@ -1651,6 +1689,7 @@ var _ = Describe("Podman checkpoint", func() { // As the container has been started with '--rm' it will be completely // cleaned up after checkpointing. Expect(result).Should(Exit(0)) + fixmeFixme14653(podmanTest, cid) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) Expect(podmanTest.NumberOfContainers()).To(Equal(0)) diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index db194b777..261db8a9a 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -41,7 +41,7 @@ var ( CGROUP_MANAGER = "systemd" //nolint:revive,stylecheck RESTORE_IMAGES = []string{ALPINE, BB, nginx} //nolint:revive,stylecheck defaultWaitTimeout = 90 - CGROUPSV2, _ = cgroups.IsCgroup2UnifiedMode() //nolint:revive,stylecheck + CGROUPSV2, _ = cgroups.IsCgroup2UnifiedMode() ) // PodmanTestIntegration struct for command line options @@ -322,7 +322,7 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration { } } - // Setup registries.conf ENV variable + // Set up registries.conf ENV variable p.setDefaultRegistriesConfigEnv() // Rewrite the PodmanAsUser function p.PodmanMakeOptions = p.makeOptions diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go index 6fd88753b..85cc5023c 100644 --- a/test/e2e/create_staticip_test.go +++ b/test/e2e/create_staticip_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman create with --ip flag", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - // Cleanup the CNI networks used by the tests + // Clean up the CNI networks used by the tests os.RemoveAll("/var/lib/cni/networks/podman") }) diff --git a/test/e2e/create_staticmac_test.go b/test/e2e/create_staticmac_test.go index f02d9c88b..32deb04a8 100644 --- a/test/e2e/create_staticmac_test.go +++ b/test/e2e/create_staticmac_test.go @@ -25,7 +25,7 @@ var _ = Describe("Podman run with --mac-address flag", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - // Cleanup the CNI networks used by the tests + // Clean up the CNI networks used by the tests os.RemoveAll("/var/lib/cni/networks/podman") }) diff --git a/test/e2e/image_scp_test.go b/test/e2e/image_scp_test.go index 2ad3cc75e..53681f05b 100644 --- a/test/e2e/image_scp_test.go +++ b/test/e2e/image_scp_test.go @@ -22,12 +22,10 @@ var _ = Describe("podman image scp", func() { ) BeforeEach(func() { - ConfPath.Value, ConfPath.IsSet = os.LookupEnv("CONTAINERS_CONF") conf, err := ioutil.TempFile("", "containersconf") - if err != nil { - panic(err) - } + Expect(err).ToNot(HaveOccurred()) + os.Setenv("CONTAINERS_CONF", conf.Name()) tempdir, err = CreateTempDirInTempDir() if err != nil { @@ -57,7 +55,7 @@ var _ = Describe("podman image scp", func() { } scp := podmanTest.Podman([]string{"image", "scp", "FOOBAR"}) scp.WaitWithDefaultTimeout() - Expect(scp).To(ExitWithError()) + Expect(scp).Should(ExitWithError()) }) It("podman image scp with proper connection", func() { @@ -67,27 +65,28 @@ var _ = Describe("podman image scp", func() { cmd := []string{"system", "connection", "add", "--default", "QA", - "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + "ssh://root@podman.test:2222/run/podman/podman.sock", } session := podmanTest.Podman(cmd) session.WaitWithDefaultTimeout() - Expect(session).To(Exit(0)) + Expect(session).Should(Exit(0)) cfg, err := config.ReadCustomConfig() Expect(err).ShouldNot(HaveOccurred()) - Expect(cfg.Engine).To(HaveField("ActiveService", "QA")) + Expect(cfg.Engine).Should(HaveField("ActiveService", "QA")) Expect(cfg.Engine.ServiceDestinations).To(HaveKeyWithValue("QA", config.Destination{ - URI: "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + URI: "ssh://root@podman.test:2222/run/podman/podman.sock", }, )) scp := podmanTest.Podman([]string{"image", "scp", ALPINE, "QA::"}) - scp.Wait(45) + scp.WaitWithDefaultTimeout() // exit with error because we cannot make an actual ssh connection // This tests that the input we are given is validated and prepared correctly - // The error given should either be a missing image (due to testing suite complications) or a i/o timeout on ssh - Expect(scp).To(ExitWithError()) + // The error given should either be a missing image (due to testing suite complications) or a no such host timeout on ssh + Expect(scp).Should(ExitWithError()) + Expect(scp.ErrorToString()).Should(ContainSubstring("no such host")) }) diff --git a/test/e2e/manifest_test.go b/test/e2e/manifest_test.go index 88ccdc87d..2fffc9118 100644 --- a/test/e2e/manifest_test.go +++ b/test/e2e/manifest_test.go @@ -91,6 +91,27 @@ var _ = Describe("Podman manifest", func() { Expect(session.OutputToString()).To(ContainSubstring(imageListARM64InstanceDigest)) }) + It("add with new version", func() { + // Following test must pass for both podman and podman-remote + session := podmanTest.Podman([]string{"manifest", "create", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + id := strings.TrimSpace(string(session.Out.Contents())) + + session = podmanTest.Podman([]string{"manifest", "inspect", id}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"manifest", "add", "--os-version", "7.7.7", "foo", imageListInstance}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"manifest", "inspect", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring("7.7.7")) + }) + It("tag", func() { session := podmanTest.Podman([]string{"manifest", "create", "foobar"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index 715455521..2fdd62f7e 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -163,6 +163,26 @@ var _ = Describe("Podman network", func() { Expect(session.OutputToString()).To(Not(ContainSubstring(name))) }) + It("podman network list --filter dangling", func() { + name, path := generateNetworkConfig(podmanTest) + defer removeConf(path) + + session := podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=true"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring(name)) + + session = podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=false"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).NotTo(ContainSubstring(name)) + + session = podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=foo"}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) + Expect(session.ErrorToString()).To(ContainSubstring(`invalid dangling filter value "foo"`)) + }) + It("podman network ID test", func() { net := "networkIDTest" // the network id should be the sha256 hash of the network name diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go index 402719de2..566aca07e 100644 --- a/test/e2e/pause_test.go +++ b/test/e2e/pause_test.go @@ -82,7 +82,7 @@ var _ = Describe("Podman pause", func() { // check we can read stats for a paused container result = podmanTest.Podman([]string{"stats", "--no-stream", cid}) result.WaitWithDefaultTimeout() - Expect(result).To(ExitWithError()) + Expect(result).Should(Exit(0)) }) It("podman pause a running container by id", func() { diff --git a/test/e2e/pod_clone_test.go b/test/e2e/pod_clone_test.go new file mode 100644 index 000000000..b90bf10da --- /dev/null +++ b/test/e2e/pod_clone_test.go @@ -0,0 +1,158 @@ +package integration + +import ( + "os" + + . "github.com/containers/podman/v4/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("Podman pod clone", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + SkipIfRemote("podman pod clone is not supported in remote") + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + + }) + + It("podman pod clone basic test", func() { + create := podmanTest.Podman([]string{"pod", "create", "--name", "1"}) + create.WaitWithDefaultTimeout() + Expect(create).To(Exit(0)) + + run := podmanTest.Podman([]string{"run", "--pod", "1", "-dt", ALPINE}) + run.WaitWithDefaultTimeout() + Expect(run).To(Exit(0)) + + clone := podmanTest.Podman([]string{"pod", "clone", create.OutputToString()}) + clone.WaitWithDefaultTimeout() + Expect(clone).To(Exit(0)) + + podInspect := podmanTest.Podman([]string{"pod", "inspect", clone.OutputToString()}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect).To(Exit(0)) + data := podInspect.InspectPodToJSON() + Expect(data.Name).To(ContainSubstring("-clone")) + + podStart := podmanTest.Podman([]string{"pod", "start", clone.OutputToString()}) + podStart.WaitWithDefaultTimeout() + Expect(podStart).To(Exit(0)) + + podInspect = podmanTest.Podman([]string{"pod", "inspect", clone.OutputToString()}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect).To(Exit(0)) + data = podInspect.InspectPodToJSON() + Expect(data.Containers[1].State).To(ContainSubstring("running")) // make sure non infra ctr is running + }) + + It("podman pod clone renaming test", func() { + create := podmanTest.Podman([]string{"pod", "create", "--name", "1"}) + create.WaitWithDefaultTimeout() + Expect(create).To(Exit(0)) + + clone := podmanTest.Podman([]string{"pod", "clone", "--name", "2", create.OutputToString()}) + clone.WaitWithDefaultTimeout() + Expect(clone).To(Exit(0)) + + podInspect := podmanTest.Podman([]string{"pod", "inspect", clone.OutputToString()}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect).To(Exit(0)) + data := podInspect.InspectPodToJSON() + Expect(data.Name).To(ContainSubstring("2")) + + podStart := podmanTest.Podman([]string{"pod", "start", clone.OutputToString()}) + podStart.WaitWithDefaultTimeout() + Expect(podStart).To(Exit(0)) + }) + + It("podman pod clone start test", func() { + create := podmanTest.Podman([]string{"pod", "create", "--name", "1"}) + create.WaitWithDefaultTimeout() + Expect(create).To(Exit(0)) + + clone := podmanTest.Podman([]string{"pod", "clone", "--start", create.OutputToString()}) + clone.WaitWithDefaultTimeout() + Expect(clone).To(Exit(0)) + + podInspect := podmanTest.Podman([]string{"pod", "inspect", clone.OutputToString()}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect).To(Exit(0)) + data := podInspect.InspectPodToJSON() + Expect(data.State).To(ContainSubstring("Running")) + + }) + + It("podman pod clone destroy test", func() { + create := podmanTest.Podman([]string{"pod", "create", "--name", "1"}) + create.WaitWithDefaultTimeout() + Expect(create).To(Exit(0)) + + clone := podmanTest.Podman([]string{"pod", "clone", "--destroy", create.OutputToString()}) + clone.WaitWithDefaultTimeout() + Expect(clone).To(Exit(0)) + + podInspect := podmanTest.Podman([]string{"pod", "inspect", create.OutputToString()}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect).ToNot(Exit(0)) + }) + + It("podman pod clone infra option test", func() { + // proof of concept that all currently tested infra options work since + + volName := "testVol" + volCreate := podmanTest.Podman([]string{"volume", "create", volName}) + volCreate.WaitWithDefaultTimeout() + Expect(volCreate).Should(Exit(0)) + + podName := "testPod" + podCreate := podmanTest.Podman([]string{"pod", "create", "--name", podName}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate).Should(Exit(0)) + + podClone := podmanTest.Podman([]string{"pod", "clone", "--volume", volName + ":/tmp1", podName}) + podClone.WaitWithDefaultTimeout() + Expect(podClone).Should(Exit(0)) + + podInspect := podmanTest.Podman([]string{"pod", "inspect", "testPod-clone"}) + podInspect.WaitWithDefaultTimeout() + Expect(podInspect).Should(Exit(0)) + data := podInspect.InspectPodToJSON() + Expect(data.Mounts[0]).To(HaveField("Name", volName)) + }) + + It("podman pod clone --shm-size", func() { + podCreate := podmanTest.Podman([]string{"pod", "create"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate).Should(Exit(0)) + + podClone := podmanTest.Podman([]string{"pod", "clone", "--shm-size", "10mb", podCreate.OutputToString()}) + podClone.WaitWithDefaultTimeout() + Expect(podClone).Should(Exit(0)) + + run := podmanTest.Podman([]string{"run", "-it", "--pod", podClone.OutputToString(), ALPINE, "mount"}) + run.WaitWithDefaultTimeout() + Expect(run).Should(Exit(0)) + t, strings := run.GrepString("shm on /dev/shm type tmpfs") + Expect(t).To(BeTrue()) + Expect(strings[0]).Should(ContainSubstring("size=10240k")) + }) + +}) diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index 4919cc670..a48193e90 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -1134,4 +1134,27 @@ ENTRYPOINT ["sleep","99999"] Expect(session.OutputToString()).Should(ContainSubstring("/vol2")) }) + It("podman pod create --shm-size", func() { + podCreate := podmanTest.Podman([]string{"pod", "create", "--shm-size", "10mb"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate).Should(Exit(0)) + + run := podmanTest.Podman([]string{"run", "-it", "--pod", podCreate.OutputToString(), ALPINE, "mount"}) + run.WaitWithDefaultTimeout() + Expect(run).Should(Exit(0)) + t, strings := run.GrepString("shm on /dev/shm type tmpfs") + Expect(t).To(BeTrue()) + Expect(strings[0]).Should(ContainSubstring("size=10240k")) + }) + + It("podman pod create --shm-size and --ipc=host conflict", func() { + podCreate := podmanTest.Podman([]string{"pod", "create", "--shm-size", "10mb"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate).Should(Exit(0)) + + run := podmanTest.Podman([]string{"run", "-dt", "--pod", podCreate.OutputToString(), "--ipc", "host", ALPINE}) + run.WaitWithDefaultTimeout() + Expect(run).ShouldNot(Exit(0)) + }) + }) diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go index 75adf1724..119c8d41e 100644 --- a/test/e2e/prune_test.go +++ b/test/e2e/prune_test.go @@ -258,6 +258,29 @@ var _ = Describe("Podman prune", func() { Expect(pods.OutputToStringArray()).To(HaveLen(2)) }) + It("podman system prune networks", func() { + // About netavark network backend test. + session := podmanTest.Podman([]string{"network", "create", "test"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"system", "prune", "-f"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + // Default network should exists. + session = podmanTest.Podman([]string{"network", "ls", "-q", "--filter", "name=^podman$"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToStringArray()).To(HaveLen(1)) + + // Remove all unused networks. + session = podmanTest.Podman([]string{"network", "ls", "-q", "--filter", "name=^test$"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToStringArray()).To(HaveLen(0)) + }) + It("podman system prune - pod,container stopped", func() { session := podmanTest.Podman([]string{"pod", "create"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go index af3f98d4b..09fb4e03c 100644 --- a/test/e2e/run_staticip_test.go +++ b/test/e2e/run_staticip_test.go @@ -28,7 +28,7 @@ var _ = Describe("Podman run with --ip flag", func() { } podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - // Cleanup the CNI networks used by the tests + // Clean up the CNI networks used by the tests os.RemoveAll("/var/lib/cni/networks/podman") }) diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 1c0480407..edb657695 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -908,6 +908,20 @@ USER testuser`, fedoraMinimal) Expect(session.OutputToString()).To(Equal(perms)) }) + It("podman run with -v $SRC:/run does not create /run/.containerenv", func() { + mountSrc := filepath.Join(podmanTest.TempDir, "vol-test1") + err := os.MkdirAll(mountSrc, 0755) + Expect(err).To(BeNil()) + + session := podmanTest.Podman([]string{"run", "-v", mountSrc + ":/run", ALPINE, "true"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + // the file should not have been created + _, err = os.Stat(filepath.Join(mountSrc, ".containerenv")) + Expect(err).To(Not(BeNil())) + }) + It("podman volume with uid and gid works", func() { volName := "testVol" volCreate := podmanTest.Podman([]string{"volume", "create", "--opt", "o=uid=1000", volName}) @@ -939,4 +953,32 @@ USER testuser`, fedoraMinimal) Expect(volMount).Should(Exit(0)) Expect(volMount.OutputToString()).To(Equal("1000:1000")) }) + + It("podman run -v with a relative dir", func() { + mountPath := filepath.Join(podmanTest.TempDir, "vol") + err = os.Mkdir(mountPath, 0755) + Expect(err).ToNot(HaveOccurred()) + defer func() { + err := os.RemoveAll(mountPath) + Expect(err).ToNot(HaveOccurred()) + }() + + f, err := os.CreateTemp(mountPath, "podman") + Expect(err).ToNot(HaveOccurred()) + + cwd, err := os.Getwd() + Expect(err).ToNot(HaveOccurred()) + + err = os.Chdir(mountPath) + Expect(err).ToNot(HaveOccurred()) + defer func() { + err := os.Chdir(cwd) + Expect(err).ToNot(HaveOccurred()) + }() + + run := podmanTest.Podman([]string{"run", "-it", "--security-opt", "label=disable", "-v", "./:" + dest, ALPINE, "ls", dest}) + run.WaitWithDefaultTimeout() + Expect(run).Should(Exit(0)) + Expect(run.OutputToString()).Should(ContainSubstring(strings.TrimLeft("/vol/", f.Name()))) + }) }) diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go index b43a81cd3..3000a819f 100644 --- a/test/e2e/stats_test.go +++ b/test/e2e/stats_test.go @@ -236,4 +236,15 @@ var _ = Describe("Podman stats", func() { Expect(customLimit).To(BeNumerically("<", defaultLimit)) }) + + It("podman stats with a container that is not running", func() { + ctr := "created_container" + session := podmanTest.Podman([]string{"create", "--name", ctr, ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"stats", "--no-stream", ctr}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + }) }) diff --git a/test/e2e/system_connection_test.go b/test/e2e/system_connection_test.go index 2228c23b2..baa31424b 100644 --- a/test/e2e/system_connection_test.go +++ b/test/e2e/system_connection_test.go @@ -47,9 +47,7 @@ var _ = Describe("podman system connection", func() { } f := CurrentGinkgoTestDescription() - _, _ = GinkgoWriter.Write( - []byte( - fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds()))) + processTestResult(f) }) Context("without running API service", func() { @@ -58,7 +56,7 @@ var _ = Describe("podman system connection", func() { "--default", "--identity", "~/.ssh/id_rsa", "QA", - "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + "ssh://root@podman.test:2222/run/podman/podman.sock", } session := podmanTest.Podman(cmd) session.WaitWithDefaultTimeout() @@ -67,10 +65,10 @@ var _ = Describe("podman system connection", func() { cfg, err := config.ReadCustomConfig() Expect(err).ShouldNot(HaveOccurred()) - Expect(cfg).To(HaveActiveService("QA")) + Expect(cfg).Should(HaveActiveService("QA")) Expect(cfg).Should(VerifyService( "QA", - "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + "ssh://root@podman.test:2222/run/podman/podman.sock", "~/.ssh/id_rsa", )) @@ -82,7 +80,7 @@ var _ = Describe("podman system connection", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - Expect(config.ReadCustomConfig()).To(HaveActiveService("QE")) + Expect(config.ReadCustomConfig()).Should(HaveActiveService("QE")) }) It("add UDS", func() { @@ -141,7 +139,7 @@ var _ = Describe("podman system connection", func() { "--default", "--identity", "~/.ssh/id_rsa", "QA", - "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + "ssh://root@podman.test:2222/run/podman/podman.sock", }) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -155,8 +153,8 @@ var _ = Describe("podman system connection", func() { cfg, err := config.ReadCustomConfig() Expect(err).ShouldNot(HaveOccurred()) - Expect(cfg.Engine.ActiveService).To(BeEmpty()) - Expect(cfg.Engine.ServiceDestinations).To(BeEmpty()) + Expect(cfg.Engine.ActiveService).Should(BeEmpty()) + Expect(cfg.Engine.ServiceDestinations).Should(BeEmpty()) } }) @@ -165,7 +163,7 @@ var _ = Describe("podman system connection", func() { "--default", "--identity", "~/.ssh/id_rsa", "QA", - "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + "ssh://root@podman.test:2222/run/podman/podman.sock", }) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -187,7 +185,7 @@ var _ = Describe("podman system connection", func() { "--default", "--identity", "~/.ssh/id_rsa", name, - "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + "ssh://root@podman.test:2222/run/podman/podman.sock", } session := podmanTest.Podman(cmd) session.WaitWithDefaultTimeout() @@ -247,7 +245,7 @@ var _ = Describe("podman system connection", func() { // podman-remote commands will be executed by ginkgo directly. SkipIfContainerized("sshd is not available when running in a container") SkipIfRemote("connection heuristic requires both podman and podman-remote binaries") - SkipIfNotRootless(fmt.Sprintf("FIXME: setup ssh keys when root. uid(%d) euid(%d)", os.Getuid(), os.Geteuid())) + SkipIfNotRootless(fmt.Sprintf("FIXME: set up ssh keys when root. uid(%d) euid(%d)", os.Getuid(), os.Geteuid())) SkipIfSystemdNotRunning("cannot test connection heuristic if systemd is not running") SkipIfNotActive("sshd", "cannot test connection heuristic if sshd is not running") }) diff --git a/test/e2e/systemd_activate_test.go b/test/e2e/systemd_activate_test.go index aeea4f932..240139b98 100644 --- a/test/e2e/systemd_activate_test.go +++ b/test/e2e/systemd_activate_test.go @@ -4,9 +4,11 @@ import ( "errors" "fmt" "io/fs" + "net" "os" "os/exec" "path/filepath" + "strconv" "syscall" "time" @@ -21,6 +23,7 @@ var _ = Describe("Systemd activate", func() { var tempDir string var err error var podmanTest *PodmanTestIntegration + var activate string BeforeEach(func() { tempDir, err = testUtils.CreateTempDirInTempDir() @@ -31,17 +34,10 @@ var _ = Describe("Systemd activate", func() { podmanTest = PodmanTestCreate(tempDir) podmanTest.Setup() - }) - AfterEach(func() { - podmanTest.Cleanup() - processTestResult(CurrentGinkgoTestDescription()) - }) - - It("stop podman.service", func() { SkipIfRemote("Testing stopped service requires both podman and podman-remote binaries") - activate, err := exec.LookPath("systemd-socket-activate") + activate, err = exec.LookPath("systemd-socket-activate") if err != nil { activate = "/usr/bin/systemd-socket-activate" } @@ -54,14 +50,22 @@ var _ = Describe("Systemd activate", func() { case err != nil: Skip(err.Error()) } + }) + AfterEach(func() { + podmanTest.Cleanup() + processTestResult(CurrentGinkgoTestDescription()) + }) + + It("stop podman.service", func() { // systemd-socket-activate does not support DNS lookups host := "127.0.0.1" port, err := podmanUtils.GetRandomPort() Expect(err).ToNot(HaveOccurred()) + addr := net.JoinHostPort(host, strconv.Itoa(port)) activateSession := testUtils.StartSystemExec(activate, []string{ - fmt.Sprintf("--listen=%s:%d", host, port), + "--listen", addr, podmanTest.PodmanBinary, "--root=" + filepath.Join(tempDir, "server_root"), "system", "service", @@ -71,7 +75,7 @@ var _ = Describe("Systemd activate", func() { // Curried functions for specialized podman calls podmanRemote := func(args ...string) *testUtils.PodmanSession { - args = append([]string{"--url", fmt.Sprintf("tcp://%s:%d", host, port)}, args...) + args = append([]string{"--url", "tcp://" + addr}, args...) return testUtils.SystemExec(podmanTest.RemotePodmanBinary, args) } @@ -103,4 +107,37 @@ var _ = Describe("Systemd activate", func() { Expect(abiSession).To(Exit(0)) Expect(abiSession.OutputToString()).To(Equal("true")) }) + + It("invalid systemd file descriptor", func() { + host := "127.0.0.1" + port, err := podmanUtils.GetRandomPort() + Expect(err).ToNot(HaveOccurred()) + + addr := net.JoinHostPort(host, strconv.Itoa(port)) + + // start systemd activation with datagram socket + activateSession := testUtils.StartSystemExec(activate, []string{ + "--datagram", "--listen", addr, + podmanTest.PodmanBinary, + "--root=" + filepath.Join(tempDir, "server_root"), + "system", "service", + "--time=0", + }) + Expect(activateSession.Exited).ShouldNot(Receive(), "Failed to start podman service") + + // we have to wait for systemd-socket-activate to become ready + time.Sleep(1 * time.Second) + + // now dial the socket to start podman + conn, err := net.Dial("udp", addr) + Expect(err).ToNot(HaveOccurred()) + defer conn.Close() + _, err = conn.Write([]byte("test")) + Expect(err).ToNot(HaveOccurred()) + + // wait for podman to exit + activateSession.Wait(10) + Expect(activateSession).To(Exit(125)) + Expect(activateSession.ErrorToString()).To(ContainSubstring("Error: unexpected fd received from systemd: cannot listen on it")) + }) }) diff --git a/test/framework/framework.go b/test/framework/framework.go index 57c6bda2a..26e8bf21c 100644 --- a/test/framework/framework.go +++ b/test/framework/framework.go @@ -37,7 +37,7 @@ func NilFunc(f *TestFramework) error { func (t *TestFramework) Setup() { // Global initialization for the whole framework goes in here - // Setup the actual test suite + // Set up the actual test suite gomega.Expect(t.setup(t)).To(gomega.Succeed()) } diff --git a/test/system/010-images.bats b/test/system/010-images.bats index 257508418..69ed1004c 100644 --- a/test/system/010-images.bats +++ b/test/system/010-images.bats @@ -158,6 +158,11 @@ Labels.created_at | 20[0-9-]\\\+T[0-9:]\\\+Z # start here because this is the first one, fix this problem. # You can (probably) ignore any subsequent failures showing '@sha' # in the error output. + # + # WARNING! This test is likely to fail for an hour or so after + # building a new testimage (via build-testimage script), because + # two consecutive 'podman images' may result in a one-minute + # difference in the "XX minutes ago" output. This is OK to ignore. run_podman images -a is "$output" "$images_baseline" "images -a, after pull: same as before" diff --git a/test/system/015-help.bats b/test/system/015-help.bats index 1356c99a0..dd5a7ed44 100644 --- a/test/system/015-help.bats +++ b/test/system/015-help.bats @@ -199,7 +199,7 @@ function check_help() { check_help # Test for regression of #7273 (spurious "--remote" help on output) - for helpopt in help --help; do + for helpopt in help --help -h; do run_podman $helpopt is "${lines[0]}" "Manage pods, containers and images" \ "podman $helpopt: first line of output" diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 241831257..56cf4f266 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -34,12 +34,8 @@ echo $rand | 0 | $rand # FIXME: The </dev/null is a hack, necessary because as of 2019-09 # podman-remote has a bug in which it silently slurps up stdin, # including the output of parse_table (i.e. tests to be run). - run_podman $expected_rc run $IMAGE "$@" </dev/null - - # FIXME: remove conditional once podman-remote issue #4096 is fixed - if ! is_remote; then - is "$output" "$expected_output" "podman run $cmd - output" - fi + run_podman $expected_rc run $IMAGE "$@" + is "$output" "$expected_output" "podman run $cmd - output" tests_run=$(expr $tests_run + 1) done < <(parse_table "$tests") @@ -380,17 +376,7 @@ json-file | f while read driver do_check; do msg=$(random_string 15) run_podman run --name myctr --log-driver $driver $IMAGE echo $msg - - # Simple output check - # Special case: 'json-file' emits a warning, the rest do not - # ...but with podman-remote the warning is on the server only - if [[ $do_check == 'f' ]] && ! is_remote; then # 'f' for 'fallback' - is "${lines[0]}" ".* level=error msg=\"json-file logging specified but not supported. Choosing k8s-file logging instead\"" \ - "Fallback warning emitted" - is "${lines[1]}" "$msg" "basic output sanity check (driver=$driver)" - else - is "$output" "$msg" "basic output sanity check (driver=$driver)" - fi + is "$output" "$msg" "basic output sanity check (driver=$driver)" # Simply confirm that podman preserved our argument as-is run_podman inspect --format '{{.HostConfig.LogConfig.Type}}' myctr @@ -470,10 +456,10 @@ json-file | f # dependent, we pick an obscure zone (+1245) that is unlikely to # collide with any of our testing environments. # - # To get a reference timestamp we run 'date' locally; note the explicit - # strftime() format. We can't use --iso=seconds because GNU date adds - # a colon to the TZ offset (eg -07:00) whereas alpine does not (-0700). - run date --date=@1600000000 +%Y-%m-%dT%H:%M:%S%z + # To get a reference timestamp we run 'date' locally. This requires + # that GNU date output matches that of alpine; this seems to be true + # as of testimage:20220615. + run date --date=@1600000000 --iso=seconds expect="$output" TZ=Pacific/Chatham run_podman run --rm --tz=local $IMAGE date -Iseconds -r $testfile is "$output" "$expect" "podman run with --tz=local, matches host" @@ -628,7 +614,8 @@ json-file | f run_podman image mount $IMAGE romount="$output" - run_podman run --rm --rootfs $romount echo "Hello world" + # FIXME FIXME FIXME: Remove :O once (if) #14504 is fixed! + run_podman run --rm --rootfs $romount:O echo "Hello world" is "$output" "Hello world" run_podman image unmount $IMAGE diff --git a/test/system/070-build.bats b/test/system/070-build.bats index b7e0ab447..9fddbaa21 100644 --- a/test/system/070-build.bats +++ b/test/system/070-build.bats @@ -496,7 +496,12 @@ Labels.$label_name | $label_value "image tree: third line" is "${lines[3]}" "Image Layers" \ "image tree: fourth line" - is "${lines[4]}" ".* ID: [0-9a-f]\{12\} Size: .* Top Layer of: \[$IMAGE]" \ + # FIXME: if #14536 is ever fixed, rebuild testimage & s/5/4/ below. + # Summary: this should be ${lines[4]}, not [5], and prior to 2022-06-15 + # it was. Unfortunately, a nightmarish bug interaction makes it impossible + # for us to use --squash-all on our testimage. Unless/until that bug is + # fixed, we have an extra layer that all we can do is ignore. + is "${lines[5]}" ".* ID: [0-9a-f]\{12\} Size: .* Top Layer of: \[$IMAGE]" \ "image tree: first layer line" is "${lines[-1]}" ".* ID: [0-9a-f]\{12\} Size: .* Top Layer of: \[localhost/build_test:latest]" \ "image tree: last layer line" @@ -757,7 +762,7 @@ EOF is "$output" "[no instance of 'Using cache']" "no cache used" fi - run_podman rmi -a --force + run_podman rmi -f build_test } # Caveat lector: this test was mostly copy-pasted from buildah in #9275. diff --git a/test/system/150-login.bats b/test/system/150-login.bats index 33b8438bf..dc902d5fe 100644 --- a/test/system/150-login.bats +++ b/test/system/150-login.bats @@ -314,7 +314,7 @@ function _test_skopeo_credential_sharing() { fi # Make sure socket is closed - if { exec 3<> /dev/tcp/127.0.0.1/${PODMAN_LOGIN_REGISTRY_PORT}; } &>/dev/null; then + if ! port_is_free $PODMAN_LOGIN_REGISTRY_PORT; then die "Socket still seems open" fi } diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index 404ad67ec..f597c0e0a 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -472,4 +472,30 @@ spec: run_podman pod rm $name-pod } +@test "pod resource limits" { + skip_if_remote "resource limits only implemented on non-remote" + if is_rootless; then + skip "only meaningful for rootful" + fi + + local name1="resources1" + run_podman --cgroup-manager=systemd pod create --name=$name1 --cpus=5 + run_podman --cgroup-manager=systemd pod start $name1 + run_podman pod inspect --format '{{.CgroupPath}}' $name1 + local path1="$output" + local actual1=$(< /sys/fs/cgroup/$path1/cpu.max) + is "$actual1" "500000 100000" "resource limits set properly" + run_podman pod --cgroup-manager=systemd rm -f $name1 + + local name2="resources2" + run_podman --cgroup-manager=cgroupfs pod create --cpus=5 --name=$name2 + run_podman --cgroup-manager=cgroupfs pod start $name2 + run_podman pod inspect --format '{{.CgroupPath}}' $name2 + local path2="$output" + local actual2=$(< /sys/fs/cgroup/$path2/cpu.max) + is "$actual2" "500000 100000" "resource limits set properly" + run_podman --cgroup-manager=cgroupfs pod rm $name2 + +} + # vim: filetype=sh diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats index 110d425d2..e251e8a6d 100644 --- a/test/system/250-systemd.bats +++ b/test/system/250-systemd.bats @@ -27,7 +27,6 @@ function teardown() { rm -f "$UNIT_FILE" systemctl daemon-reload fi - run_podman rmi -a basic_teardown } @@ -53,10 +52,17 @@ function service_setup() { # Helper to stop a systemd service running a container function service_cleanup() { - local status=$1 run systemctl stop "$SERVICE_NAME" assert $status -eq 0 "Error stopping systemd unit $SERVICE_NAME: $output" + # Regression test for #11304: confirm that unit stops into correct state + local expected_state="$1" + if [[ -n "$expected_state" ]]; then + run systemctl show --property=ActiveState "$SERVICE_NAME" + assert "$output" = "ActiveState=$expected_state" \ + "state of service after systemctl stop" + fi + run systemctl disable "$SERVICE_NAME" assert $status -eq 0 "Error disabling systemd unit $SERVICE_NAME: $output" @@ -88,26 +94,28 @@ function service_cleanup() { @test "podman autoupdate local" { # Note that the entrypoint may be a JSON string which requires preserving the quotes (see #12477) cname=$(random_string) - run_podman create --name $cname --label "io.containers.autoupdate=local" --entrypoint '["top"]' $IMAGE + + # Create a scratch image (copy of our regular one) + image_copy=base$(random_string | tr A-Z a-z) + run_podman tag $IMAGE $image_copy + + # Create a container based on that + run_podman create --name $cname --label "io.containers.autoupdate=local" --entrypoint '["top"]' $image_copy # Start systemd service to run this container service_setup # Give container time to start; make sure output looks top-like - sleep 2 - run_podman logs $cname - is "$output" ".*Load average:.*" "running container 'top'-like output" - - # Save the container id before updating - run_podman ps --format '{{.ID}}' + wait_for_output 'Load average' $cname # Run auto-update and check that it restarted the container - run_podman commit --change "CMD=/bin/bash" $cname $IMAGE + run_podman commit --change "CMD=/bin/bash" $cname $image_copy run_podman auto-update is "$output" ".*$SERVICE_NAME.*" "autoupdate local restarted container" # All good. Stop service, clean up. service_cleanup + run_podman rmi $image_copy } # These tests can fail in dev. environment because of SELinux. @@ -235,6 +243,7 @@ LISTEN_FDNAMES=listen_fdnames" | sort) run_podman rm -f $cname run_podman pod rm -f $podname + run_podman rmi $(pause_image) } @test "podman generate - systemd template only used on --new" { @@ -295,6 +304,8 @@ LISTEN_FDNAMES=listen_fdnames" | sort) 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 @@ -360,6 +371,33 @@ EOF systemctl stop $service_name run_podman 1 container exists $service_container run_podman 1 pod exists test_pod + run_podman rmi $(pause_image) + rm -f $UNIT_DIR/$unit_name +} + +@test "podman-system-service containers survive service stop" { + skip_if_remote "N/A under podman-remote" + + SERVICE_NAME=podman-service-$(random_string) + port=$(random_free_port) + URL=tcp://127.0.0.1:$port + + systemd-run --unit=$SERVICE_NAME $PODMAN system service $URL --time=0 + wait_for_port 127.0.0.1 $port + + # Start a long-running container. + cname=keeps-running + run_podman --url $URL run -d --name $cname $IMAGE top -d 2 + + run_podman container inspect -l --format "{{.State.Running}}" + is "$output" "true" "This should never fail" + + systemctl stop $SERVICE_NAME + + run_podman container inspect $cname --format "{{.State.Running}}" + is "$output" "true" "Container is still running after podman server stops" + + run_podman rm -f -t 0 $cname } # vim: filetype=sh diff --git a/test/system/410-selinux.bats b/test/system/410-selinux.bats index 21ac4cb8f..d437465a4 100644 --- a/test/system/410-selinux.bats +++ b/test/system/410-selinux.bats @@ -205,7 +205,11 @@ function check_label() { # from /proc/thread-self/attr/exec`: .* unable to assign # to /proc/self/attr/keycreate`: .* unable to process crun) expect="\`/proc/.*\`: OCI runtime error: unable to \(assign\|process\) security attribute" ;; - runc) expect="OCI runtime error: .*: failed to set /proc/self/attr/keycreate on procfs" ;; + # runc 1.1 changed the error message because of new selinux pkg that uses standard os.PathError, see + # https://github.com/opencontainers/selinux/pull/148/commits/a5dc47f74c56922d58ead05d1fdcc5f7f52d5f4e + # from failed to set /proc/self/attr/keycreate on procfs + # to write /proc/self/attr/keycreate: invalid argument + runc) expect="OCI runtime error: .*: \(failed to set|write\) /proc/self/attr/keycreate" ;; *) skip "Unknown runtime '$runtime'";; esac diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index 92aabae32..0d724985e 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -165,6 +165,9 @@ load helpers run_podman pod rm $pod_name is "$output" "$pid" "Only ID in output (no extra errors)" + + # Clean up + run_podman rmi $(pause_image) } @test "podman run with slirp4ns assigns correct addresses to /etc/hosts" { @@ -356,7 +359,7 @@ load helpers run curl -s $SERVER/index.txt is "$output" "$random_1" "curl 127.0.0.1:/index.txt" - # cleanup the container + # clean up the container run_podman rm -t 0 -f $cid # test that we cannot remove the default network @@ -546,7 +549,7 @@ load helpers run curl --max-time 3 -s $SERVER/index.txt is "$output" "$random_1" "curl 127.0.0.1:/index.txt should still work" - # cleanup + # clean up run_podman rm -t 0 -f $cid $background_cid run_podman network rm -t 0 -f $netname $netname2 } @@ -619,7 +622,7 @@ load helpers run_podman rm -t 0 -f $cid done - # Cleanup network + # Clean up network run_podman network rm -t 0 -f $netname } @@ -673,12 +676,12 @@ EOF @test "podman run port forward range" { for netmode in bridge slirp4netns:port_handler=slirp4netns slirp4netns:port_handler=rootlesskit; do - local port=$(random_free_port) - local end_port=$(( $port + 2 )) - local range="$port-$end_port:$port-$end_port" + local range=$(random_free_port_range 3) + local port="${test%-*}" + local end_port="${test#-*}" local random=$(random_string) - run_podman run --network $netmode -p "$range" -d $IMAGE sleep inf + run_podman run --network $netmode -p "$range:$range" -d $IMAGE sleep inf cid="$output" for port in $(seq $port $end_port); do run_podman exec -d $cid nc -l -p $port -e /bin/cat diff --git a/test/system/build-testimage b/test/system/build-testimage index eb5849b5e..a0d831abb 100755 --- a/test/system/build-testimage +++ b/test/system/build-testimage @@ -12,8 +12,8 @@ # still need a fedora image for that. # -# Buildah binary -BUILDAH=${BUILDAH:-buildah} +# Podman binary to use +PODMAN=${PODMAN:-$(pwd)/bin/podman} # Tag for this new image YMD=$(date +%Y%m%d) @@ -25,7 +25,8 @@ if [ -z "$create_script" ]; then fi # Creation timestamp, Zulu time -create_time_z=$(env TZ=UTC date +'%Y-%m-%dT%H:%M:%SZ') +create_time_t=$(date +%s) +create_time_z=$(env TZ=UTC date --date=@$create_time_t +'%Y-%m-%dT%H:%M:%SZ') set -ex @@ -60,19 +61,33 @@ chmod 755 pause # alpine because it's small and light and reliable # - check for updates @ https://hub.docker.com/_/alpine # busybox-extras provides httpd needed in 500-networking.bats -cat >Containerfile <<EOF +# +# Two Containerfiles, because we have to do the image build in two parts, +# which I think are easier to describe in reverse order: +# 2) The second build has to be run with --timestamp=CONSTANT, otherwise +# the Created test in 110-history.bats may fail (#14456); but +# 1) the timestamp of the testimage-id file must be preserved (see above), +# and 'build --timestamp' clobbers all file timestamps. +# +cat >Containerfile1 <<EOF ARG REPO=please-override-repo -FROM docker.io/\${REPO}/alpine:3.13.5 +FROM docker.io/\${REPO}/alpine:3.16.0 RUN apk add busybox-extras ADD testimage-id pause /home/podman/ +EOF + +cat >Containerfile2 <<EOF +FROM localhost/interim-image:latest LABEL created_by=$create_script LABEL created_at=$create_time_z WORKDIR /home/podman CMD ["/bin/echo", "This container is intended for podman CI testing"] EOF -# --squash-all : needed by 'tree' test in 070-build.bats -podman rmi -f testimage &> /dev/null || true +# Start from scratch +testimg_base=quay.io/libpod/testimage +testimg=${testimg_base}:$YMD +$PODMAN rmi -f $testimg &> /dev/null || true # There should always be a testimage tagged ':0000000<X>' (eight digits, # zero-padded sequence ID) in the same location; this is used by tests @@ -80,7 +95,7 @@ podman rmi -f testimage &> /dev/null || true # if ever need to change, nor in fact does it even have to be a copy of # this testimage since all we use it for is 'true'. # However, it does need to be multiarch :-( -zerotag_latest=$(skopeo list-tags docker://quay.io/libpod/testimage |\ +zerotag_latest=$(skopeo list-tags docker://${testimg_base} |\ jq -r '.Tags[]' |\ sort --version-sort |\ grep '^000' |\ @@ -88,12 +103,9 @@ zerotag_latest=$(skopeo list-tags docker://quay.io/libpod/testimage |\ zerotag_next=$(printf "%08d" $((zerotag_latest + 1))) # We don't always need to push the :00xx image, but build it anyway. -zeroimg=quay.io/libpod/testimage:${zerotag_next} -buildah manifest create $zeroimg +zeroimg=${testimg_base}:${zerotag_next} +$PODMAN manifest create $zeroimg -# We need to use buildah because (as of 2021-02-23) only buildah has --manifest -# and because Dan says arch emulation is not currently working on podman -# (no further details). # Arch emulation on Fedora requires the qemu-user-static package. for arch in amd64 arm64 ppc64le s390x;do # docker.io repo is usually the same name as the desired arch; except @@ -104,16 +116,32 @@ for arch in amd64 arm64 ppc64le s390x;do repo="${repo}v8" fi - ${BUILDAH} bud \ - --arch=$arch \ - --build-arg REPO=$repo \ - --manifest=testimage \ - --squash \ - . + # First build defines REPO, but does not have --timestamp + $PODMAN build \ + --arch=$arch \ + --build-arg REPO=$repo \ + --squash-all \ + --file Containerfile1 \ + -t interim-image \ + . + + # Second build forces --timestamp, and adds to manifest. Unfortunately + # we can't use --squash-all with --timestamp: *all* timestamps get + # clobbered. This is not fixable (#14536). + $PODMAN build \ + --arch=$arch \ + --timestamp=$create_time_t \ + --manifest=$testimg \ + --squash \ + --file Containerfile2 \ + . + + # No longer need the interim image + $PODMAN rmi interim-image # The zero-tag image - ${BUILDAH} pull --arch $arch docker.io/$repo/busybox:1.33.1 - ${BUILDAH} manifest add $zeroimg docker.io/$repo/busybox:1.33.1 + $PODMAN pull --arch $arch docker.io/$repo/busybox:1.34.1 + $PODMAN manifest add $zeroimg docker.io/$repo/busybox:1.34.1 done # Clean up @@ -121,14 +149,12 @@ cd /tmp rm -rf $tmpdir # Tag image and push (all arches) to quay. -remote_tag=quay.io/libpod/testimage:$YMD -podman tag testimage ${remote_tag} cat <<EOF If you're happy with these images, run: - ${BUILDAH} manifest push --all ${remote_tag} docker://${remote_tag} - ${BUILDAH} manifest push --all ${zeroimg} docker://${zeroimg} + podman manifest push --all ${testimg} docker://${testimg} + podman manifest push --all ${zeroimg} docker://${zeroimg} (You do not always need to push the :0000 image) diff --git a/test/system/helpers.bash b/test/system/helpers.bash index fe9e971fb..273e8d2f5 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -7,14 +7,14 @@ PODMAN=${PODMAN:-podman} PODMAN_TEST_IMAGE_REGISTRY=${PODMAN_TEST_IMAGE_REGISTRY:-"quay.io"} PODMAN_TEST_IMAGE_USER=${PODMAN_TEST_IMAGE_USER:-"libpod"} PODMAN_TEST_IMAGE_NAME=${PODMAN_TEST_IMAGE_NAME:-"testimage"} -PODMAN_TEST_IMAGE_TAG=${PODMAN_TEST_IMAGE_TAG:-"20210610"} +PODMAN_TEST_IMAGE_TAG=${PODMAN_TEST_IMAGE_TAG:-"20220615"} PODMAN_TEST_IMAGE_FQN="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG" PODMAN_TEST_IMAGE_ID= # Remote image that we *DO NOT* fetch or keep by default; used for testing pull # This has changed in 2021, from 0 through 3, various iterations of getting # multiarch to work. It should change only very rarely. -PODMAN_NONLOCAL_IMAGE_TAG=${PODMAN_NONLOCAL_IMAGE_TAG:-"00000003"} +PODMAN_NONLOCAL_IMAGE_TAG=${PODMAN_NONLOCAL_IMAGE_TAG:-"00000004"} PODMAN_NONLOCAL_IMAGE_FQN="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_NONLOCAL_IMAGE_TAG" # Because who wants to spell that out each time? @@ -284,7 +284,7 @@ function random_free_port() { local port for port in $(shuf -i ${range}); do - if ! { exec {unused_fd}<> /dev/tcp/127.0.0.1/$port; } &>/dev/null; then + if port_is_free $port; then echo $port return fi @@ -293,6 +293,35 @@ function random_free_port() { die "Could not find open port in range $range" } +function random_free_port_range() { + local size=${1?Usage: random_free_port_range SIZE (as in, number of ports)} + + local maxtries=10 + while [[ $maxtries -gt 0 ]]; do + local firstport=$(random_free_port) + local all_ports_free=1 + for i in $(seq 2 $size); do + if ! port_is_free $((firstport + $i)); then + all_ports_free= + break + fi + done + if [[ -n "$all_ports_free" ]]; then + echo "$firstport-$((firstport + $size - 1))" + return + fi + + maxtries=$((maxtries - 1)) + done + + die "Could not find free port range with size $size" +} + +function port_is_free() { + local port=${1?Usage: port_is_free PORT} + ! { exec {unused_fd}<> /dev/tcp/127.0.0.1/$port; } &>/dev/null +} + ################### # wait_for_port # Returns once port is available on host ################### diff --git a/test/system/helpers.systemd.bash b/test/system/helpers.systemd.bash index 4bde912a4..d9abc087d 100644 --- a/test/system/helpers.systemd.bash +++ b/test/system/helpers.systemd.bash @@ -28,3 +28,7 @@ systemctl() { journalctl() { command journalctl $_DASHUSER "$@" } + +systemd-run() { + command systemd-run $_DASHUSER "$@"; +} |