diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/apiv2/01-basic.at | 2 | ||||
-rw-r--r-- | test/apiv2/12-imagesMore.at | 4 | ||||
-rw-r--r-- | test/apiv2/20-containers.at | 9 | ||||
-rw-r--r-- | test/apiv2/44-mounts.at | 2 | ||||
-rw-r--r-- | test/apiv2/60-auth.at | 29 | ||||
-rwxr-xr-x | test/apiv2/test-apiv2 | 115 | ||||
-rw-r--r-- | test/e2e/generate_kube_test.go | 32 | ||||
-rw-r--r-- | test/e2e/network_connect_disconnect_test.go | 7 | ||||
-rw-r--r-- | test/e2e/network_test.go | 23 | ||||
-rw-r--r-- | test/e2e/run_selinux_test.go | 49 | ||||
-rw-r--r-- | test/e2e/stop_test.go | 4 | ||||
-rw-r--r-- | test/python/docker/build_labels/Dockerfile | 1 | ||||
-rw-r--r-- | test/python/docker/compat/test_images.py | 8 | ||||
-rw-r--r-- | test/system/065-cp.bats | 315 | ||||
-rw-r--r-- | test/system/070-build.bats | 114 | ||||
-rw-r--r-- | test/system/120-load.bats | 7 | ||||
-rw-r--r-- | test/system/410-selinux.bats | 21 |
17 files changed, 653 insertions, 89 deletions
diff --git a/test/apiv2/01-basic.at b/test/apiv2/01-basic.at index 1ddf49c6f..1357e0ca6 100644 --- a/test/apiv2/01-basic.at +++ b/test/apiv2/01-basic.at @@ -18,7 +18,7 @@ t HEAD libpod/_ping 200 for i in /version version; do t GET $i 200 \ .Components[0].Name="Podman Engine" \ - .Components[0].Details.APIVersion=3.0.0 \ + .Components[0].Details.APIVersion=3.1.0-dev \ .Components[0].Details.MinAPIVersion=3.0.0 \ .Components[0].Details.Os=linux \ .ApiVersion=1.40 \ diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at index 4f3ddf925..ce3049106 100644 --- a/test/apiv2/12-imagesMore.at +++ b/test/apiv2/12-imagesMore.at @@ -46,6 +46,10 @@ t POST "images/localhost:5000/myrepo/push?tlsVerify=false&tag=mytag" '' 200 # Untag the image t POST "libpod/images/$iid/untag?repo=localhost:5000/myrepo&tag=mytag" '' 201 +# Try to push non-existing image +t POST "images/localhost:5000/idonotexist/push?tlsVerify=false" '' 200 +jq -re 'select(.errorDetail)' <<<"$output" &>/dev/null || echo -e "${red}not ok: error message not found in output${nc}" 1>&2 + t GET libpod/images/$IMAGE/json 200 \ .RepoTags[-1]=$IMAGE diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at index 18364a47d..f73d03123 100644 --- a/test/apiv2/20-containers.at +++ b/test/apiv2/20-containers.at @@ -263,3 +263,12 @@ t GET containers/json 200 \ .[0].Ports[0].Type="tcp" podman stop bar + +# Test CPU limit (NanoCPUs) +t POST containers/create '"Image":"'$IMAGE'","HostConfig":{"NanoCpus":500000}' 201 \ + .Id~[0-9a-f]\\{64\\} +cid=$(jq -r '.Id' <<<"$output") +t GET containers/$cid/json 200 \ + .HostConfig.NanoCpus=500000 + +t DELETE containers/$cid?v=true 204 diff --git a/test/apiv2/44-mounts.at b/test/apiv2/44-mounts.at index fe202576d..5dc560852 100644 --- a/test/apiv2/44-mounts.at +++ b/test/apiv2/44-mounts.at @@ -4,7 +4,7 @@ podman pull $IMAGE &>/dev/null # Test various HostConfig options tmpfs_name="/mytmpfs" -t POST containers/create?name=hostconfig_test '"Image":"'$IMAGE'","Cmd":["df"],"HostConfig":{"TmpFs":{"'$tmpfs_name'":"rw"}}' 201 \ +t POST containers/create?name=hostconfig_test '"Image":"'$IMAGE'","Cmd":["df"],"HostConfig":{"Binds":["/tmp/doesnotexist:/test1"],"TmpFs":{"'$tmpfs_name'":"rw"}}' 201 \ .Id~[0-9a-f]\\{64\\} cid=$(jq -r '.Id' <<<"$output") diff --git a/test/apiv2/60-auth.at b/test/apiv2/60-auth.at new file mode 100644 index 000000000..378955cd7 --- /dev/null +++ b/test/apiv2/60-auth.at @@ -0,0 +1,29 @@ +# -*- sh -*- +# +# registry-related tests +# + +start_registry + +# FIXME FIXME FIXME: remove the 'if false' for use with PR 9589 +if false; then + +# FIXME FIXME: please forgive the horrible POST params format; I have an +# upcoming PR which should fix that. + +# Test with wrong password. Confirm bad status and appropriate error message +t POST /v1.40/auth "\"username\":\"${REGISTRY_USERNAME}\",\"password\":\"WrOnGPassWord\",\"serveraddress\":\"localhost:$REGISTRY_PORT/\"" \ + 400 \ + .Status~'.* invalid username/password' + +# Test with the right password. Confirm status message and reasonable token +t POST /v1.40/auth "\"username\":\"${REGISTRY_USERNAME}\",\"password\":\"${REGISTRY_PASSWORD}\",\"serveraddress\":\"localhost:$REGISTRY_PORT/\"" \ + 200 \ + .Status="Login Succeeded" \ + .IdentityToken~[a-zA-Z0-9] + +# FIXME: now what? Try something-something using that token? +token=$(jq -r .IdentityToken <<<"$output") +# ... + +fi # FIXME FIXME FIXME: remove when working diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2 index d545df245..e32d6bc62 100755 --- a/test/apiv2/test-apiv2 +++ b/test/apiv2/test-apiv2 @@ -17,6 +17,8 @@ PODMAN_TEST_IMAGE_FQN="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODM IMAGE=$PODMAN_TEST_IMAGE_FQN +REGISTRY_IMAGE="${PODMAN_TEST_IMAGE_REGISTRY}/${PODMAN_TEST_IMAGE_USER}/registry:2.7" + # END stuff you can but probably shouldn't customize ############################################################################### # BEGIN setup @@ -313,13 +315,115 @@ function start_service() { die "Cannot start service on non-localhost ($HOST)" fi - $PODMAN_BIN --root $WORKDIR system service --time 15 tcp:127.0.0.1:$PORT \ + $PODMAN_BIN --root $WORKDIR/server_root system service \ + --time 15 \ + tcp:127.0.0.1:$PORT \ &> $WORKDIR/server.log & service_pid=$! wait_for_port $HOST $PORT } +function stop_service() { + # Stop the server + if [[ -n $service_pid ]]; then + kill $service_pid + wait $service_pid + fi +} + +#################### +# start_registry # Run a local registry +#################### +REGISTRY_PORT= +REGISTRY_USERNAME= +REGISTRY_PASSWORD= +function start_registry() { + # We can be invoked multiple times, e.g. from different subtests, but + # let's assume that once started we only kill it at the end of tests. + if [[ -n "$REGISTRY_PORT" ]]; then + return + fi + + REGISTRY_PORT=$(random_port) + REGISTRY_USERNAME=u$(random_string 7) + REGISTRY_PASSWORD=p$(random_string 7) + + local REGDIR=$WORKDIR/registry + local AUTHDIR=$REGDIR/auth + mkdir -p $AUTHDIR + + mkdir -p ${REGDIR}/{root,runroot} + local PODMAN_REGISTRY_ARGS="--root ${REGDIR}/root --runroot ${REGDIR}/runroot" + + # Give it three tries, to compensate for network flakes + podman ${PODMAN_REGISTRY_ARGS} pull $REGISTRY_IMAGE || + podman ${PODMAN_REGISTRY_ARGS} pull $REGISTRY_IMAGE || + podman ${PODMAN_REGISTRY_ARGS} pull $REGISTRY_IMAGE + + # Create a local cert and credentials + # FIXME: is there a hidden "--quiet" flag? This is too noisy. + openssl req -newkey rsa:4096 -nodes -sha256 \ + -keyout $AUTHDIR/domain.key -x509 -days 2 \ + -out $AUTHDIR/domain.crt \ + -subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=registry host certificate" \ + -addext subjectAltName=DNS:localhost + htpasswd -Bbn ${REGISTRY_USERNAME} ${REGISTRY_PASSWORD} \ + > $AUTHDIR/htpasswd + + # Run the registry, and wait for it to come up + podman ${PODMAN_REGISTRY_ARGS} run -d \ + -p ${REGISTRY_PORT}:5000 \ + --name registry \ + -v $AUTHDIR:/auth:Z \ + -e "REGISTRY_AUTH=htpasswd" \ + -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ + -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \ + -e REGISTRY_HTTP_TLS_CERTIFICATE=/auth/domain.crt \ + -e REGISTRY_HTTP_TLS_KEY=/auth/domain.key \ + ${REGISTRY_IMAGE} + + wait_for_port localhost $REGISTRY_PORT +} + +function stop_registry() { + local REGDIR=${WORKDIR}/registry + if [[ -d $REGDIR ]]; then + local OPTS="--root ${REGDIR}/root --runroot ${REGDIR}/runroot" + podman $OPTS stop -f -t 0 -a + + # rm/rmi are important when running rootless: without them we + # get EPERMS in tmpdir cleanup because files are owned by subuids. + podman $OPTS rm -f -a + podman $OPTS rmi -f -a + fi +} + +################# +# random_port # Random open port; arg is range (min-max), default 5000-5999 +################# +function random_port() { + local range=${1:-5000-5999} + + local port + for port in $(shuf -i ${range}); do + if ! { exec 5<> /dev/tcp/127.0.0.1/$port; } &>/dev/null; then + echo $port + return + fi + done + + die "Could not find open port in range $range" +} + +################### +# random_string # Pseudorandom alphanumeric string of given length +################### +function random_string() { + local length=${1:-10} + head /dev/urandom | tr -dc a-zA-Z0-9 | head -c$length +} + ################### # wait_for_port # Returns once port is available on host ################### @@ -341,8 +445,8 @@ function wait_for_port() { # podman # Needed by some test scripts to invoke the actual podman binary ############ function podman() { - echo "\$ $PODMAN_BIN $*" >>$WORKDIR/output.log - $PODMAN_BIN --root $WORKDIR "$@" >>$WORKDIR/output.log 2>&1 + echo "\$ $PODMAN_BIN $*" >>$WORKDIR/output.log + $PODMAN_BIN --root $WORKDIR/server_root "$@" >>$WORKDIR/output.log 2>&1 } #################### @@ -412,9 +516,8 @@ if [ -n "$service_pid" ]; then podman rm -a podman rmi -af - # Stop the server - kill $service_pid - wait $service_pid + stop_registry + stop_service fi test_count=$(<$testcounter_file) diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go index d7c697f28..21e006c20 100644 --- a/test/e2e/generate_kube_test.go +++ b/test/e2e/generate_kube_test.go @@ -734,4 +734,36 @@ ENTRYPOINT /bin/sleep` kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(0)) }) + + It("podman generate kube based on user in container", func() { + // Build an image with an entrypoint. + containerfile := `FROM quay.io/libpod/alpine:latest +RUN adduser -u 10001 -S test1 +USER test1` + + targetPath, err := CreateTempDirInTempDir() + Expect(err).To(BeNil()) + containerfilePath := filepath.Join(targetPath, "Containerfile") + err = ioutil.WriteFile(containerfilePath, []byte(containerfile), 0644) + Expect(err).To(BeNil()) + + image := "generatekube:test" + session := podmanTest.Podman([]string{"build", "-f", containerfilePath, "-t", image}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"create", "--pod", "new:testpod", image, "test1"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + kube := podmanTest.Podman([]string{"generate", "kube", "testpod"}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + pod := new(v1.Pod) + err = yaml.Unmarshal(kube.Out.Contents(), pod) + Expect(err).To(BeNil()) + Expect(*pod.Spec.Containers[0].SecurityContext.RunAsUser).To(Equal(int64(10001))) + }) + }) diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go index eb8ad7181..e9a7b421f 100644 --- a/test/e2e/network_connect_disconnect_test.go +++ b/test/e2e/network_connect_disconnect_test.go @@ -193,6 +193,13 @@ var _ = Describe("Podman network connect and disconnect", func() { exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth1"}) exec.WaitWithDefaultTimeout() Expect(exec.ExitCode()).To(BeZero()) + + // make sure no logrus errors are shown https://github.com/containers/podman/issues/9602 + rm := podmanTest.Podman([]string{"rm", "-f", "test"}) + rm.WaitWithDefaultTimeout() + Expect(rm.ExitCode()).To(BeZero()) + Expect(rm.ErrorToString()).To(Equal("")) + }) It("podman network connect when not running", func() { diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index 53521cdc4..ff2e1eb66 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -352,6 +352,29 @@ var _ = Describe("Podman network", func() { Expect(rmAll.ExitCode()).To(BeZero()) }) + It("podman network remove after disconnect when container initially created with the network", func() { + SkipIfRootless("disconnect works only in non rootless container") + + container := "test" + network := "foo" + + session := podmanTest.Podman([]string{"network", "create", network}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"run", "--name", container, "--network", network, "-d", ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"network", "disconnect", network, container}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"network", "rm", network}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman network remove bogus", func() { session := podmanTest.Podman([]string{"network", "rm", "bogus"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/run_selinux_test.go b/test/e2e/run_selinux_test.go index 8c712b1be..6abe152a9 100644 --- a/test/e2e/run_selinux_test.go +++ b/test/e2e/run_selinux_test.go @@ -2,6 +2,7 @@ package integration import ( "os" + "path/filepath" . "github.com/containers/podman/v3/test/utils" . "github.com/onsi/ginkgo" @@ -294,4 +295,52 @@ var _ = Describe("Podman run", func() { Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("container_t")) }) + + It("podman test --ipc=net", func() { + session := podmanTest.Podman([]string{"run", "--net=host", ALPINE, "cat", "/proc/self/attr/current"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("container_t")) + }) + + It("podman test --ipc=net", func() { + session := podmanTest.Podman([]string{"run", "--net=host", ALPINE, "cat", "/proc/self/attr/current"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("container_t")) + }) + + It("podman test --runtime=/PATHTO/kata-runtime", func() { + runtime := podmanTest.OCIRuntime + podmanTest.OCIRuntime = filepath.Join(podmanTest.TempDir, "kata-runtime") + err := os.Symlink("/bin/true", podmanTest.OCIRuntime) + Expect(err).To(BeNil()) + if IsRemote() { + podmanTest.StopRemoteService() + podmanTest.StartRemoteService() + } + session := podmanTest.Podman([]string{"create", ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + cid := session.OutputToString() + session = podmanTest.Podman([]string{"inspect", "--format", "{{ .ProcessLabel }}", cid}) + session.WaitWithDefaultTimeout() + Expect(session.OutputToString()).To(ContainSubstring("container_kvm_t")) + + podmanTest.OCIRuntime = runtime + if IsRemote() { + podmanTest.StopRemoteService() + podmanTest.StartRemoteService() + } + }) + + It("podman test init labels", func() { + session := podmanTest.Podman([]string{"create", ubi_init, "/sbin/init"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + cid := session.OutputToString() + session = podmanTest.Podman([]string{"inspect", "--format", "{{ .ProcessLabel }}", cid}) + session.WaitWithDefaultTimeout() + Expect(session.OutputToString()).To(ContainSubstring("container_init_t")) + }) }) diff --git a/test/e2e/stop_test.go b/test/e2e/stop_test.go index dd264eb0d..d6d58c94c 100644 --- a/test/e2e/stop_test.go +++ b/test/e2e/stop_test.go @@ -150,7 +150,7 @@ var _ = Describe("Podman stop", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"stop", "--time", "1", "test4"}) + session = podmanTest.Podman([]string{"stop", "--time", "0", "test4"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) output := session.OutputToString() @@ -166,7 +166,7 @@ var _ = Describe("Podman stop", func() { session := podmanTest.Podman([]string{"run", "-d", "--name", "test5", ALPINE, "sleep", "100"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"stop", "--timeout", "1", "test5"}) + session = podmanTest.Podman([]string{"stop", "--timeout", "0", "test5"}) // Without timeout container stops in 10 seconds // If not stopped in 5 seconds, then --timeout did not work session.Wait(5) diff --git a/test/python/docker/build_labels/Dockerfile b/test/python/docker/build_labels/Dockerfile new file mode 100644 index 000000000..f6e07066c --- /dev/null +++ b/test/python/docker/build_labels/Dockerfile @@ -0,0 +1 @@ +FROM quay.io/libpod/alpine:latest diff --git a/test/python/docker/compat/test_images.py b/test/python/docker/compat/test_images.py index 842e38f31..4a90069a9 100644 --- a/test/python/docker/compat/test_images.py +++ b/test/python/docker/compat/test_images.py @@ -149,6 +149,14 @@ class TestImages(unittest.TestCase): self.assertEqual(len(self.client.images.list()), 2) + def test_build_image(self): + labels = {"apple": "red", "grape": "green"} + _ = self.client.images.build(path="test/python/docker/build_labels", labels=labels, tag="labels") + image = self.client.images.get("labels") + self.assertEqual(image.labels["apple"], labels["apple"]) + self.assertEqual(image.labels["grape"], labels["grape"]) + + if __name__ == "__main__": # Setup temporary space diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats index 312106b36..73e807843 100644 --- a/test/system/065-cp.bats +++ b/test/system/065-cp.bats @@ -15,6 +15,7 @@ load helpers random-1-$(random_string 15) random-2-$(random_string 20) ) + echo "${randomcontent[0]}" > $srcdir/hostfile0 echo "${randomcontent[1]}" > $srcdir/hostfile1 echo "${randomcontent[2]}" > $srcdir/hostfile2 @@ -24,6 +25,10 @@ load helpers run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sleep infinity run_podman exec cpcontainer mkdir /srv/subdir + # Commit the image for testing non-running containers + run_podman commit -q cpcontainer + cpimage="$output" + # format is: <id> | <destination arg to cp> | <full dest path> | <test name> # where: # id is 0-2, one of the random strings/files @@ -44,8 +49,7 @@ load helpers 0 | subdir | /srv/subdir/hostfile0 | copy to workdir/subdir " - # Copy one of the files into container, exec+cat, confirm the file - # is there and matches what we expect + # RUNNING container while read id dest dest_fullname description; do run_podman cp $srcdir/hostfile$id cpcontainer:$dest run_podman exec cpcontainer cat $dest_fullname @@ -67,6 +71,61 @@ load helpers is "$output" 'Error: "/IdoNotExist/" could not be found on container cpcontainer: No such file or directory' \ "copy into nonexistent path in container" + run_podman kill cpcontainer + run_podman rm -f cpcontainer + + # CREATED container + while read id dest dest_fullname description; do + run_podman create --name cpcontainer --workdir=/srv $cpimage sleep infinity + run_podman cp $srcdir/hostfile$id cpcontainer:$dest + run_podman start cpcontainer + run_podman exec cpcontainer cat $dest_fullname + is "$output" "${randomcontent[$id]}" "$description (cp -> ctr:$dest)" + run_podman kill cpcontainer + run_podman rm -f cpcontainer + done < <(parse_table "$tests") + + run_podman rmi -f $cpimage +} + + +@test "podman cp file from host to container tmpfs mount" { + srcdir=$PODMAN_TMPDIR/cp-test-file-host-to-ctr + mkdir -p $srcdir + content=tmpfile-content$(random_string 20) + echo $content > $srcdir/file + + # RUNNING container + run_podman run -d --mount type=tmpfs,dst=/tmp --name cpcontainer $IMAGE sleep infinity + run_podman cp $srcdir/file cpcontainer:/tmp + run_podman exec cpcontainer cat /tmp/file + is "$output" "${content}" "cp to running container's tmpfs" + run_podman kill cpcontainer + run_podman rm -f cpcontainer + + # CREATED container (with copy up) + run_podman create --mount type=tmpfs,dst=/tmp --name cpcontainer $IMAGE sleep infinity + run_podman cp $srcdir/file cpcontainer:/tmp + run_podman start cpcontainer + run_podman exec cpcontainer cat /tmp/file + is "$output" "${content}" "cp to created container's tmpfs" + run_podman kill cpcontainer + run_podman rm -f cpcontainer +} + + +@test "podman cp file from host to container and check ownership" { + srcdir=$PODMAN_TMPDIR/cp-test-file-host-to-ctr + mkdir -p $srcdir + content=cp-user-test-$(random_string 10) + echo "content" > $srcdir/hostfile + userid=$(id -u) + + run_podman run --user=$userid --userns=keep-id -d --name cpcontainer $IMAGE sleep infinity + run_podman cp $srcdir/hostfile cpcontainer:/tmp/hostfile + run_podman exec cpcontainer stat -c "%u" /tmp/hostfile + is "$output" "$userid" "copied file is chowned to the container user" + run_podman kill cpcontainer run_podman rm -f cpcontainer } @@ -87,6 +146,10 @@ load helpers run_podman exec cpcontainer sh -c "echo ${randomcontent[1]} > /srv/containerfile1" run_podman exec cpcontainer sh -c "mkdir /srv/subdir; echo ${randomcontent[2]} > /srv/subdir/containerfile2" + # Commit the image for testing non-running containers + run_podman commit -q cpcontainer + cpimage="$output" + # format is: <id> | <source arg to cp> | <destination arg (appended to $srcdir) to cp> | <full dest path (appended to $srcdir)> | <test name> tests=" 0 | /tmp/containerfile | | /containerfile | copy to srcdir/ @@ -98,109 +161,214 @@ load helpers 2 | subdir/containerfile2 | / | /containerfile2 | copy from workdir/subdir (rel path) to srcdir " - # Copy one of the files to the host, cat, confirm the file - # is there and matches what we expect + # RUNNING container while read id src dest dest_fullname description; do # dest may be "''" for empty table cells if [[ $dest == "''" ]];then unset dest fi run_podman cp cpcontainer:$src "$srcdir$dest" - run cat $srcdir$dest_fullname - is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to \$srcdir$dest)" - rm $srcdir/$dest_fullname + is "$(< $srcdir$dest_fullname)" "${randomcontent[$id]}" "$description (cp ctr:$src to \$srcdir$dest)" + rm $srcdir$dest_fullname done < <(parse_table "$tests") + run_podman kill cpcontainer + run_podman rm -f cpcontainer + # Created container + run_podman create --name cpcontainer --workdir=/srv $cpimage + while read id src dest dest_fullname description; do + # dest may be "''" for empty table cells + if [[ $dest == "''" ]];then + unset dest + fi + run_podman cp cpcontainer:$src "$srcdir$dest" + is "$(< $srcdir$dest_fullname)" "${randomcontent[$id]}" "$description (cp ctr:$src to \$srcdir$dest)" + rm $srcdir$dest_fullname + done < <(parse_table "$tests") run_podman rm -f cpcontainer + + run_podman rmi -f $cpimage } @test "podman cp dir from host to container" { - dirname=dir-test - srcdir=$PODMAN_TMPDIR/$dirname - mkdir -p $srcdir + srcdir=$PODMAN_TMPDIR + mkdir -p $srcdir/dir/sub local -a randomcontent=( random-0-$(random_string 10) random-1-$(random_string 15) ) - echo "${randomcontent[0]}" > $srcdir/hostfile0 - echo "${randomcontent[1]}" > $srcdir/hostfile1 + echo "${randomcontent[0]}" > $srcdir/dir/sub/hostfile0 + echo "${randomcontent[1]}" > $srcdir/dir/sub/hostfile1 # "." and "dir/." will copy the contents, so make sure that a dir ending # with dot is treated correctly. - mkdir -p $srcdir. - cp $srcdir/* $srcdir./ + mkdir -p $srcdir/dir. + cp -r $srcdir/dir/* $srcdir/dir. run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sleep infinity run_podman exec cpcontainer mkdir /srv/subdir + # Commit the image for testing non-running containers + run_podman commit -q cpcontainer + cpimage="$output" + # format is: <source arg to cp (appended to srcdir)> | <destination arg to cp> | <full dest path> | <test name> tests=" - | / | /dir-test | copy to root - . | / | /dir-test. | copy dotdir to root - / | /tmp | /tmp/dir-test | copy to tmp - /. | /usr/ | /usr/ | copy contents of dir to usr/ - | . | /srv/dir-test | copy to workdir (rel path) - | subdir/. | /srv/subdir/dir-test | copy to workdir subdir (rel path) + dir | / | /dir/sub | copy dir to root + dir. | / | /dir./sub | copy dir. to root + dir/ | /tmp | /tmp/dir/sub | copy dir/ to tmp + dir/. | /usr/ | /usr/sub | copy dir/. usr/ + dir/sub | . | /srv/sub | copy dir/sub to workdir (rel path) + dir/sub/. | subdir/. | /srv/subdir | copy dir/sub/. to workdir subdir (rel path) + dir | /newdir1 | /newdir1/sub | copy dir to newdir1 + dir/ | /newdir2 | /newdir2/sub | copy dir/ to newdir2 + dir/. | /newdir3 | /newdir3/sub | copy dir/. to newdir3 " + # RUNNING container while read src dest dest_fullname description; do # src may be "''" for empty table cells if [[ $src == "''" ]];then unset src fi - run_podman cp $srcdir$src cpcontainer:$dest - run_podman exec cpcontainer ls $dest_fullname - run_podman exec cpcontainer cat $dest_fullname/hostfile0 - is "$output" "${randomcontent[0]}" "$description (cp -> ctr:$dest)" - run_podman exec cpcontainer cat $dest_fullname/hostfile1 - is "$output" "${randomcontent[1]}" "$description (cp -> ctr:$dest)" + run_podman cp $srcdir/$src cpcontainer:$dest + run_podman exec cpcontainer cat $dest_fullname/hostfile0 $dest_fullname/hostfile1 + is "${lines[0]}" "${randomcontent[0]}" "$description (cp -> ctr:$dest)" + is "${lines[1]}" "${randomcontent[1]}" "$description (cp -> ctr:$dest)" done < <(parse_table "$tests") - + run_podman kill cpcontainer run_podman rm -f cpcontainer + + # CREATED container + while read src dest dest_fullname description; do + # src may be "''" for empty table cells + if [[ $src == "''" ]];then + unset src + fi + run_podman create --name cpcontainer --workdir=/srv $cpimage sleep infinity + run_podman cp $srcdir/$src cpcontainer:$dest + run_podman start cpcontainer + run_podman exec cpcontainer cat $dest_fullname/hostfile0 $dest_fullname/hostfile1 + is "${lines[0]}" "${randomcontent[0]}" "$description (cp -> ctr:$dest)" + is "${lines[1]}" "${randomcontent[1]}" "$description (cp -> ctr:$dest)" + run_podman kill cpcontainer + run_podman rm -f cpcontainer + done < <(parse_table "$tests") + + run_podman rmi -f $cpimage } @test "podman cp dir from container to host" { - srcdir=$PODMAN_TMPDIR/dir-test - mkdir -p $srcdir + destdir=$PODMAN_TMPDIR/cp-test-dir-ctr-to-host + mkdir -p $destdir + # Create 2 files with random content in the container. + local -a randomcontent=( + random-0-$(random_string 10) + random-1-$(random_string 15) + ) run_podman run -d --name cpcontainer --workdir=/srv $IMAGE sleep infinity - run_podman exec cpcontainer sh -c 'mkdir /srv/subdir; echo "This first file is on the container" > /srv/subdir/containerfile1' - run_podman exec cpcontainer sh -c 'echo "This second file is on the container as well" > /srv/subdir/containerfile2' + run_podman exec cpcontainer sh -c "mkdir /srv/subdir; echo ${randomcontent[0]} > /srv/subdir/containerfile0" + run_podman exec cpcontainer sh -c "echo ${randomcontent[1]} > /srv/subdir/containerfile1" # "." and "dir/." will copy the contents, so make sure that a dir ending # with dot is treated correctly. run_podman exec cpcontainer sh -c 'mkdir /tmp/subdir.; cp /srv/subdir/* /tmp/subdir./' - run_podman cp cpcontainer:/srv $srcdir - run cat $srcdir/srv/subdir/containerfile1 - is "$output" "This first file is on the container" - run cat $srcdir/srv/subdir/containerfile2 - is "$output" "This second file is on the container as well" - rm -rf $srcdir/srv/subdir - - run_podman cp cpcontainer:/srv/. $srcdir - run ls $srcdir/subdir - run cat $srcdir/subdir/containerfile1 - is "$output" "This first file is on the container" - run cat $srcdir/subdir/containerfile2 - is "$output" "This second file is on the container as well" - rm -rf $srcdir/subdir - - run_podman cp cpcontainer:/srv/subdir/. $srcdir - run cat $srcdir/containerfile1 - is "$output" "This first file is on the container" - run cat $srcdir/containerfile2 - is "$output" "This second file is on the container as well" - rm -rf $srcdir/subdir - - run_podman cp cpcontainer:/tmp/subdir. $srcdir - run cat $srcdir/subdir./containerfile1 - is "$output" "This first file is on the container" - run cat $srcdir/subdir./containerfile2 - is "$output" "This second file is on the container as well" - rm -rf $srcdir/subdir. + # Commit the image for testing non-running containers + run_podman commit -q cpcontainer + cpimage="$output" + + # format is: <source arg to cp (appended to /srv)> | <dest> | <full dest path> | <test name> + tests=" +/srv | | /srv/subdir | copy /srv +/srv | /newdir | /newdir/subdir | copy /srv to /newdir +/srv/ | | /srv/subdir | copy /srv/ +/srv/. | | /subdir | copy /srv/. +/srv/. | /newdir | /newdir/subdir | copy /srv/. to /newdir +/srv/subdir/. | | | copy /srv/subdir/. +/tmp/subdir. | | /subdir. | copy /tmp/subdir. +" + + # RUNNING container + while read src dest dest_fullname description; do + if [[ $src == "''" ]];then + unset src + fi + if [[ $dest == "''" ]];then + unset dest + fi + if [[ $dest_fullname == "''" ]];then + unset dest_fullname + fi + run_podman cp cpcontainer:$src $destdir$dest + is "$(< $destdir$dest_fullname/containerfile0)" "${randomcontent[0]}" "$description" + is "$(< $destdir$dest_fullname/containerfile1)" "${randomcontent[1]}" "$description" + rm -rf $destdir/* + done < <(parse_table "$tests") + run_podman kill cpcontainer + run_podman rm -f cpcontainer + + # CREATED container + run_podman create --name cpcontainer --workdir=/srv $cpimage + while read src dest dest_fullname description; do + if [[ $src == "''" ]];then + unset src + fi + if [[ $dest == "''" ]];then + unset dest + fi + if [[ $dest_fullname == "''" ]];then + unset dest_fullname + fi + run_podman cp cpcontainer:$src $destdir$dest + is "$(< $destdir$dest_fullname/containerfile0)" "${randomcontent[0]}" "$description" + is "$(< $destdir$dest_fullname/containerfile1)" "${randomcontent[1]}" "$description" + rm -rf $destdir/* + done < <(parse_table "$tests") + run_podman rm -f cpcontainer + + run_podman rmi -f $cpimage +} + + +@test "podman cp symlinked directory from container" { + destdir=$PODMAN_TMPDIR/cp-weird-symlink + mkdir -p $destdir + + # Create 3 files with random content in the container. + local -a randomcontent=( + random-0-$(random_string 10) + random-1-$(random_string 15) + ) + run_podman run -d --name cpcontainer $IMAGE sleep infinity + run_podman exec cpcontainer sh -c "echo ${randomcontent[0]} > /tmp/containerfile0" + run_podman exec cpcontainer sh -c "echo ${randomcontent[1]} > /tmp/containerfile1" + run_podman exec cpcontainer sh -c "mkdir /tmp/sub && cd /tmp/sub && ln -s .. weirdlink" + + # Commit the image for testing non-running containers + run_podman commit -q cpcontainer + cpimage="$output" + + # RUNNING container + # NOTE: /dest does not exist yet but is expected to be created during copy + run_podman cp cpcontainer:/tmp/sub/weirdlink $destdir/dest + run cat $destdir/dest/containerfile0 $destdir/dest/containerfile1 + is "${lines[0]}" "${randomcontent[0]}" "eval symlink - running container" + is "${lines[1]}" "${randomcontent[1]}" "eval symlink - running container" + + run_podman kill cpcontainer + run_podman rm -f cpcontainer + run rm -rf $srcdir/dest + + # CREATED container + run_podman create --name cpcontainer $cpimage + run_podman cp cpcontainer:/tmp/sub/weirdlink $destdir/dest + run cat $destdir/dest/containerfile0 $destdir/dest/containerfile1 + is "${lines[0]}" "${randomcontent[0]}" "eval symlink - created container" + is "${lines[1]}" "${randomcontent[1]}" "eval symlink - created container" run_podman rm -f cpcontainer } @@ -228,9 +396,7 @@ load helpers run_podman create --name cpcontainer -v $volume1:/tmp/volume -v $volume2:/tmp/volume/sub-volume $IMAGE run_podman cp $srcdir/hostfile cpcontainer:/tmp/volume/sub-volume - - run cat $volume2_mount/hostfile - is "$output" "This file should be in volume2" + is "$(< $volume2_mount/hostfile)" "This file should be in volume2" # Volume 1 must be empty. run ls $volume1_mount @@ -254,9 +420,7 @@ load helpers run_podman create --name cpcontainer -v $volume:/tmp/volume -v $mountdir:/tmp/volume/mount $IMAGE run_podman cp $srcdir/hostfile cpcontainer:/tmp/volume/mount - - run cat $mountdir/hostfile - is "$output" "This file should be in the mount" + is "$(< $mountdir/hostfile)" "This file should be in the mount" run_podman rm -f cpcontainer run_podman volume rm $volume @@ -284,7 +448,7 @@ load helpers # cp no longer supports wildcarding run_podman 125 cp 'cpcontainer:/tmp/*' $dstdir - run_podman rm cpcontainer + run_podman rm -f cpcontainer } @@ -308,7 +472,7 @@ load helpers # make sure there are no files in dstdir is "$(/bin/ls -1 $dstdir)" "" "incorrectly copied symlink from host" - run_podman rm cpcontainer + run_podman rm -f cpcontainer } @@ -332,7 +496,7 @@ load helpers # make sure there are no files in dstdir is "$(/bin/ls -1 $dstdir)" "" "incorrectly copied symlink from host" - run_podman rm cpcontainer + run_podman rm -f cpcontainer } @@ -352,7 +516,7 @@ load helpers # dstdir must be empty is "$(/bin/ls -1 $dstdir)" "" "incorrectly copied symlink from host" - run_podman rm cpcontainer + run_podman rm -f cpcontainer } @@ -409,6 +573,7 @@ load helpers run_podman exec cpcontainer cat /tmp/d3/x is "$output" "$rand_content3" "cp creates file named x" + run_podman kill cpcontainer run_podman rm -f cpcontainer } @@ -446,6 +611,7 @@ load helpers run_podman exec cpcontainer cat $graphroot/$rand_filename is "$output" "$rand_content" "Contents of file copied into container" + run_podman kill cpcontainer run_podman rm -f cpcontainer } @@ -494,6 +660,7 @@ load helpers run_podman 125 cp - cpcontainer:/tmp/IdoNotExist < $tar_file is "$output" 'Error: destination must be a directory when copying from stdin' + run_podman kill cpcontainer run_podman rm -f cpcontainer } @@ -527,8 +694,7 @@ load helpers fi tar xvf $srcdir/stdout.tar -C $srcdir - run cat $srcdir/file.txt - is "$output" "$rand_content" + is "$(< $srcdir/file.txt)" "$rand_content" run 1 ls $srcdir/empty.txt rm -f $srcdir/* @@ -539,11 +705,10 @@ load helpers fi tar xvf $srcdir/stdout.tar -C $srcdir - run cat $srcdir/tmp/file.txt - is "$output" "$rand_content" - run cat $srcdir/tmp/empty.txt - is "$output" "" + is "$(< $srcdir/tmp/file.txt)" "$rand_content" + is "$(< $srcdir/tmp/empty.txt)" "" + run_podman kill cpcontainer run_podman rm -f cpcontainer } diff --git a/test/system/070-build.bats b/test/system/070-build.bats index 1e7d366a1..d413b0c10 100644 --- a/test/system/070-build.bats +++ b/test/system/070-build.bats @@ -168,6 +168,9 @@ EOF CAT_SECRET="cat /run/secrets/$secret_filename" fi + # For --dns-search: a domain that is unlikely to exist + local nosuchdomain=nx$(random_string 10).net + # Command to run on container startup with no args cat >$tmpdir/mycmd <<EOF #!/bin/sh @@ -188,11 +191,17 @@ EOF https_proxy=https-proxy-in-env-file EOF + # Build args: one explicit (foo=bar), one implicit (foo) + local arg_implicit_value=implicit_$(random_string 15) + local arg_explicit_value=explicit_$(random_string 15) + # NOTE: it's important to not create the workdir. # Podman will make sure to create a missing workdir # if needed. See #9040. cat >$tmpdir/Containerfile <<EOF FROM $IMAGE +ARG arg_explicit +ARG arg_implicit LABEL $label_name=$label_value WORKDIR $workdir @@ -217,18 +226,47 @@ RUN chown 2:3 /bin/mydefaultcmd RUN $CAT_SECRET +RUN echo explicit-build-arg=\$arg_explicit +RUN echo implicit-build-arg=\$arg_implicit + CMD ["/bin/mydefaultcmd","$s_echo"] +RUN cat /etc/resolv.conf EOF + # The goal is to test that a missing value will be inherited from + # environment - but that can't work with remote, so for simplicity + # just make it explicit in that case too. + local build_arg_implicit="--build-arg arg_implicit" + if is_remote; then + build_arg_implicit+="=$arg_implicit_value" + fi + # cd to the dir, so we test relative paths (important for podman-remote) cd $PODMAN_TMPDIR + export arg_explicit="THIS SHOULD BE OVERRIDDEN BY COMMAND LINE!" + export arg_implicit=${arg_implicit_value} run_podman ${MOUNTS_CONF} build \ + --build-arg arg_explicit=${arg_explicit_value} \ + $build_arg_implicit \ + --dns-search $nosuchdomain \ -t build_test -f build-test/Containerfile build-test local iid="${lines[-1]}" + if [[ $output =~ missing.*build.argument ]]; then + die "podman did not see the given --build-arg(s)" + fi + # Make sure 'podman build' had the secret mounted is "$output" ".*$secret_contents.*" "podman build has /run/secrets mounted" + # --build-arg should be set, both via 'foo=bar' and via just 'foo' ($foo) + is "$output" ".*explicit-build-arg=${arg_explicit_value}" \ + "--build-arg arg_explicit=explicit-value works" + is "$output" ".*implicit-build-arg=${arg_implicit_value}" \ + "--build-arg arg_implicit works (inheriting from environment)" + is "$output" ".*search $nosuchdomain" \ + "--dns-search added to /etc/resolv.conf" + if is_remote; then ENVHOST="" else @@ -362,6 +400,82 @@ Labels.$label_name | $label_value run_podman rmi -f build_test } +@test "podman build - COPY with ignore" { + local tmpdir=$PODMAN_TMPDIR/build-test-$(random_string 10) + mkdir -p $tmpdir/subdir + + # Create a bunch of files. Declare this as an array to avoid duplication + # because we iterate over that list below, checking for each file. + # A leading "-" indicates that the file SHOULD NOT exist in the built image + local -a files=( + -test1 -test1.txt + test2 test2.txt + subdir/sub1 subdir/sub1.txt + -subdir/sub2 -subdir/sub2.txt + this-file-does-not-match-anything-in-ignore-file + comment + ) + for f in ${files[@]}; do + # The magic '##-' strips off the '-' prefix + echo "$f" > $tmpdir/${f##-} + done + + # Directory that doesn't exist in the image; COPY should create it + local newdir=/newdir-$(random_string 12) + cat >$tmpdir/Containerfile <<EOF +FROM $IMAGE +COPY ./ $newdir/ +EOF + + # Run twice: first with a custom --ignorefile, then with a default one. + # This ordering is deliberate: if we were to run with .dockerignore + # first, and forget to rm it, and then run with --ignorefile, _and_ + # there was a bug in podman where --ignorefile was a NOP (eg #9570), + # the test might pass because of the existence of .dockerfile. + for ignorefile in ignoreme-$(random_string 5) .dockerignore; do + # Patterns to ignore. Mostly copied from buildah/tests/bud/dockerignore + cat >$tmpdir/$ignorefile <<EOF +# comment +test* +!test2* +subdir +!*/sub1* +EOF + + # Build an image. For .dockerignore + local -a ignoreflag + unset ignoreflag + if [[ $ignorefile != ".dockerignore" ]]; then + ignoreflag="--ignorefile $tmpdir/$ignorefile" + fi + run_podman build -t build_test ${ignoreflag} $tmpdir + + # Delete the ignore file! Otherwise, in the next iteration of the loop, + # we could end up with an existing .dockerignore that invisibly + # takes precedence over --ignorefile + rm -f $tmpdir/$ignorefile + + # It would be much more readable, and probably safer, to iterate + # over each file, running 'podman run ... ls -l $f'. But each podman run + # takes a second or so, and we are mindful of each second. + run_podman run --rm build_test find $newdir -type f + for f in ${files[@]}; do + if [[ $f =~ ^- ]]; then + f=${f##-} + if [[ $output =~ $f ]]; then + die "File '$f' found in image; it should have been ignored via $ignorefile" + fi + else + is "$output" ".*$newdir/$f" \ + "File '$f' should exist in container (no match in $ignorefile)" + fi + done + + # Clean up + run_podman rmi -f build_test + done +} + @test "podman build - stdin test" { # Random workdir, and random string to verify build output workdir=/$(random_string 10) diff --git a/test/system/120-load.bats b/test/system/120-load.bats index 902cd9f5e..936449bdb 100644 --- a/test/system/120-load.bats +++ b/test/system/120-load.bats @@ -26,6 +26,13 @@ verify_iid_and_name() { is "$new_img_name" "$1" "Name & tag of restored image" } +@test "podman load invalid file" { + # Regression test for #9672 to make sure invalid input yields errors. + invalid=$PODMAN_TMPDIR/invalid + echo "I am an invalid file and should cause a podman-load error" > $invalid + run_podman 125 load -i $invalid +} + @test "podman save to pipe and load" { # Generate a random name and tag (must be lower-case) local random_name=x0$(random_string 12 | tr A-Z a-z) diff --git a/test/system/410-selinux.bats b/test/system/410-selinux.bats index 7482d3e55..49743ff33 100644 --- a/test/system/410-selinux.bats +++ b/test/system/410-selinux.bats @@ -39,17 +39,17 @@ function check_label() { } @test "podman selinux: container with label=disable" { - skip_if_rootless - check_label "--security-opt label=disable" "spc_t" } @test "podman selinux: privileged container" { - skip_if_rootless - check_label "--privileged --userns=host" "spc_t" } +@test "podman selinux: init container" { + check_label "--systemd=always" "container_init_t" +} + @test "podman selinux: pid=host" { # FIXME FIXME FIXME: Remove these lines once all VMs have >= 2.146.0 # (this is ugly, but better than an unconditional skip) @@ -74,6 +74,19 @@ function check_label() { check_label "--security-opt label=level:s0:c1,c2" "container_t" "s0:c1,c2" } +@test "podman selinux: inspect kvm labels" { + skip_if_no_selinux + skip_if_remote "runtime flag is not passed over remote" + + tmpdir=$PODMAN_TMPDIR/kata-test + mkdir -p $tmpdir + KATA=${tmpdir}/kata-runtime + ln -s /bin/true ${KATA} + run_podman create --runtime=${KATA} --name myc $IMAGE + run_podman inspect --format='{{ .ProcessLabel }}' myc + is "$output" ".*container_kvm_t" +} + # pr #6752 @test "podman selinux: inspect multiple labels" { skip_if_no_selinux |