diff options
Diffstat (limited to 'test')
47 files changed, 1081 insertions, 103 deletions
diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at index 96eba1db5..67b4f1c79 100644 --- a/test/apiv2/12-imagesMore.at +++ b/test/apiv2/12-imagesMore.at @@ -26,7 +26,8 @@ t GET libpod/images/$IMAGE/json 200 \ .RepoTags[1]=localhost:5000/myrepo:mytag # Run registry container -podman run -d --name registry -p 5000:5000 quay.io/libpod/registry:2.6 /entrypoint.sh /etc/docker/registry/config.yml +# FIXME this fails if python tests have been run first... +podman run -d --name registry -p 5000:5000 quay.io/libpod/registry:2.7 /entrypoint.sh /etc/docker/registry/config.yml wait_for_port localhost 5000 # Push to local registry and check output @@ -58,7 +59,7 @@ t DELETE libpod/containers/registry?force=true 200 # Remove images t DELETE libpod/images/$IMAGE 200 \ .ExitCode=0 -t DELETE libpod/images/quay.io/libpod/registry:2.6 200 \ +t DELETE libpod/images/quay.io/libpod/registry:2.7 200 \ .ExitCode=0 if [ -z "${GOT_DIGEST}" ] ; then diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at index cc5eda88e..94de2cf24 100644 --- a/test/apiv2/20-containers.at +++ b/test/apiv2/20-containers.at @@ -280,7 +280,7 @@ t DELETE containers/$cid_top 204 t POST containers/create \ Image=$ENV_WORKDIR_IMG \ WorkingDir=/dataDir \ - StopSignal=9 \ + StopSignal=\"9\" \ 201 \ .Id~[0-9a-f]\\{64\\} cid=$(jq -r '.Id' <<<"$output") @@ -394,7 +394,8 @@ t GET containers/$cid/json 200 \ .Config.Healthcheck.Retries=3 # compat api: Test for mount options support -payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch","TmpfsOptions":{"SizeBytes":1024,"Mode":755}}]}' +# Sigh, JSON can't handle octal. 0755(octal) = 493(decimal) +payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch","TmpfsOptions":{"SizeBytes":1024,"Mode":493}}]}' t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\} cid=$(jq -r '.Id' <<<"$output") t GET containers/$cid/json 200 \ diff --git a/test/apiv2/python/conftest.py b/test/apiv2/python/conftest.py new file mode 100644 index 000000000..54a267049 --- /dev/null +++ b/test/apiv2/python/conftest.py @@ -0,0 +1,8 @@ +""" +Configure pytest +""" + + +def pytest_report_header(config): + """Add header to report.""" + return "python client -- requests library" diff --git a/test/apiv2/python/requirements.txt b/test/apiv2/python/requirements.txt new file mode 100644 index 000000000..d9cfc687a --- /dev/null +++ b/test/apiv2/python/requirements.txt @@ -0,0 +1,5 @@ +requests-mock~=1.9.3 +requests~=2.20.0 +setuptools~=50.3.2 +python-dateutil~=2.8.1 +PyYAML~=5.4.1 diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2 index bd728e130..c3545522e 100755 --- a/test/apiv2/test-apiv2 +++ b/test/apiv2/test-apiv2 @@ -194,8 +194,16 @@ function jsonify() { local rhs IFS='=' read lhs rhs <<<"$i" - # If right-hand side already includes double quotes, do nothing - if [[ ! $rhs =~ \" ]]; then + if [[ $rhs =~ \" || $rhs == true || $rhs == false || $rhs =~ ^-?[0-9]+$ ]]; then + # rhs has been pre-formatted for JSON or a non-string, do not change it + : + elif [[ $rhs == False ]]; then + # JSON boolean is lowercase only + rhs=false + elif [[ $rhs == True ]]; then + # JSON boolean is lowercase only + rhs=true + else rhs="\"${rhs}\"" fi settings_out+=("\"${lhs}\":${rhs}") @@ -241,26 +249,30 @@ function t() { # entrypoint path can include a descriptive comment; strip it off path=${path%% *} - # path may include JSONish params that curl will barf on; url-encode them - path="${path//'['/%5B}" - path="${path//']'/%5D}" - path="${path//'{'/%7B}" - path="${path//'}'/%7D}" - path="${path//':'/%3A}" + local url=$path + if ! [[ $path =~ ^'http://' ]]; then + # path may include JSONish params that curl will barf on; url-encode them + path="${path//'['/%5B}" + path="${path//']'/%5D}" + path="${path//'{'/%7B}" + path="${path//'}'/%7D}" + path="${path//':'/%3A}" + + # If given path begins with /, use it as-is; otherwise prepend /version/ + url=http://$HOST:$PORT + case "$path" in + /*) url="$url$path" ;; + libpod/*) url="$url/v4.0.0/$path" ;; + *) url="$url/v1.41/$path" ;; + esac + fi # curl -X HEAD but without --head seems to wait for output anyway if [[ $method == "HEAD" ]]; then curl_args="--head" fi - local expected_code=$1; shift - # If given path begins with /, use it as-is; otherwise prepend /version/ - local url=http://$HOST:$PORT - case "$path" in - /*) url="$url$path" ;; - libpod/*) url="$url/v4.0.0/$path" ;; - *) url="$url/v1.41/$path" ;; - esac + local expected_code=$1; shift # Log every action we do echo "-------------------------------------------------------------" >>$LOG @@ -368,7 +380,7 @@ function start_service() { die "Cannot start service on non-localhost ($HOST)" fi - echo $WORKDIR + echo "rootdir: "$WORKDIR # Some tests use shortnames; force registry override to work around # docker.io throttling. # FIXME esm revisit pulling expected images re: shortnames caused tests to fail @@ -376,7 +388,7 @@ function start_service() { $PODMAN_BIN \ --root $WORKDIR/server_root --syslog=true \ system service \ - --time 15 \ + --time 0 \ tcp:127.0.0.1:$PORT \ &> $WORKDIR/server.log & service_pid=$! @@ -443,7 +455,7 @@ function start_registry() { -e REGISTRY_HTTP_TLS_KEY=/auth/domain.key \ ${REGISTRY_IMAGE} - wait_for_port localhost $REGISTRY_PORT + wait_for_port localhost $REGISTRY_PORT 10 } function stop_registry() { @@ -492,13 +504,16 @@ function wait_for_port() { local port=$2 # Numeric port local _timeout=${3:-5} # Optional; default to 5 seconds + local path=/dev/tcp/$host/$port + # Wait - while [ $_timeout -gt 0 ]; do + local i=$_timeout + while [ $i -gt 0 ]; do { exec 3<> /dev/tcp/$host/$port; } &>/dev/null && return sleep 1 - _timeout=$(( $_timeout - 1 )) + i=$(( $i - 1 )) done - die "Timed out waiting for service" + die "Timed out (${_timeout}s) waiting for service ($path)" } ############ @@ -543,6 +558,9 @@ done ############################################################################### # BEGIN entry handler (subtest invoker) +echo '============================= test session starts ==============================' +echo "podman client -- $(curl --version)" + # Identify the tests to run. If called with args, use those as globs. tests_to_run=() if [ -n "$*" ]; then @@ -558,6 +576,7 @@ if [ -n "$*" ]; then else tests_to_run=($TESTS_DIR/*.at) fi +echo -e "collected ${#tests_to_run[@]} items\n" start_service diff --git a/test/buildah-bud/apply-podman-deltas b/test/buildah-bud/apply-podman-deltas index dd5331091..26d7fc075 100755 --- a/test/buildah-bud/apply-podman-deltas +++ b/test/buildah-bud/apply-podman-deltas @@ -140,6 +140,18 @@ errmsg "no such file or directory" \ skip "N/A under podman" \ "bud-flags-order-verification" +# TODO +# Some of the podman tests in CI expects exit code 125, which might not be true +# since exit code from runtime is relayed as it is without any modification both +# in `buildah` and `podman`. Following behviour is seen when PR https://github.com/containers/buildah/pull/3809 +# added a test here https://github.com/containers/buildah/blob/main/tests/bud.bats#L3183 +# which relays exit code from runtime as it is, in case of both `podman` and `buildah`. +# However apart from this test case no other test case was able to trigger this behavior +# hence marking this test as an anomaly. Since its debatable if we should override this +# returned error number or not hence adding a note here. +skip "podman CI expects all exit code to be 125 this test has anomaly behaviour" \ + "bud with --add-host" + skip "does not work under podman" \ "bud without any arguments should succeed" diff --git a/test/buildah-bud/buildah-tests.diff b/test/buildah-bud/buildah-tests.diff index b1a19a522..ca38b5a10 100644 --- a/test/buildah-bud/buildah-tests.diff +++ b/test/buildah-bud/buildah-tests.diff @@ -1,15 +1,15 @@ -From c18638abfbc1066442cf6ff0b3f012a5c25a918e Mon Sep 17 00:00:00 2001 +From 1a5562929a85074a7498165191558f434bb30bf1 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 | 72 +++++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 68 insertions(+), 4 deletions(-) + tests/helpers.bash | 73 +++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/tests/helpers.bash b/tests/helpers.bash -index bd2794c9..ecf6ed7d 100644 +index 2bb6b429..0dc98a85 100644 --- a/tests/helpers.bash +++ b/tests/helpers.bash @@ -43,6 +43,23 @@ EOF @@ -63,8 +63,8 @@ index bd2794c9..ecf6ed7d 100644 + ${PODMAN_BINARY} ${ROOTDIR_OPTS} "$@" } - ################# -@@ -192,15 +221,41 @@ function run_buildah() { + # There are various scenarios where we would like to execute `tests` as rootless user, however certain commands like `buildah mount` +@@ -221,8 +250,35 @@ function run_buildah() { --retry) retry=3; shift;; # retry network flakes esac @@ -94,11 +94,14 @@ index bd2794c9..ecf6ed7d 100644 + fi + local cmd_basename=$(basename ${podman_or_buildah}) + ++ # Remember command args, for possible use in later diagnostic messages - MOST_RECENT_BUILDAH_COMMAND="buildah $*" + MOST_RECENT_BUILDAH_COMMAND="$cmd_basename $*" - while [ $retry -gt 0 ]; do + # 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. +@@ -236,8 +292,8 @@ function run_buildah() { retry=$(( retry - 1 )) # stdout is only emitted upon error; this echo is to help a debugger @@ -109,7 +112,7 @@ index bd2794c9..ecf6ed7d 100644 # without "quotes", multiple lines are glommed together into one if [ -n "$output" ]; then echo "$output" -@@ -499,6 +554,15 @@ function skip_if_no_docker() { +@@ -545,6 +601,15 @@ function skip_if_no_docker() { fi } @@ -126,5 +129,5 @@ index bd2794c9..ecf6ed7d 100644 daemondir=${TESTDIR}/git-daemon mkdir -p ${daemondir}/repo -- -2.34.1 +2.31.1 diff --git a/test/checkseccomp/checkseccomp.go b/test/checkseccomp/checkseccomp.go index 9046e0955..6c188ec0d 100644 --- a/test/checkseccomp/checkseccomp.go +++ b/test/checkseccomp/checkseccomp.go @@ -1,3 +1,4 @@ +//go:build seccomp // +build seccomp package main diff --git a/test/compose/ipam_set_ip/tests.sh b/test/compose/ipam_set_ip/tests.sh index ecaf3167e..b9e761ea2 100644 --- a/test/compose/ipam_set_ip/tests.sh +++ b/test/compose/ipam_set_ip/tests.sh @@ -1,4 +1,8 @@ # -*- bash -*- -podman container inspect ipam_set_ip_test_1 --format '{{ .NetworkSettings.Networks.ipam_set_ip_net1.IPAddress }}' +ctr_name="ipam_set_ip_test_1" +if [ "$TEST_FLAVOR" = "compose_v2" ]; then + ctr_name="ipam_set_ip-test-1" +fi +podman container inspect "$ctr_name" --format '{{ .NetworkSettings.Networks.ipam_set_ip_net1.IPAddress }}' like "$output" "10.123.0.253" "$testname : ip address is set" diff --git a/test/compose/slirp4netns_opts/tests.sh b/test/compose/slirp4netns_opts/tests.sh index 1efce45c4..cfa84e1e4 100644 --- a/test/compose/slirp4netns_opts/tests.sh +++ b/test/compose/slirp4netns_opts/tests.sh @@ -3,4 +3,18 @@ output="$(cat $OUTFILE)" expected="teststring" +# Reading from the nc socket is flaky because docker-compose only starts +# the containers. We cannot know at this point if the container did already +# send the message. Give the container 5 seconds time to send the message +# to prevent flakes. +local _timeout=5 +while [ $_timeout -gt 0 ]; do + if [ -n "$output" ]; then + break + fi + sleep 1 + _timeout=$(($_timeout - 1)) + output="$(cat $OUTFILE)" +done + is "$output" "$expected" "$testname : nc received teststring" diff --git a/test/compose/two_networks/tests.sh b/test/compose/two_networks/tests.sh index 1cc88aa5f..af0d1fbe3 100644 --- a/test/compose/two_networks/tests.sh +++ b/test/compose/two_networks/tests.sh @@ -1,7 +1,11 @@ # -*- bash -*- -podman container inspect two_networks_con1_1 --format '{{len .NetworkSettings.Networks}}' +ctr_name="two_networks_con1_1" +if [ "$TEST_FLAVOR" = "compose_v2" ]; then + ctr_name="two_networks-con1-1" +fi +podman container inspect "$ctr_name" --format '{{len .NetworkSettings.Networks}}' is "$output" "2" "$testname : Container is connected to both networks" -podman container inspect two_networks_con1_1 --format '{{.NetworkSettings.Networks}}' +podman container inspect "$ctr_name" --format '{{.NetworkSettings.Networks}}' like "$output" "two_networks_net1" "$testname : First network name exists" like "$output" "two_networks_net2" "$testname : Second network name exists" diff --git a/test/e2e/attach_test.go b/test/e2e/attach_test.go index a7af76529..74e3a619a 100644 --- a/test/e2e/attach_test.go +++ b/test/e2e/attach_test.go @@ -1,7 +1,6 @@ package integration import ( - "os" "syscall" "time" @@ -20,12 +19,11 @@ var _ = Describe("Podman attach", func() { BeforeEach(func() { tempdir, err = CreateTempDirInTempDir() - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.SeedImages() + err = podmanTest.SeedImages() + Expect(err).To(BeNil()) }) AfterEach(func() { diff --git a/test/e2e/build/Dockerfile.with-multiple-secret b/test/e2e/build/Containerfile.with-multiple-secret index f3478914f..f3478914f 100644 --- a/test/e2e/build/Dockerfile.with-multiple-secret +++ b/test/e2e/build/Containerfile.with-multiple-secret diff --git a/test/e2e/build/Dockerfile.with-secret b/test/e2e/build/Containerfile.with-secret index 920663a92..920663a92 100644 --- a/test/e2e/build/Dockerfile.with-secret +++ b/test/e2e/build/Containerfile.with-secret diff --git a/test/e2e/build/Dockerfile.test-cp-root-dir b/test/e2e/build/Dockerfile.test-cp-root-dir deleted file mode 100644 index 9f7de7c32..000000000 --- a/test/e2e/build/Dockerfile.test-cp-root-dir +++ /dev/null @@ -1,2 +0,0 @@ -FROM scratch -COPY Dockerfile.test-cp-root-dir / diff --git a/test/e2e/build/Dockerfile.with-secret-verify-leak b/test/e2e/build/secret-verify-leak/Containerfile.with-secret-verify-leak index 0957ac6a6..0957ac6a6 100644 --- a/test/e2e/build/Dockerfile.with-secret-verify-leak +++ b/test/e2e/build/secret-verify-leak/Containerfile.with-secret-verify-leak diff --git a/test/e2e/build/workdir-symlink/Dockerfile b/test/e2e/build/workdir-symlink/Dockerfile new file mode 100644 index 000000000..abc9b47ee --- /dev/null +++ b/test/e2e/build/workdir-symlink/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine +RUN mkdir /tmp/destination +RUN ln -s /tmp/destination /tmp/link +WORKDIR /tmp/link +CMD ["echo", "hello"] diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go index a1c2f5e54..c5903f037 100644 --- a/test/e2e/build_test.go +++ b/test/e2e/build_test.go @@ -60,7 +60,7 @@ var _ = Describe("Podman build", func() { }) It("podman build with a secret from file", func() { - session := podmanTest.Podman([]string{"build", "-f", "build/Dockerfile.with-secret", "-t", "secret-test", "--secret", "id=mysecret,src=build/secret.txt", "build/"}) + session := podmanTest.Podman([]string{"build", "-f", "build/Containerfile.with-secret", "-t", "secret-test", "--secret", "id=mysecret,src=build/secret.txt", "build/"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(ContainSubstring("somesecret")) @@ -71,7 +71,7 @@ var _ = Describe("Podman build", func() { }) It("podman build with multiple secrets from files", func() { - session := podmanTest.Podman([]string{"build", "-f", "build/Dockerfile.with-multiple-secret", "-t", "multiple-secret-test", "--secret", "id=mysecret,src=build/secret.txt", "--secret", "id=mysecret2,src=build/anothersecret.txt", "build/"}) + session := podmanTest.Podman([]string{"build", "-f", "build/Containerfile.with-multiple-secret", "-t", "multiple-secret-test", "--secret", "id=mysecret,src=build/secret.txt", "--secret", "id=mysecret2,src=build/anothersecret.txt", "build/"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(ContainSubstring("somesecret")) @@ -83,7 +83,7 @@ var _ = Describe("Podman build", func() { }) It("podman build with a secret from file and verify if secret file is not leaked into image", func() { - session := podmanTest.Podman([]string{"build", "-f", "build/Dockerfile.with-secret-verify-leak", "-t", "secret-test-leak", "--secret", "id=mysecret,src=build/secret.txt", "build/"}) + session := podmanTest.Podman([]string{"build", "-f", "build/secret-verify-leak/Containerfile.with-secret-verify-leak", "-t", "secret-test-leak", "--secret", "id=mysecret,src=build/secret.txt", "build/"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(ContainSubstring("somesecret")) @@ -259,6 +259,19 @@ var _ = Describe("Podman build", func() { Expect(session.OutputToString()).NotTo(ContainSubstring("io.podman.annotations.seccomp")) }) + It("podman build where workdir is a symlink and run without creating new workdir", func() { + session := podmanTest.Podman([]string{ + "build", "-f", "build/workdir-symlink/Dockerfile", "-t", "test-symlink", + }) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"run", "--workdir", "/tmp/link", "test-symlink"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).To(ContainSubstring("hello")) + }) + It("podman build --http_proxy flag", func() { os.Setenv("http_proxy", "1.2.3.4") if IsRemote() { diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index 5abc672e9..7b2dd89c9 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -37,12 +37,12 @@ var _ = Describe("Podman checkpoint", func() { BeforeEach(func() { SkipIfRootless("checkpoint not supported in rootless mode") tempdir, err = CreateTempDirInTempDir() - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) + podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.SeedImages() + err = podmanTest.SeedImages() + Expect(err).To(BeNil()) // Check if the runtime implements checkpointing. Currently only // runc's checkpoint/restore implementation is supported. cmd := exec.Command(podmanTest.OCIRuntime, "checkpoint", "--help") diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go index 6bcf17bfe..78b607f1e 100644 --- a/test/e2e/commit_test.go +++ b/test/e2e/commit_test.go @@ -21,12 +21,11 @@ var _ = Describe("Podman commit", func() { BeforeEach(func() { tempdir, err = CreateTempDirInTempDir() - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.SeedImages() + err = podmanTest.SeedImages() + Expect(err).To(BeNil()) }) AfterEach(func() { diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index b1cd76d27..cb6574f23 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -809,7 +809,8 @@ func (p *PodmanTestIntegration) RestoreArtifactToCache(image string) error { func populateCache(podman *PodmanTestIntegration) { for _, image := range CACHE_IMAGES { - podman.RestoreArtifactToCache(image) + err := podman.RestoreArtifactToCache(image) + Expect(err).To(BeNil()) } // logformatter uses this to recognize the first test fmt.Printf("-----------------------------\n") @@ -896,7 +897,7 @@ func removeConf(confPath string) { } } -// generateNetworkConfig generates a cni config with a random name +// generateNetworkConfig generates a CNI or Netavark config with a random name // it returns the network name and the filepath func generateNetworkConfig(p *PodmanTestIntegration) (string, string) { var ( @@ -1042,3 +1043,27 @@ func ncz(port int) bool { func createNetworkName(name string) string { return name + stringid.GenerateNonCryptoID()[:10] } + +var IPRegex = `(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}` + +// digShort execs into the given container and does a dig lookup with a timeout +// backoff. If it gets a response, it ensures that the output is in the correct +// format and iterates a string array for match +func digShort(container, lookupName string, matchNames []string, p *PodmanTestIntegration) string { + digInterval := time.Millisecond * 250 + for i := 0; i < 6; i++ { + time.Sleep(digInterval * time.Duration(i)) + dig := p.Podman([]string{"exec", container, "dig", "+short", lookupName}) + dig.WaitWithDefaultTimeout() + if dig.ExitCode() == 0 { + output := dig.OutputToString() + Expect(output).To(MatchRegexp(IPRegex)) + for _, name := range matchNames { + Expect(output).To(Equal(name)) + } + return output + } + } + Fail("dns is not responding") + return "" +} diff --git a/test/e2e/containers_conf_test.go b/test/e2e/containers_conf_test.go index bfed01854..09cd68042 100644 --- a/test/e2e/containers_conf_test.go +++ b/test/e2e/containers_conf_test.go @@ -562,6 +562,11 @@ var _ = Describe("Verify podman containers.conf usage", func() { inspect = podmanTest.Podman([]string{"inspect", "--format", "{{ .HostConfig.Cgroups }}", result.OutputToString()}) inspect.WaitWithDefaultTimeout() Expect(inspect.OutputToString()).To(Equal("disabled")) + + // Check we can also create a pod when cgroups=disabled + result = podmanTest.Podman([]string{"pod", "create"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) }) It("podman containers.conf runtime", func() { diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index 6a4a394ef..4c3b5604a 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -24,12 +24,11 @@ var _ = Describe("Podman create", func() { BeforeEach(func() { tempdir, err = CreateTempDirInTempDir() - if err != nil { - os.Exit(1) - } + Expect(err).To(BeNil()) podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() - podmanTest.SeedImages() + err = podmanTest.SeedImages() + Expect(err).To(BeNil()) }) AfterEach(func() { @@ -706,4 +705,34 @@ var _ = Describe("Podman create", func() { Expect(create.ErrorToString()).To(ContainSubstring("cannot specify a new uid/gid map when entering a pod with an infra container")) }) + + It("podman create --chrootdirs inspection test", func() { + session := podmanTest.Podman([]string{"create", "--chrootdirs", "/var/local/qwerty", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + setup := podmanTest.Podman([]string{"container", "inspect", session.OutputToString()}) + setup.WaitWithDefaultTimeout() + Expect(setup).Should(Exit(0)) + + data := setup.InspectContainerToJSON() + Expect(data).To(HaveLen(1)) + Expect(data[0].Config.ChrootDirs).To(HaveLen(1)) + Expect(data[0].Config.ChrootDirs[0]).To(Equal("/var/local/qwerty")) + }) + + It("podman create --chrootdirs functionality test", func() { + session := podmanTest.Podman([]string{"create", "-t", "--chrootdirs", "/var/local/qwerty", ALPINE, "/bin/cat"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + ctrID := session.OutputToString() + + setup := podmanTest.Podman([]string{"start", ctrID}) + setup.WaitWithDefaultTimeout() + Expect(setup).Should(Exit(0)) + + setup = podmanTest.Podman([]string{"exec", ctrID, "cmp", "/etc/resolv.conf", "/var/local/qwerty/etc/resolv.conf"}) + setup.WaitWithDefaultTimeout() + Expect(setup).Should(Exit(0)) + }) }) diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index 53829e89b..44c906eed 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -9,13 +9,13 @@ import ( "github.com/containers/podman/v4/libpod/define" + v1 "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" "github.com/containers/podman/v4/pkg/util" . "github.com/containers/podman/v4/test/utils" "github.com/ghodss/yaml" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gexec" - v1 "k8s.io/api/core/v1" ) var _ = Describe("Podman generate kube", func() { @@ -1018,7 +1018,7 @@ USER test1` pvc := new(v1.PersistentVolumeClaim) err := yaml.Unmarshal(kube.Out.Contents(), pvc) Expect(err).To(BeNil()) - Expect(pvc.GetName()).To(Equal(vol)) + Expect(pvc.Name).To(Equal(vol)) Expect(pvc.Spec.AccessModes[0]).To(Equal(v1.ReadWriteOnce)) Expect(pvc.Spec.Resources.Requests.Storage().String()).To(Equal("1Gi")) }) @@ -1040,11 +1040,11 @@ USER test1` pvc := new(v1.PersistentVolumeClaim) err := yaml.Unmarshal(kube.Out.Contents(), pvc) Expect(err).To(BeNil()) - Expect(pvc.GetName()).To(Equal(vol)) + Expect(pvc.Name).To(Equal(vol)) Expect(pvc.Spec.AccessModes[0]).To(Equal(v1.ReadWriteOnce)) Expect(pvc.Spec.Resources.Requests.Storage().String()).To(Equal("1Gi")) - for k, v := range pvc.GetAnnotations() { + for k, v := range pvc.Annotations { switch k { case util.VolumeDeviceAnnotation: Expect(v).To(Equal(volDevice)) @@ -1069,7 +1069,7 @@ USER test1` err := yaml.Unmarshal(kube.Out.Contents(), pod) Expect(err).To(BeNil()) - Expect(pod.GetAnnotations()).To(HaveKeyWithValue("io.containers.autoupdate/top", "local")) + Expect(pod.Annotations).To(HaveKeyWithValue("io.containers.autoupdate/top", "local")) }) It("podman generate kube on pod with auto update labels in all containers", func() { @@ -1096,8 +1096,8 @@ USER test1` Expect(pod.Spec.Containers[1].WorkingDir).To(Equal("/root")) for _, ctr := range []string{"top1", "top2"} { - Expect(pod.GetAnnotations()).To(HaveKeyWithValue("io.containers.autoupdate/"+ctr, "registry")) - Expect(pod.GetAnnotations()).To(HaveKeyWithValue("io.containers.autoupdate.authfile/"+ctr, "/some/authfile.json")) + Expect(pod.Annotations).To(HaveKeyWithValue("io.containers.autoupdate/"+ctr, "registry")) + Expect(pod.Annotations).To(HaveKeyWithValue("io.containers.autoupdate.authfile/"+ctr, "/some/authfile.json")) } }) diff --git a/test/e2e/generate_systemd_test.go b/test/e2e/generate_systemd_test.go index 55b9a8037..e4b854332 100644 --- a/test/e2e/generate_systemd_test.go +++ b/test/e2e/generate_systemd_test.go @@ -423,6 +423,20 @@ var _ = Describe("Podman generate systemd", func() { }) + It("podman generate systemd --container-prefix ''", func() { + n := podmanTest.Podman([]string{"create", "--name", "foo", "alpine", "top"}) + n.WaitWithDefaultTimeout() + Expect(n).Should(Exit(0)) + + session := podmanTest.Podman([]string{"generate", "systemd", "--name", "--container-prefix", "", "foo"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + // Grepping the output (in addition to unit tests) + Expect(session.OutputToString()).To(ContainSubstring("# foo.service")) + + }) + It("podman generate systemd --separator _", func() { n := podmanTest.Podman([]string{"create", "--name", "foo", "alpine", "top"}) n.WaitWithDefaultTimeout() @@ -485,6 +499,44 @@ var _ = Describe("Podman generate systemd", func() { Expect(session.OutputToString()).To(ContainSubstring("BindsTo=p_foo.service")) }) + It("podman generate systemd pod --pod-prefix '' --container-prefix '' --separator _ change all prefixes/separator", func() { + n := podmanTest.Podman([]string{"pod", "create", "--name", "foo"}) + n.WaitWithDefaultTimeout() + Expect(n).Should(Exit(0)) + + n = podmanTest.Podman([]string{"create", "--pod", "foo", "--name", "foo-1", "alpine", "top"}) + n.WaitWithDefaultTimeout() + Expect(n).Should(Exit(0)) + + n = podmanTest.Podman([]string{"create", "--pod", "foo", "--name", "foo-2", "alpine", "top"}) + n.WaitWithDefaultTimeout() + Expect(n).Should(Exit(0)) + + // test systemd generate with empty pod prefix + session1 := podmanTest.Podman([]string{"generate", "systemd", "--pod-prefix", "", "--name", "foo"}) + session1.WaitWithDefaultTimeout() + Expect(session1).Should(Exit(0)) + + // Grepping the output (in addition to unit tests) + Expect(session1.OutputToString()).To(ContainSubstring("# foo.service")) + Expect(session1.OutputToString()).To(ContainSubstring("Requires=container-foo-1.service container-foo-2.service")) + Expect(session1.OutputToString()).To(ContainSubstring("# container-foo-1.service")) + Expect(session1.OutputToString()).To(ContainSubstring("BindsTo=foo.service")) + + // test systemd generate with empty container and pod prefix + session2 := podmanTest.Podman([]string{"generate", "systemd", "--container-prefix", "", "--pod-prefix", "", "--separator", "_", "--name", "foo"}) + session2.WaitWithDefaultTimeout() + Expect(session2).Should(Exit(0)) + + // Grepping the output (in addition to unit tests) + Expect(session2.OutputToString()).To(ContainSubstring("# foo.service")) + Expect(session2.OutputToString()).To(ContainSubstring("Requires=foo-1.service foo-2.service")) + Expect(session2.OutputToString()).To(ContainSubstring("# foo-1.service")) + Expect(session2.OutputToString()).To(ContainSubstring("# foo-2.service")) + Expect(session2.OutputToString()).To(ContainSubstring("BindsTo=foo.service")) + + }) + It("podman generate systemd pod with containers --new", func() { tmpDir, err := ioutil.TempDir("", "") Expect(err).To(BeNil()) diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go index 866edbf0e..757eaed20 100644 --- a/test/e2e/healthcheck_run_test.go +++ b/test/e2e/healthcheck_run_test.go @@ -54,6 +54,16 @@ var _ = Describe("Podman healthcheck run", func() { Expect(hc).Should(Exit(125)) }) + It("podman disable healthcheck with --no-healthcheck must not show starting on status", func() { + session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", healthcheck}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + hc := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Health.Status}}", "hc"}) + hc.WaitWithDefaultTimeout() + Expect(hc).Should(Exit(0)) + Expect(hc.OutputToString()).To(Not(ContainSubstring("starting"))) + }) + It("podman run healthcheck and logs should contain healthcheck output", func() { session := podmanTest.Podman([]string{"run", "--name", "test-logs", "-dt", "--health-interval", "1s", "--health-cmd", "echo working", "busybox", "sleep", "3600"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go index 3943a5e87..bb5a3a6ad 100644 --- a/test/e2e/inspect_test.go +++ b/test/e2e/inspect_test.go @@ -86,6 +86,7 @@ var _ = Describe("Podman inspect", func() { It("podman inspect container with GO format for ConmonPidFile", func() { session, ec, _ := podmanTest.RunLsContainer("test1") + session.WaitWithDefaultTimeout() Expect(ec).To(Equal(0)) session = podmanTest.Podman([]string{"inspect", "--format", "{{.ConmonPidFile}}", "test1"}) @@ -94,7 +95,8 @@ var _ = Describe("Podman inspect", func() { }) It("podman inspect container with size", func() { - _, ec, _ := podmanTest.RunLsContainer("sizetest") + session, ec, _ := podmanTest.RunLsContainer("sizetest") + session.WaitWithDefaultTimeout() Expect(ec).To(Equal(0)) result := podmanTest.Podman([]string{"inspect", "--size", "sizetest"}) @@ -107,6 +109,7 @@ var _ = Describe("Podman inspect", func() { It("podman inspect container and image", func() { ls, ec, _ := podmanTest.RunLsContainer("") + ls.WaitWithDefaultTimeout() Expect(ec).To(Equal(0)) cid := ls.OutputToString() @@ -118,6 +121,7 @@ var _ = Describe("Podman inspect", func() { It("podman inspect container and filter for Image{ID}", func() { ls, ec, _ := podmanTest.RunLsContainer("") + ls.WaitWithDefaultTimeout() Expect(ec).To(Equal(0)) cid := ls.OutputToString() @@ -134,6 +138,7 @@ var _ = Describe("Podman inspect", func() { It("podman inspect container and filter for CreateCommand", func() { ls, ec, _ := podmanTest.RunLsContainer("") + ls.WaitWithDefaultTimeout() Expect(ec).To(Equal(0)) cid := ls.OutputToString() @@ -529,6 +534,7 @@ var _ = Describe("Podman inspect", func() { It("podman inspect container with GO format for PidFile", func() { SkipIfRemote("pidfile not handled by remote") session, ec, _ := podmanTest.RunLsContainer("test1") + session.WaitWithDefaultTimeout() Expect(ec).To(Equal(0)) session = podmanTest.Podman([]string{"inspect", "--format", "{{.PidFile}}", "test1"}) diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index ccd7c771e..cf81a0348 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -1,3 +1,4 @@ +//go:build !remote // +build !remote package integration diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go index 1280b3e83..77549a9a8 100644 --- a/test/e2e/login_logout_test.go +++ b/test/e2e/login_logout_test.go @@ -417,12 +417,12 @@ var _ = Describe("Podman login and logout", func() { Expect(authInfo).NotTo(HaveKey(testRepos[1])) }) - It("podman login with repository invalid arguments", func() { + It("podman login with http{s} prefix", func() { authFile := filepath.Join(podmanTest.TempDir, "auth.json") for _, invalidArg := range []string{ "https://" + server + "/podmantest", - server + "/podmantest/image:latest", + "http://" + server + "/podmantest/image:latest", } { session := podmanTest.Podman([]string{ "login", @@ -432,7 +432,7 @@ var _ = Describe("Podman login and logout", func() { invalidArg, }) session.WaitWithDefaultTimeout() - Expect(session).Should(ExitWithError()) + Expect(session).To(Exit(0)) } }) diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index 395759ee6..82b99bd68 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -416,8 +416,8 @@ var _ = Describe("Podman network create", func() { subnet1 := "10.10.3.0/24" gw1 := "10.10.3.10" range1 := "10.10.3.0/26" - subnet2 := "fd52:2a5a:747e:3acd::/64" - gw2 := "fd52:2a5a:747e:3acd::10" + subnet2 := "fd52:2a5a:747e:3ace::/64" + gw2 := "fd52:2a5a:747e:3ace::10" nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--gateway", gw1, "--ip-range", range1, "--subnet", subnet2, "--gateway", gw2, name}) nc.WaitWithDefaultTimeout() defer podmanTest.removeNetwork(name) @@ -440,7 +440,7 @@ var _ = Describe("Podman network create", func() { name := "subnets-" + stringid.GenerateNonCryptoID() subnet1 := "10.10.3.0/24" gw1 := "10.10.3.10" - gw2 := "fd52:2a5a:747e:3acd::10" + gw2 := "fd52:2a5a:747e:3acf::10" nc := podmanTest.Podman([]string{"network", "create", "--subnet", subnet1, "--gateway", gw1, "--gateway", gw2, name}) nc.WaitWithDefaultTimeout() Expect(nc).To(Exit(125)) diff --git a/test/e2e/play_build_test.go b/test/e2e/play_build_test.go index 849ba7162..96785c569 100644 --- a/test/e2e/play_build_test.go +++ b/test/e2e/play_build_test.go @@ -1,3 +1,4 @@ +//go:build !remote // +build !remote // build for play kube is not supported on remote yet. diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index c0c71652e..6a4083565 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -38,6 +38,21 @@ spec: hostname: unknown ` +var workdirSymlinkPodYaml = ` +apiVersion: v1 +kind: Pod +metadata: + labels: + app: test-symlink + name: test-symlink +spec: + containers: + - image: test-symlink + name: test-symlink + resources: {} + restartPolicy: Never +` + var podnameEqualsContainerNameYaml = ` apiVersion: v1 kind: Pod @@ -1332,6 +1347,26 @@ var _ = Describe("Podman play kube", func() { Expect(sharednamespaces).To(ContainSubstring("pid")) }) + It("podman play kube should be able to run image where workdir is a symlink", func() { + session := podmanTest.Podman([]string{ + "build", "-f", "build/workdir-symlink/Dockerfile", "-t", "test-symlink", + }) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + err := writeYaml(workdirSymlinkPodYaml, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + logs := podmanTest.Podman([]string{"pod", "logs", "-c", "test-symlink-test-symlink", "test-symlink"}) + logs.WaitWithDefaultTimeout() + Expect(logs).Should(Exit(0)) + Expect(logs.OutputToString()).To(ContainSubstring("hello")) + }) + It("podman play kube should not rename pod if container in pod has same name", func() { err := writeYaml(podnameEqualsContainerNameYaml, kubeYaml) Expect(err).To(BeNil()) @@ -1853,6 +1888,26 @@ var _ = Describe("Podman play kube", func() { Expect(kube).Should(Exit(0)) }) + It("podman play kube test duplicate container name", func() { + p := getPod(withCtr(getCtr(withName("testctr"), withCmd([]string{"echo", "hello"}))), withCtr(getCtr(withName("testctr"), withCmd([]string{"echo", "world"})))) + + err := generateKubeYaml("pod", p, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).To(ExitWithError()) + + p = getPod(withPodInitCtr(getCtr(withImage(ALPINE), withCmd([]string{"echo", "hello"}), withInitCtr(), withName("initctr"))), withCtr(getCtr(withImage(ALPINE), withName("initctr"), withCmd([]string{"top"})))) + + err = generateKubeYaml("pod", p, kubeYaml) + Expect(err).To(BeNil()) + + kube = podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).To(ExitWithError()) + }) + It("podman play kube test hostname", func() { pod := getPod() err := generateKubeYaml("pod", pod, kubeYaml) diff --git a/test/e2e/run_aardvark_test.go b/test/e2e/run_aardvark_test.go new file mode 100644 index 000000000..c82f614a6 --- /dev/null +++ b/test/e2e/run_aardvark_test.go @@ -0,0 +1,314 @@ +package integration + +import ( + "fmt" + "os" + "strings" + + . "github.com/containers/podman/v4/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("Podman run networking", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + podmanTest.SeedImages() + SkipIfCNI(podmanTest) + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + + }) + + It("Aardvark Test 1: One container", func() { + netName := createNetworkName("Test") + session := podmanTest.Podman([]string{"network", "create", netName}) + session.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netName) + Expect(session).Should(Exit(0)) + + ctrID := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netName, nginx}) + ctrID.WaitWithDefaultTimeout() + Expect(ctrID).Should(Exit(0)) + cid := ctrID.OutputToString() + + ctrIP := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netName), cid}) + ctrIP.WaitWithDefaultTimeout() + Expect(ctrIP).Should(Exit(0)) + cip := ctrIP.OutputToString() + Expect(cip).To(MatchRegexp(IPRegex)) + + _ = digShort(cid, "aone", []string{cip}, podmanTest) + + reverseLookup := podmanTest.Podman([]string{"exec", cid, "dig", "+short", "-x", cip}) + reverseLookup.WaitWithDefaultTimeout() + Expect(reverseLookup).Should(Exit(0)) + revListArray := reverseLookup.OutputToStringArray() + Expect(revListArray).Should(HaveLen(2)) + Expect(strings.TrimRight(revListArray[0], ".")).To(Equal("aone")) + Expect(strings.TrimRight(revListArray[1], ".")).To(Equal(cid[:12])) + + }) + + It("Aardvark Test 2: Two containers, same subnet", func() { + netName := createNetworkName("Test") + session := podmanTest.Podman([]string{"network", "create", netName}) + session.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netName) + Expect(session).Should(Exit(0)) + + ctr1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netName, nginx}) + ctr1.WaitWithDefaultTimeout() + Expect(ctr1).Should(Exit(0)) + cid1 := ctr1.OutputToString() + + ctrIP1 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netName), cid1}) + ctrIP1.WaitWithDefaultTimeout() + Expect(ctrIP1).Should(Exit(0)) + cip1 := ctrIP1.OutputToString() + Expect(cip1).To(MatchRegexp(IPRegex)) + + ctr2 := podmanTest.Podman([]string{"run", "-dt", "--name", "atwo", "--network", netName, nginx}) + ctr2.WaitWithDefaultTimeout() + Expect(ctr2).Should(Exit(0)) + cid2 := ctr2.OutputToString() + + ctrIP2 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netName), cid2}) + ctrIP2.WaitWithDefaultTimeout() + Expect(ctrIP2).Should(Exit(0)) + cip2 := ctrIP2.OutputToString() + Expect(cip2).To(MatchRegexp(IPRegex)) + + _ = digShort("aone", "atwo", []string{cip2}, podmanTest) + + _ = digShort("atwo", "aone", []string{cip1}, podmanTest) + + reverseLookup12 := podmanTest.Podman([]string{"exec", cid1, "dig", "+short", "-x", cip2}) + reverseLookup12.WaitWithDefaultTimeout() + Expect(reverseLookup12).Should(Exit(0)) + revListArray12 := reverseLookup12.OutputToStringArray() + Expect(revListArray12).Should(HaveLen(2)) + Expect(strings.TrimRight(revListArray12[0], ".")).To(Equal("atwo")) + Expect(strings.TrimRight(revListArray12[1], ".")).To(Equal(cid2[:12])) + + reverseLookup21 := podmanTest.Podman([]string{"exec", cid2, "dig", "+short", "-x", cip1}) + reverseLookup21.WaitWithDefaultTimeout() + Expect(reverseLookup21).Should(Exit(0)) + revListArray21 := reverseLookup21.OutputToStringArray() + Expect(revListArray21).Should(HaveLen(2)) + Expect(strings.TrimRight(revListArray21[0], ".")).To(Equal("aone")) + Expect(strings.TrimRight(revListArray21[1], ".")).To(Equal(cid1[:12])) + + }) + + It("Aardvark Test 3: Two containers, same subnet w/aliases", func() { + netName := createNetworkName("Test") + session := podmanTest.Podman([]string{"network", "create", netName}) + session.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netName) + Expect(session).Should(Exit(0)) + + ctr1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netName, "--network-alias", "alias_a1,alias_1a", nginx}) + ctr1.WaitWithDefaultTimeout() + Expect(ctr1).Should(Exit(0)) + + ctrIP1 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netName), "aone"}) + ctrIP1.WaitWithDefaultTimeout() + Expect(ctrIP1).Should(Exit(0)) + cip1 := ctrIP1.OutputToString() + Expect(cip1).To(MatchRegexp(IPRegex)) + + ctr2 := podmanTest.Podman([]string{"run", "-dt", "--name", "atwo", "--network", netName, "--network-alias", "alias_a2,alias_2a", nginx}) + ctr2.WaitWithDefaultTimeout() + Expect(ctr2).Should(Exit(0)) + + ctrIP2 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netName), "atwo"}) + ctrIP2.WaitWithDefaultTimeout() + Expect(ctrIP2).Should(Exit(0)) + cip2 := ctrIP2.OutputToString() + Expect(cip2).To(MatchRegexp(IPRegex)) + + _ = digShort("aone", "atwo", []string{cip2}, podmanTest) + + _ = digShort("aone", "alias_a2", []string{cip2}, podmanTest) + + _ = digShort("aone", "alias_2a", []string{cip2}, podmanTest) + + _ = digShort("atwo", "aone", []string{cip1}, podmanTest) + + _ = digShort("atwo", "alias_a1", []string{cip1}, podmanTest) + + _ = digShort("atwo", "alias_1a", []string{cip1}, podmanTest) + + }) + + It("Aardvark Test 4: Two containers, different subnets", func() { + netNameA := createNetworkName("TestA") + sessionA := podmanTest.Podman([]string{"network", "create", netNameA}) + sessionA.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netNameA) + Expect(sessionA).Should(Exit(0)) + + netNameB := createNetworkName("TestB") + sessionB := podmanTest.Podman([]string{"network", "create", netNameB}) + sessionB.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netNameB) + Expect(sessionB).Should(Exit(0)) + + ctrA1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netNameA, nginx}) + ctrA1.WaitWithDefaultTimeout() + cidA1 := ctrA1.OutputToString() + + ctrB1 := podmanTest.Podman([]string{"run", "-dt", "--name", "bone", "--network", netNameB, nginx}) + ctrB1.WaitWithDefaultTimeout() + cidB1 := ctrB1.OutputToString() + + ctrIPA1 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netNameA), cidA1}) + ctrIPA1.WaitWithDefaultTimeout() + Expect(ctrIPA1).Should(Exit(0)) + cipA1 := ctrIPA1.OutputToString() + Expect(cipA1).To(MatchRegexp(IPRegex)) + + ctrIPB1 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netNameB), cidB1}) + ctrIPB1.WaitWithDefaultTimeout() + Expect(ctrIPB1).Should(Exit(0)) + cipB1 := ctrIPB1.OutputToString() + Expect(cipB1).To(MatchRegexp(IPRegex)) + + resA1B1 := podmanTest.Podman([]string{"exec", "aone", "dig", "+short", "bone"}) + resA1B1.WaitWithDefaultTimeout() + Expect(resA1B1).Should(Exit(0)) + Expect(resA1B1.OutputToString()).To(Equal("")) + + resB1A1 := podmanTest.Podman([]string{"exec", "bone", "dig", "+short", "aone"}) + resB1A1.WaitWithDefaultTimeout() + Expect(resB1A1).Should(Exit(0)) + Expect(resB1A1.OutputToString()).To(Equal("")) + }) + + It("Aardvark Test 5: Two containers on their own subnets, one container on both", func() { + netNameA := createNetworkName("TestA") + sessionA := podmanTest.Podman([]string{"network", "create", netNameA}) + sessionA.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netNameA) + Expect(sessionA).Should(Exit(0)) + + netNameB := createNetworkName("TestB") + sessionB := podmanTest.Podman([]string{"network", "create", netNameB}) + sessionB.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netNameB) + Expect(sessionB).Should(Exit(0)) + + ctrA1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netNameA, nginx}) + ctrA1.WaitWithDefaultTimeout() + cidA1 := ctrA1.OutputToString() + + ctrIPA1 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netNameA), cidA1}) + ctrIPA1.WaitWithDefaultTimeout() + Expect(ctrIPA1).Should(Exit(0)) + cipA1 := ctrIPA1.OutputToString() + Expect(cipA1).To(MatchRegexp(IPRegex)) + + ctrB1 := podmanTest.Podman([]string{"run", "-dt", "--name", "bone", "--network", netNameB, nginx}) + ctrB1.WaitWithDefaultTimeout() + cidB1 := ctrB1.OutputToString() + + ctrIPB1 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netNameB), cidB1}) + ctrIPB1.WaitWithDefaultTimeout() + Expect(ctrIPB1).Should(Exit(0)) + cipB1 := ctrIPB1.OutputToString() + Expect(cipB1).To(MatchRegexp(IPRegex)) + + ctrA2B2 := podmanTest.Podman([]string{"run", "-dt", "--name", "atwobtwo", "--network", netNameA, "--network", netNameB, nginx}) + ctrA2B2.WaitWithDefaultTimeout() + cidA2B2 := ctrA2B2.OutputToString() + + ctrIPA2B21 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netNameA), cidA2B2}) + ctrIPA2B21.WaitWithDefaultTimeout() + Expect(ctrIPA2B21).Should(Exit(0)) + cipA2B21 := ctrIPA2B21.OutputToString() + Expect(cipA2B21).To(MatchRegexp(IPRegex)) + + ctrIPA2B22 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netNameB), cidA2B2}) + ctrIPA2B22.WaitWithDefaultTimeout() + Expect(ctrIPA2B22).Should(Exit(0)) + cipA2B22 := ctrIPA2B22.OutputToString() + Expect(cipA2B22).To(MatchRegexp(IPRegex)) + + _ = digShort("aone", "atwobtwo", []string{cipA2B21}, podmanTest) + + _ = digShort("bone", "atwobtwo", []string{cipA2B22}, podmanTest) + + _ = digShort("atwobtwo", "aone", []string{cipA1}, podmanTest) + + _ = digShort("atwobtwo", "bone", []string{cipB1}, podmanTest) + }) + + It("Aardvark Test 6: Three subnets, first container on 1/2 and second on 2/3, w/ network aliases", func() { + netNameA := createNetworkName("TestA") + sessionA := podmanTest.Podman([]string{"network", "create", netNameA}) + sessionA.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netNameA) + Expect(sessionA).Should(Exit(0)) + + netNameB := createNetworkName("TestB") + sessionB := podmanTest.Podman([]string{"network", "create", netNameB}) + sessionB.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netNameB) + Expect(sessionB).Should(Exit(0)) + + netNameC := createNetworkName("TestC") + sessionC := podmanTest.Podman([]string{"network", "create", netNameC}) + sessionC.WaitWithDefaultTimeout() + defer podmanTest.removeNetwork(netNameC) + Expect(sessionC).Should(Exit(0)) + + ctrA := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netNameA, nginx}) + ctrA.WaitWithDefaultTimeout() + Expect(ctrA).Should(Exit(0)) + + ctrC := podmanTest.Podman([]string{"run", "-dt", "--name", "cone", "--network", netNameC, nginx}) + ctrC.WaitWithDefaultTimeout() + Expect(ctrC).Should(Exit(0)) + + ctrnetAB1 := podmanTest.Podman([]string{"network", "connect", "--alias", "testB1_nw", netNameB, "aone"}) + ctrnetAB1.WaitWithDefaultTimeout() + Expect(ctrnetAB1).Should(Exit(0)) + + ctrIPAB1 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netNameB), "aone"}) + ctrIPAB1.WaitWithDefaultTimeout() + Expect(ctrIPAB1).Should(Exit(0)) + cipAB1 := ctrIPAB1.OutputToString() + + ctrnetCB2 := podmanTest.Podman([]string{"network", "connect", "--alias", "testB2_nw", netNameB, "cone"}) + ctrnetCB2.WaitWithDefaultTimeout() + Expect(ctrnetCB2).Should(Exit(0)) + + ctrIPCB2 := podmanTest.Podman([]string{"inspect", "--format", fmt.Sprintf(`{{.NetworkSettings.Networks.%s.IPAddress}}`, netNameB), "cone"}) + ctrIPCB2.WaitWithDefaultTimeout() + Expect(ctrIPCB2).Should(Exit(0)) + cipCB2 := ctrIPCB2.OutputToString() + + _ = digShort("aone", "testB2_nw", []string{cipCB2}, podmanTest) + + _ = digShort("cone", "testB1_nw", []string{cipAB1}, podmanTest) + + }) + +}) diff --git a/test/e2e/run_apparmor_test.go b/test/e2e/run_apparmor_test.go index e6526217a..64a01deb7 100644 --- a/test/e2e/run_apparmor_test.go +++ b/test/e2e/run_apparmor_test.go @@ -1,3 +1,4 @@ +//go:build !remote // +build !remote package integration diff --git a/test/e2e/run_device_test.go b/test/e2e/run_device_test.go index b8bdc84f8..479837dda 100644 --- a/test/e2e/run_device_test.go +++ b/test/e2e/run_device_test.go @@ -44,6 +44,11 @@ var _ = Describe("Podman run device", func() { session := podmanTest.Podman([]string{"run", "-q", "--security-opt", "label=disable", "--device", "/dev/kmsg", ALPINE, "test", "-c", "/dev/kmsg"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) + if !isRootless() { + session = podmanTest.Podman([]string{"run", "-q", "--security-opt", "label=disable", "--device", "/dev/kmsg", "--cap-add", "SYS_ADMIN", ALPINE, "head", "-n", "1", "/dev/kmsg"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + } }) It("podman run device rename test", func() { diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index aa1887f84..2202cadd8 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -2,15 +2,19 @@ package integration import ( "fmt" + "net" "os" "strings" + "syscall" + "github.com/containernetworking/plugins/pkg/ns" . "github.com/containers/podman/v4/test/utils" "github.com/containers/storage/pkg/stringid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gexec" "github.com/uber/jaeger-client-go/utils" + "github.com/vishvananda/netlink" ) var _ = Describe("Podman run networking", func() { @@ -694,6 +698,157 @@ EXPOSE 2004-2005/tcp`, ALPINE) Expect(session.OutputToString()).To(ContainSubstring("11.11.11.11")) }) + addAddr := func(cidr string, containerInterface netlink.Link) error { + _, ipnet, err := net.ParseCIDR(cidr) + Expect(err).To(BeNil()) + addr := &netlink.Addr{IPNet: ipnet, Label: ""} + if err := netlink.AddrAdd(containerInterface, addr); err != nil && err != syscall.EEXIST { + return err + } + return nil + } + + loopbackup := func() { + lo, err := netlink.LinkByName("lo") + Expect(err).To(BeNil()) + err = netlink.LinkSetUp(lo) + Expect(err).To(BeNil()) + } + + linkup := func(name string, mac string, addresses []string) { + linkAttr := netlink.NewLinkAttrs() + linkAttr.Name = name + m, err := net.ParseMAC(mac) + Expect(err).To(BeNil()) + linkAttr.HardwareAddr = net.HardwareAddr(m) + eth := &netlink.Dummy{LinkAttrs: linkAttr} + err = netlink.LinkAdd(eth) + Expect(err).To(BeNil()) + err = netlink.LinkSetUp(eth) + Expect(err).To(BeNil()) + for _, address := range addresses { + err := addAddr(address, eth) + Expect(err).To(BeNil()) + } + } + + routeAdd := func(gateway string) { + gw := net.ParseIP(gateway) + route := &netlink.Route{Dst: nil, Gw: gw} + netlink.RouteAdd(route) + } + + setupNetworkNs := func(networkNSName string) { + ns.WithNetNSPath("/run/netns/"+networkNSName, func(_ ns.NetNS) error { + loopbackup() + linkup("eth0", "46:7f:45:6e:4f:c8", []string{"10.25.40.0/24", "fd04:3e42:4a4e:3381::/64"}) + linkup("eth1", "56:6e:35:5d:3e:a8", []string{"10.88.0.0/16"}) + + routeAdd("10.25.40.0") + return nil + }) + } + + checkNetworkNsInspect := func(name string) { + inspectOut := podmanTest.InspectContainer(name) + Expect(inspectOut[0].NetworkSettings.IPAddress).To(Equal("10.25.40.0")) + Expect(inspectOut[0].NetworkSettings.IPPrefixLen).To(Equal(24)) + Expect(len(inspectOut[0].NetworkSettings.SecondaryIPAddresses)).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.SecondaryIPAddresses[0].Addr).To(Equal("10.88.0.0")) + Expect(inspectOut[0].NetworkSettings.SecondaryIPAddresses[0].PrefixLength).To(Equal(16)) + Expect(inspectOut[0].NetworkSettings.GlobalIPv6Address).To(Equal("fd04:3e42:4a4e:3381::")) + Expect(inspectOut[0].NetworkSettings.GlobalIPv6PrefixLen).To(Equal(64)) + Expect(len(inspectOut[0].NetworkSettings.SecondaryIPv6Addresses)).To(Equal(0)) + Expect(inspectOut[0].NetworkSettings.MacAddress).To(Equal("46:7f:45:6e:4f:c8")) + Expect(len(inspectOut[0].NetworkSettings.AdditionalMacAddresses)).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.AdditionalMacAddresses[0]).To(Equal("56:6e:35:5d:3e:a8")) + Expect(inspectOut[0].NetworkSettings.Gateway).To(Equal("10.25.40.0")) + + } + + It("podman run newtork inspect fails gracefully on non-reachable network ns", func() { + SkipIfRootless("ip netns is not supported for rootless users") + + networkNSName := RandomString(12) + addNamedNetwork := SystemExec("ip", []string{"netns", "add", networkNSName}) + Expect(addNamedNetwork).Should(Exit(0)) + + setupNetworkNs(networkNSName) + + name := RandomString(12) + session := podmanTest.Podman([]string{"run", "-d", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE, "top"}) + session.WaitWithDefaultTimeout() + + // delete the named network ns before inspect + delNetworkNamespace := SystemExec("ip", []string{"netns", "delete", networkNSName}) + Expect(delNetworkNamespace).Should(Exit(0)) + + inspectOut := podmanTest.InspectContainer(name) + Expect(inspectOut[0].NetworkSettings.IPAddress).To(Equal("")) + Expect(len(inspectOut[0].NetworkSettings.Networks)).To(Equal(0)) + }) + + It("podman inspect can handle joined network ns with multiple interfaces", func() { + SkipIfRootless("ip netns is not supported for rootless users") + + networkNSName := RandomString(12) + addNamedNetwork := SystemExec("ip", []string{"netns", "add", networkNSName}) + Expect(addNamedNetwork).Should(Exit(0)) + defer func() { + delNetworkNamespace := SystemExec("ip", []string{"netns", "delete", networkNSName}) + Expect(delNetworkNamespace).Should(Exit(0)) + }() + setupNetworkNs(networkNSName) + + name := RandomString(12) + session := podmanTest.Podman([]string{"run", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE}) + session.WaitWithDefaultTimeout() + + session = podmanTest.Podman([]string{"container", "rm", name}) + session.WaitWithDefaultTimeout() + + // no network teardown should touch joined network ns interfaces + session = podmanTest.Podman([]string{"run", "-d", "--replace", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE, "top"}) + session.WaitWithDefaultTimeout() + + checkNetworkNsInspect(name) + }) + + It("podman do not tamper with joined network ns interfaces", func() { + SkipIfRootless("ip netns is not supported for rootless users") + + networkNSName := RandomString(12) + addNamedNetwork := SystemExec("ip", []string{"netns", "add", networkNSName}) + Expect(addNamedNetwork).Should(Exit(0)) + defer func() { + delNetworkNamespace := SystemExec("ip", []string{"netns", "delete", networkNSName}) + Expect(delNetworkNamespace).Should(Exit(0)) + }() + + setupNetworkNs(networkNSName) + + name := RandomString(12) + session := podmanTest.Podman([]string{"run", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE}) + session.WaitWithDefaultTimeout() + + checkNetworkNsInspect(name) + + name = RandomString(12) + session = podmanTest.Podman([]string{"run", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE}) + session.WaitWithDefaultTimeout() + + checkNetworkNsInspect(name) + + // delete container, the network inspect should not change + session = podmanTest.Podman([]string{"container", "rm", name}) + session.WaitWithDefaultTimeout() + + session = podmanTest.Podman([]string{"run", "-d", "--replace", "--name", name, "--net", "ns:/run/netns/" + networkNSName, ALPINE, "top"}) + session.WaitWithDefaultTimeout() + + checkNetworkNsInspect(name) + }) + It("podman run network in bogus user created network namespace", func() { session := podmanTest.Podman([]string{"run", "-dt", "--net", "ns:/run/netns/xxy", ALPINE, "wget", "www.podman.io"}) session.Wait(90) diff --git a/test/e2e/system_df_test.go b/test/e2e/system_df_test.go index 2d75316ad..a9fa5f4ac 100644 --- a/test/e2e/system_df_test.go +++ b/test/e2e/system_df_test.go @@ -41,11 +41,17 @@ var _ = Describe("podman system df", func() { session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - session = podmanTest.Podman([]string{"volume", "create", "data"}) + // run two containers with volumes to create something in the volume + session = podmanTest.Podman([]string{"run", "-v", "data1:/data", "--name", "container1", BB, "sh", "-c", "echo test > /data/1"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - session = podmanTest.Podman([]string{"create", "-v", "data:/data", "--name", "container1", BB}) + session = podmanTest.Podman([]string{"run", "-v", "data2:/data", "--name", "container2", BB, "sh", "-c", "echo test > /data/1"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + // remove one container, we keep the volume + session = podmanTest.Podman([]string{"rm", "container2"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -61,9 +67,10 @@ var _ = Describe("podman system df", func() { images := strings.Fields(session.OutputToStringArray()[1]) containers := strings.Fields(session.OutputToStringArray()[2]) volumes := strings.Fields(session.OutputToStringArray()[3]) - Expect(images[1]).To(Equal(string(totImages))) - Expect(containers[1]).To(Equal("2")) - Expect(volumes[2]).To(Equal("1")) + Expect(images[1]).To(Equal(string(totImages)), "total images expected") + Expect(containers[1]).To(Equal("2"), "total containers expected") + Expect(volumes[2]).To(Equal("2"), "total volumes expected") + Expect(volumes[6]).To(Equal("(50%)"), "percentage usage expected") }) It("podman system df image with no tag", func() { diff --git a/test/e2e/system_service_test.go b/test/e2e/system_service_test.go index dcf5e03b2..2bc7756d6 100644 --- a/test/e2e/system_service_test.go +++ b/test/e2e/system_service_test.go @@ -58,6 +58,7 @@ var _ = Describe("podman system service", func() { const magicComment = "pprof service listening on" It("are available", func() { + Skip("FIXME: Test is too flaky (#12624)") SkipIfRemote("service subcommand not supported remotely") address := url.URL{ @@ -97,6 +98,7 @@ var _ = Describe("podman system service", func() { }) It("are not available", func() { + Skip("FIXME: Test is too flaky (#12624)") SkipIfRemote("service subcommand not supported remotely") address := url.URL{ diff --git a/test/e2e/systemd_activate_test.go b/test/e2e/systemd_activate_test.go new file mode 100644 index 000000000..d5434868d --- /dev/null +++ b/test/e2e/systemd_activate_test.go @@ -0,0 +1,107 @@ +package integration + +import ( + "errors" + "fmt" + "io/fs" + "os" + "os/exec" + "path/filepath" + "syscall" + "time" + + testUtils "github.com/containers/podman/v4/test/utils" + podmanUtils "github.com/containers/podman/v4/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("Systemd activate", func() { + var tempDir string + var err error + var podmanTest *PodmanTestIntegration + + BeforeEach(func() { + tempDir, err = testUtils.CreateTempDirInTempDir() + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + os.Exit(1) + } + + podmanTest = PodmanTestCreate(tempDir) + podmanTest.Setup() + podmanTest.SeedImages() + }) + + 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") + if err != nil { + activate = "/usr/bin/systemd-socket-activate" + } + stat, err := os.Stat(activate) + switch { + case errors.Is(err, fs.ErrNotExist): + Skip(activate + " required for systemd activation tests") + case stat.Mode()&0111 == 0: + Skip("Unable to execute " + activate) + case err != nil: + Skip(err.Error()) + } + + // systemd-socket-activate does not support DNS lookups + host := "127.0.0.1" + port, err := podmanUtils.GetRandomPort() + Expect(err).ToNot(HaveOccurred()) + + activateSession := testUtils.StartSystemExec(activate, []string{ + fmt.Sprintf("--listen=%s:%d", host, port), + podmanTest.PodmanBinary, + "--root=" + filepath.Join(tempDir, "server_root"), + "system", "service", + "--time=0", + }) + Expect(activateSession.Exited).ShouldNot(Receive(), "Failed to start podman service") + + // Curried functions for specialized podman calls + podmanRemote := func(args ...string) *testUtils.PodmanSession { + args = append([]string{"--url", fmt.Sprintf("tcp://%s:%d", host, port)}, args...) + return testUtils.SystemExec(podmanTest.RemotePodmanBinary, args) + } + + podman := func(args ...string) *testUtils.PodmanSession { + args = append([]string{"--root", filepath.Join(tempDir, "server_root")}, args...) + return testUtils.SystemExec(podmanTest.PodmanBinary, args) + } + + containerName := "top_" + testUtils.RandomString(8) + apiSession := podmanRemote( + "create", "--tty", "--name", containerName, "--entrypoint", "top", + "quay.io/libpod/alpine_labels:latest", + ) + Expect(apiSession).Should(Exit(0)) + + apiSession = podmanRemote("start", containerName) + Expect(apiSession).Should(Exit(0)) + + apiSession = podmanRemote("inspect", "--format={{.State.Running}}", containerName) + Expect(apiSession).Should(Exit(0)) + Expect(apiSession.OutputToString()).To(Equal("true")) + + // Emulate 'systemd stop podman.service' + activateSession.Signal(syscall.SIGTERM) + time.Sleep(2) + Eventually(activateSession).Should(Exit(0)) + + abiSession := podman("inspect", "--format={{.State.Running}}", containerName) + Expect(abiSession).To(Exit(0)) + Expect(abiSession.OutputToString()).To(Equal("true")) + }) +}) diff --git a/test/system/010-images.bats b/test/system/010-images.bats index ebd71450f..257508418 100644 --- a/test/system/010-images.bats +++ b/test/system/010-images.bats @@ -248,8 +248,7 @@ Labels.created_at | 20[0-9-]\\\+T[0-9:]\\\+Z run_podman inspect --format '{{.ID}}' $IMAGE imageID=$output - run_podman version --format "{{.Server.Version}}-{{.Server.Built}}" - pauseImage=localhost/podman-pause:$output + pauseImage=$(pause_image) run_podman inspect --format '{{.ID}}' $pauseImage pauseID=$output @@ -304,4 +303,13 @@ Deleted: $pauseID" run_podman image exists $IMAGE } +@test "podman rmi --ignore" { + random_image_name=$(random_string) + random_image_name=${random_image_name,,} # name must be lowercase + run_podman 1 rmi $random_image_name + is "$output" "Error: $random_image_name: image not known.*" + run_podman rmi --ignore $random_image_name + is "$output" "" +} + # vim: filetype=sh diff --git a/test/system/070-build.bats b/test/system/070-build.bats index c963d8325..7466c3b74 100644 --- a/test/system/070-build.bats +++ b/test/system/070-build.bats @@ -210,6 +210,30 @@ EOF run_podman rmi -f build_test } +@test "podman parallel build should not race" { + skip_if_remote "following test is not supported for remote clients" + + # Run thirty parallel builds using the same Containerfile + cat >$PODMAN_TMPDIR/Containerfile <<EOF +FROM $IMAGE +RUN echo hi +EOF + + local count=30 + for i in $(seq --format '%02g' 1 $count); do + timeout --foreground -v --kill=10 60 \ + $PODMAN build -t i$i $PODMAN_TMPDIR &>/dev/null & + done + + # Wait for all background builds to complete. Note that this succeeds + # even if some of the individual builds fail! Our actual test is below. + wait + + # Now delete all built images. If any image wasn't built, rmi will fail + # and test will fail. + run_podman rmi $(seq --format 'i%02g' 1 $count) +} + @test "podman build - URLs" { tmpdir=$PODMAN_TMPDIR/build-test mkdir -p $tmpdir @@ -581,7 +605,7 @@ EOF done } -# Regression test for #9867 +# Regression test for #9867 and #13529 # Make sure that if you exclude everything in context dir, that # the Containerfile/Dockerfile in the context dir are used @test "podman build with ignore '*'" { @@ -596,6 +620,15 @@ cat >$tmpdir/.dockerignore <<EOF * EOF + # Prior to the fix for #13529, pod-create would fail with 'error building + # at STEP COPY .../catatonit' because of the local .dockerignore file was + # used. + pushd "${tmpdir}" + run_podman pod create + run_podman pod rm $output + run_podman rmi $(pause_image) + popd + run_podman build -t build_test $tmpdir # Rename Containerfile to Dockerfile diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index 34dfaa8f6..f5fe41924 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -6,13 +6,7 @@ load helpers function teardown() { run_podman pod rm -f -t 0 -a run_podman rm -f -t 0 -a - run_podman image list --format '{{.ID}} {{.Repository}}' - while read id name; do - if [[ "$name" =~ /podman-pause ]]; then - run_podman rmi $id - fi - done <<<"$output" - + run_podman rmi --ignore $(pause_image) basic_teardown } @@ -323,16 +317,17 @@ EOF @test "podman pod create should fail when infra-name is already in use" { local infra_name="infra_container_$(random_string 10 | tr A-Z a-z)" + local infra_image="k8s.gcr.io/pause:3.5" local pod_name="$(random_string 10 | tr A-Z a-z)" - run_podman --noout pod create --name $pod_name --infra-name "$infra_name" --infra-image "k8s.gcr.io/pause:3.5" - is "$output" "" "output should be empty" + run_podman --noout pod create --name $pod_name --infra-name "$infra_name" --infra-image "$infra_image" + is "$output" "" "output from pod create should be empty" run_podman '?' pod create --infra-name "$infra_name" if [ $status -eq 0 ]; then die "Podman should fail when user try to create two pods with the same infra-name value" fi run_podman pod rm -f $pod_name - run_podman images -a + run_podman rmi $infra_image } @test "podman pod create --share" { diff --git a/test/system/700-play.bats b/test/system/700-play.bats index 88c7cad87..8af4cd25b 100644 --- a/test/system/700-play.bats +++ b/test/system/700-play.bats @@ -168,3 +168,68 @@ _EOF run_podman pod rm -t 0 -f test_pod run_podman rmi -f userimage:latest } + +@test "podman play --build --context-dir" { + skip_if_remote "--build is not supported in context remote" + testUserYaml=" +apiVersion: v1 +kind: Pod +metadata: + labels: + app: test + name: test_pod +spec: + containers: + - command: + - id + env: + - name: PATH + value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + - name: TERM + value: xterm + - name: container + value: podman + image: quay.io/libpod/userimage + name: test + resources: {} +status: {} +" + +mkdir -p $PODMAN_TMPDIR/userimage +cat > $PODMAN_TMPDIR/userimage/Containerfile << _EOF +from $IMAGE +USER bin +_EOF + + echo "$testUserYaml" > $PODMAN_TMPDIR/test.yaml + run_podman 125 play kube --build --start=false $PODMAN_TMPDIR/test.yaml + run_podman play kube --replace --context-dir=$PODMAN_TMPDIR --build --start=false $PODMAN_TMPDIR/test.yaml + run_podman inspect --format "{{ .Config.User }}" test_pod-test + is "$output" bin "expect container within pod to run as the bin user" + + run_podman stop -a -t 0 + run_podman pod rm -t 0 -f test_pod + run_podman rmi -f userimage:latest + + cd $PODMAN_TMPDIR + run_podman play kube --replace --build --start=false $PODMAN_TMPDIR/test.yaml + run_podman inspect --format "{{ .Config.User }}" test_pod-test + is "$output" bin "expect container within pod to run as the bin user" + + run_podman stop -a -t 0 + run_podman pod rm -t 0 -f test_pod + run_podman rmi -f userimage:latest +} + +@test "podman play --annotation" { + TESTDIR=$PODMAN_TMPDIR/testdir + RANDOMSTRING=$(random_string 15) + mkdir -p $TESTDIR + echo "$testYaml" | sed "s|TESTDIR|${TESTDIR}|g" > $PODMAN_TMPDIR/test.yaml + run_podman play kube --annotation "name=$RANDOMSTRING" $PODMAN_TMPDIR/test.yaml + run_podman inspect --format "{{ .Config.Annotations }}" test_pod-test + is "$output" ".*name:$RANDOMSTRING" "Annotation should be added to pod" + + run_podman stop -a -t 0 + run_podman pod rm -t 0 -f test_pod +} diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 221315b97..0d336592f 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -383,6 +383,15 @@ function journald_unavailable() { return 1 } +# Returns the name of the local pause image. +function pause_image() { + # This function is intended to be used as '$(pause_image)', i.e. + # our caller wants our output. run_podman() messes with output because + # it emits the command invocation to stdout, hence the redirection. + run_podman version --format "{{.Server.Version}}-{{.Server.Built}}" >/dev/null + echo "localhost/podman-pause:$output" +} + ########################### # _add_label_if_missing # make sure skip messages include rootless/remote ########################### diff --git a/test/utils/common_function_test.go b/test/utils/common_function_test.go index 810d9f2a5..6323b44eb 100644 --- a/test/utils/common_function_test.go +++ b/test/utils/common_function_test.go @@ -51,7 +51,8 @@ var _ = Describe("Common functions test", func() { txt := fmt.Sprintf("ID=%s\nVERSION_ID=%s", id, ver) if !empty { f, _ := os.Create(path) - f.WriteString(txt) + _, err := f.WriteString(txt) + Expect(err).To(BeNil(), "Failed to write data.") f.Close() } @@ -102,9 +103,10 @@ var _ = Describe("Common functions test", func() { Item2: []string{"test"}, } - testByte, _ := json.Marshal(testData) - err := WriteJSONFile(testByte, "/tmp/testJSON") + testByte, err := json.Marshal(testData) + Expect(err).To(BeNil(), "Failed to marshal data.") + err = WriteJSONFile(testByte, "/tmp/testJSON") Expect(err).To(BeNil(), "Failed to write JSON to file.") read, err := os.Open("/tmp/testJSON") @@ -135,7 +137,8 @@ var _ = Describe("Common functions test", func() { } if createFile { f, _ := os.Create(path) - f.WriteString(txt) + _, err := f.WriteString(txt) + Expect(err).To(BeNil(), "Failed to write data.") f.Close() } ProcessOneCgroupPath = path diff --git a/test/utils/matchers.go b/test/utils/matchers.go index 288779b63..0c0948e4b 100644 --- a/test/utils/matchers.go +++ b/test/utils/matchers.go @@ -13,7 +13,7 @@ import ( "github.com/onsi/gomega/types" ) -// HaveActiveService verifies the given service is the active service +// HaveActiveService verifies the given service is the active service. func HaveActiveService(name interface{}) OmegaMatcher { return WithTransform( func(cfg *config.Config) string { @@ -86,7 +86,7 @@ type URLMatcher struct { matchers.EqualMatcher } -// VerifyURL matches when actual is a valid URL and matches expected +// VerifyURL matches when actual is a valid URL and matches expected. func VerifyURL(uri interface{}) OmegaMatcher { return &URLMatcher{matchers.EqualMatcher{Expected: uri}} } @@ -129,7 +129,7 @@ func ExitWithError(optionalExitCode ...int) *ExitMatcher { return &ExitMatcher{Expected: exitCode} } -// Match follows gexec.Matcher interface +// Match follows gexec.Matcher interface. func (matcher *ExitMatcher) Match(actual interface{}) (success bool, err error) { exiter, ok := actual.(gexec.Exiter) if !ok { @@ -184,7 +184,7 @@ func (matcher *ValidJSONMatcher) Match(actual interface{}) (success bool, err er var i interface{} if err := json.Unmarshal([]byte(s), &i); err != nil { - return false, nil + return false, err } return true, nil } diff --git a/test/utils/utils.go b/test/utils/utils.go index 14092a2a5..a6295cd19 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -368,6 +368,7 @@ func CreateTempDirInTempDir() (string, error) { // SystemExec is used to exec a system command to check its exit code or output func SystemExec(command string, args []string) *PodmanSession { c := exec.Command(command, args...) + fmt.Println("Execing " + c.String() + "\n") session, err := Start(c, GinkgoWriter, GinkgoWriter) if err != nil { Fail(fmt.Sprintf("unable to run command: %s %s", command, strings.Join(args, " "))) @@ -379,6 +380,7 @@ func SystemExec(command string, args []string) *PodmanSession { // StartSystemExec is used to start exec a system command func StartSystemExec(command string, args []string) *PodmanSession { c := exec.Command(command, args...) + fmt.Println("Execing " + c.String() + "\n") session, err := Start(c, GinkgoWriter, GinkgoWriter) if err != nil { Fail(fmt.Sprintf("unable to run command: %s %s", command, strings.Join(args, " "))) @@ -477,7 +479,10 @@ func IsCommandAvailable(command string) bool { func WriteJSONFile(data []byte, filePath string) error { var jsonData map[string]interface{} json.Unmarshal(data, &jsonData) - formatJSON, _ := json.MarshalIndent(jsonData, "", " ") + formatJSON, err := json.MarshalIndent(jsonData, "", " ") + if err != nil { + return err + } return ioutil.WriteFile(filePath, formatJSON, 0644) } |