diff options
Diffstat (limited to 'test')
20 files changed, 450 insertions, 196 deletions
diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go index 2fad38a36..ed7876d8a 100644 --- a/test/e2e/inspect_test.go +++ b/test/e2e/inspect_test.go @@ -7,6 +7,7 @@ import ( . "github.com/containers/libpod/test/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/opencontainers/selinux/go-selinux" ) var _ = Describe("Podman inspect", func() { @@ -263,4 +264,29 @@ var _ = Describe("Podman inspect", func() { Expect(len(baseJSON)).To(Equal(1)) Expect(baseJSON[0].Name).To(Equal(ctrName)) }) + + It("podman inspect - HostConfig.SecurityOpt ", func() { + if !selinux.GetEnabled() { + Skip("SELinux not enabled") + } + + ctrName := "hugo" + create := podmanTest.PodmanNoCache([]string{ + "create", "--name", ctrName, + "--security-opt", "seccomp=unconfined", + "--security-opt", "label=type:spc_t", + "--security-opt", "label=level:s0", + ALPINE, "sh"}) + + create.WaitWithDefaultTimeout() + Expect(create.ExitCode()).To(Equal(0)) + + baseInspect := podmanTest.Podman([]string{"inspect", ctrName}) + baseInspect.WaitWithDefaultTimeout() + Expect(baseInspect.ExitCode()).To(Equal(0)) + baseJSON := baseInspect.InspectContainerToJSON() + Expect(len(baseJSON)).To(Equal(1)) + Expect(baseJSON[0].HostConfig.SecurityOpt).To(Equal([]string{"label=type:spc_t,label=level:s0", "seccomp=unconfined"})) + }) + }) diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go index 0dc8e01af..cfc0a415e 100644 --- a/test/e2e/ps_test.go +++ b/test/e2e/ps_test.go @@ -449,4 +449,21 @@ var _ = Describe("Podman ps", func() { Expect(len(output)).To(Equal(1)) Expect(output[0]).To(Equal(ctrName)) }) + + It("podman ps test with port shared with pod", func() { + podName := "testPod" + pod := podmanTest.Podman([]string{"pod", "create", "-p", "8080:80", "--name", podName}) + pod.WaitWithDefaultTimeout() + Expect(pod.ExitCode()).To(Equal(0)) + + ctrName := "testCtr" + session := podmanTest.Podman([]string{"run", "--name", ctrName, "-dt", "--pod", podName, ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + ps := podmanTest.Podman([]string{"ps", "--filter", fmt.Sprintf("name=%s", ctrName), "--format", "{{.Ports}}"}) + ps.WaitWithDefaultTimeout() + Expect(ps.ExitCode()).To(Equal(0)) + Expect(ps.OutputToString()).To(ContainSubstring("0.0.0.0:8080->80/tcp")) + }) }) diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index afba12ccd..cdfbd5530 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -184,6 +184,30 @@ var _ = Describe("Podman run networking", func() { Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal("")) }) + It("podman run -p 127.0.0.1::8080/udp", func() { + name := "testctr" + session := podmanTest.Podman([]string{"create", "-t", "-p", "127.0.0.1::8080/udp", "--name", name, ALPINE, "/bin/sh"}) + session.WaitWithDefaultTimeout() + inspectOut := podmanTest.InspectContainer(name) + Expect(len(inspectOut)).To(Equal(1)) + Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) + Expect(len(inspectOut[0].NetworkSettings.Ports["8080/udp"])).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports["8080/udp"][0].HostPort).To(Not(Equal("8080"))) + Expect(inspectOut[0].NetworkSettings.Ports["8080/udp"][0].HostIP).To(Equal("127.0.0.1")) + }) + + It("podman run -p :8080", func() { + name := "testctr" + session := podmanTest.Podman([]string{"create", "-t", "-p", ":8080", "--name", name, ALPINE, "/bin/sh"}) + session.WaitWithDefaultTimeout() + inspectOut := podmanTest.InspectContainer(name) + Expect(len(inspectOut)).To(Equal(1)) + Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1)) + Expect(len(inspectOut[0].NetworkSettings.Ports["8080/tcp"])).To(Equal(1)) + Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostPort).To(Not(Equal("8080"))) + Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostIP).To(Equal("")) + }) + It("podman run network expose host port 80 to container port 8000", func() { SkipIfRootless() session := podmanTest.Podman([]string{"run", "-dt", "-p", "80:8000", ALPINE, "/bin/sh"}) diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go index 7664e64bb..d2d75af9e 100644 --- a/test/e2e/volume_ls_test.go +++ b/test/e2e/volume_ls_test.go @@ -1,6 +1,7 @@ package integration import ( + "fmt" "os" . "github.com/containers/libpod/test/utils" @@ -82,4 +83,30 @@ var _ = Describe("Podman volume ls", func() { Expect(len(session.OutputToStringArray())).To(Equal(2)) Expect(session.OutputToStringArray()[1]).To(ContainSubstring(volName)) }) + + It("podman volume ls with --filter dangling", func() { + volName1 := "volume1" + session := podmanTest.Podman([]string{"volume", "create", volName1}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + volName2 := "volume2" + session2 := podmanTest.Podman([]string{"volume", "create", volName2}) + session2.WaitWithDefaultTimeout() + Expect(session2.ExitCode()).To(Equal(0)) + + ctr := podmanTest.Podman([]string{"create", "-v", fmt.Sprintf("%s:/test", volName2), ALPINE, "sh"}) + ctr.WaitWithDefaultTimeout() + Expect(ctr.ExitCode()).To(Equal(0)) + + lsNoDangling := podmanTest.Podman([]string{"volume", "ls", "--filter", "dangling=false", "--quiet"}) + lsNoDangling.WaitWithDefaultTimeout() + Expect(lsNoDangling.ExitCode()).To(Equal(0)) + Expect(lsNoDangling.OutputToString()).To(ContainSubstring(volName2)) + + lsDangling := podmanTest.Podman([]string{"volume", "ls", "--filter", "dangling=true", "--quiet"}) + lsDangling.WaitWithDefaultTimeout() + Expect(lsDangling.ExitCode()).To(Equal(0)) + Expect(lsDangling.OutputToString()).To(ContainSubstring(volName1)) + }) }) diff --git a/test/python/dockerpy/README.md b/test/python/dockerpy/README.md new file mode 100644 index 000000000..22908afc6 --- /dev/null +++ b/test/python/dockerpy/README.md @@ -0,0 +1,40 @@ +# Dockerpy regression test + +Python test suite to validate Podman endpoints using dockerpy library + +## Running Tests + +To run the tests locally in your sandbox (Fedora 32): + +```shell script +# dnf install python3-docker +``` + +### Run the entire test suite + +```shell +# cd test/python/dockerpy +# PYTHONPATH=/usr/bin/python python -m unittest discover . +``` + +Passing the -v option to your test script will instruct unittest.main() to enable a higher level of verbosity, and produce detailed output: + +```shell +# cd test/python/dockerpy +# PYTHONPATH=/usr/bin/python python -m unittest -v discover . +``` + +### Run a specific test class + +```shell +# cd test/python/dockerpy +# PYTHONPATH=/usr/bin/python python -m unittest -v tests.test_images +``` + +### Run a specific test within the test class + +```shell +# cd test/python/dockerpy +# PYTHONPATH=/usr/bin/python python -m unittest tests.test_images.TestImages.test_import_image + +``` diff --git a/test/test_dockerpy/__init__.py b/test/python/dockerpy/__init__.py index e69de29bb..e69de29bb 100644 --- a/test/test_dockerpy/__init__.py +++ b/test/python/dockerpy/__init__.py diff --git a/test/python/dockerpy/tests/__init__.py b/test/python/dockerpy/tests/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/test/python/dockerpy/tests/__init__.py diff --git a/test/python/dockerpy/tests/common.py b/test/python/dockerpy/tests/common.py new file mode 100644 index 000000000..f83f4076f --- /dev/null +++ b/test/python/dockerpy/tests/common.py @@ -0,0 +1,105 @@ +import os +import pathlib +import subprocess +import sys +import time + +from docker import APIClient + +from . import constant + +alpineDict = { + "name": "docker.io/library/alpine:latest", + "shortName": "alpine", + "tarballName": "alpine.tar" +} + + +def get_client(): + client = APIClient(base_url="http://localhost:8080", timeout=15) + return client + + +client = get_client() + + +def podman(): + binary = os.getenv("PODMAN_BINARY") + if binary is None: + binary = "../../../bin/podman" + return binary + + +def restore_image_from_cache(TestClass): + alpineImage = os.path.join(constant.ImageCacheDir, + alpineDict["tarballName"]) + if not os.path.exists(alpineImage): + os.makedirs(constant.ImageCacheDir, exist_ok=True) + client.pull(constant.ALPINE) + image = client.get_image(constant.ALPINE) + tarball = open(alpineImage, mode="wb") + for frame in image: + tarball.write(frame) + tarball.close() + else: + subprocess.run( + [podman(), "load", "-i", alpineImage], + shell=False, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + check=True, + ) + + +def flush_image_cache(TestCase): + for f in pathlib.Path(constant.ImageCacheDir).glob("*"): + f.unlink(f) + + +def run_top_container(): + c = client.create_container(image=constant.ALPINE, + command='/bin/sleep 5', + name=constant.TOP) + client.start(container=c.get("Id")) + return c.get("Id") + + +def enable_sock(TestClass): + TestClass.podman = subprocess.Popen( + [ + podman(), "system", "service", "tcp:localhost:8080", + "--log-level=debug", "--time=0" + ], + shell=False, + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + time.sleep(2) + + +def terminate_connection(TestClass): + TestClass.podman.terminate() + stdout, stderr = TestClass.podman.communicate(timeout=0.5) + if stdout: + print("\nService Stdout:\n" + stdout.decode('utf-8')) + if stderr: + print("\nService Stderr:\n" + stderr.decode('utf-8')) + + if TestClass.podman.returncode > 0: + sys.stderr.write("podman exited with error code {}\n".format( + TestClass.podman.returncode)) + sys.exit(2) + + +def remove_all_containers(): + containers = client.containers(quiet=True) + for c in containers: + client.remove_container(container=c.get("Id"), force=True) + + +def remove_all_images(): + allImages = client.images() + for image in allImages: + client.remove_image(image, force=True) diff --git a/test/python/dockerpy/tests/constant.py b/test/python/dockerpy/tests/constant.py new file mode 100644 index 000000000..b44442d02 --- /dev/null +++ b/test/python/dockerpy/tests/constant.py @@ -0,0 +1,13 @@ +BB = "docker.io/library/busybox:latest" +NGINX = "docker.io/library/nginx:latest" +ALPINE = "docker.io/library/alpine:latest" +ALPINE_SHORTNAME = "alpine" +ALPINELISTTAG = "docker.io/library/alpine:3.10.2" +ALPINELISTDIGEST = "docker.io/library/alpine@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb" +ALPINEAMD64DIGEST = "docker.io/library/alpine@sha256:acd3ca9941a85e8ed16515bfc5328e4e2f8c128caa72959a58a127b7801ee01f" +ALPINEAMD64ID = "961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4" +ALPINEARM64DIGEST = "docker.io/library/alpine@sha256:db7f3dcef3d586f7dd123f107c93d7911515a5991c4b9e51fa2a43e46335a43e" +ALPINEARM64ID = "915beeae46751fc564998c79e73a1026542e945ca4f73dc841d09ccc6c2c0672" +infra = "k8s.gcr.io/pause:3.2" +TOP = "top" +ImageCacheDir = "/tmp/podman/imagecachedir" diff --git a/test/test_dockerpy/test_containers.py b/test/python/dockerpy/tests/test_containers.py index 34fe82c18..6b89688d4 100644 --- a/test/test_dockerpy/test_containers.py +++ b/test/python/dockerpy/tests/test_containers.py @@ -1,18 +1,15 @@ - -import unittest -import docker -import requests import os -from docker import Client -from . import constant -from . import common import time +import unittest + +import requests + +from . import common, constant client = common.get_client() -class TestContainers(unittest.TestCase): - podman = None +class TestContainers(unittest.TestCase): topContainerId = "" def setUp(self): @@ -33,6 +30,7 @@ class TestContainers(unittest.TestCase): @classmethod def tearDownClass(cls): common.terminate_connection(cls) + common.flush_image_cache(cls) return super().tearDownClass() def test_inspect_container(self): @@ -42,16 +40,15 @@ class TestContainers(unittest.TestCase): self.assertEqual(error.exception.response.status_code, 404) # Inspect valid container by name container = client.inspect_container(constant.TOP) - self.assertIn(TestContainers.topContainerId , container["Id"]) + self.assertIn(TestContainers.topContainerId, container["Id"]) # Inspect valid container by Id container = client.inspect_container(TestContainers.topContainerId) - self.assertIn(constant.TOP , container["Name"]) + self.assertIn(constant.TOP, container["Name"]) def test_create_container(self): # Run a container with detach mode container = client.create_container(image="alpine", detach=True) - self.assertEqual(len(container),2) - + self.assertEqual(len(container), 2) def test_start_container(self): # Start bogus container @@ -65,9 +62,9 @@ class TestContainers(unittest.TestCase): # self.assertEqual(error.exception.response.status_code, 304) # Create a new container and validate the count - client.create_container(image=constant.ALPINE,name="container2") - containers = client.containers(quiet=True,all=True) - self.assertEqual(len(containers),2) + client.create_container(image=constant.ALPINE, name="container2") + containers = client.containers(quiet=True, all=True) + self.assertEqual(len(containers), 2) def test_stop_container(self): # Stop bogus container @@ -82,7 +79,10 @@ class TestContainers(unittest.TestCase): # Stop a running container and validate the state client.stop(TestContainers.topContainerId) container = client.inspect_container(constant.TOP) - self.assertIn(container["State"]["Status"],"stopped exited",) + self.assertIn( + container["State"]["Status"], + "stopped exited", + ) def test_restart_container(self): # Restart bogus container @@ -109,12 +109,12 @@ class TestContainers(unittest.TestCase): # Remove container by ID with force client.remove_container(TestContainers.topContainerId, force=True) containers = client.containers() - self.assertEqual(len(containers),0) + self.assertEqual(len(containers), 0) def test_remove_container_without_force(self): # Validate current container count containers = client.containers() - self.assertTrue(len(containers),1) + self.assertTrue(len(containers), 1) # Remove running container should throw error with self.assertRaises(requests.HTTPError) as error: @@ -125,7 +125,7 @@ class TestContainers(unittest.TestCase): client.stop(TestContainers.topContainerId) client.remove_container(TestContainers.topContainerId) containers = client.containers() - self.assertEqual(len(containers),0) + self.assertEqual(len(containers), 0) def test_pause_container(self): # Pause bogus container @@ -151,7 +151,6 @@ class TestContainers(unittest.TestCase): client.pause(TestContainers.topContainerId) self.assertEqual(error.exception.response.status_code, 500) - def test_unpause_container(self): # Unpause bogus container with self.assertRaises(requests.HTTPError) as error: @@ -173,7 +172,7 @@ class TestContainers(unittest.TestCase): # Add container and validate the count client.create_container(image="alpine", detach=True) containers = client.containers(all=True) - self.assertEqual(len(containers),2) + self.assertEqual(len(containers), 2) # Not working for now......checking # # List container with filter by id diff --git a/test/test_dockerpy/test_images.py b/test/python/dockerpy/tests/test_images.py index c88353b79..5eae61c2f 100644 --- a/test/test_dockerpy/test_images.py +++ b/test/python/dockerpy/tests/test_images.py @@ -1,17 +1,18 @@ - +import os +import stat import unittest +from os import remove +from stat import ST_SIZE + import docker import requests -import os -from docker import Client -from . import constant -from . import common + +from . import common, constant client = common.get_client() -class TestImages(unittest.TestCase): - podman = None +class TestImages(unittest.TestCase): def setUp(self): super().setUp() common.restore_image_from_cache(self) @@ -25,13 +26,12 @@ class TestImages(unittest.TestCase): super().setUpClass() common.enable_sock(cls) - @classmethod def tearDownClass(cls): common.terminate_connection(cls) + common.flush_image_cache(cls) return super().tearDownClass() - # Inspect Image def test_inspect_image(self): @@ -43,46 +43,46 @@ class TestImages(unittest.TestCase): # Tag Image - # Validates if invalid image name is given a bad response is encountered. +# Validates if invalid image name is given a bad response is encountered. + def test_tag_invalid_image(self): with self.assertRaises(requests.HTTPError): - client.tag("dummy","demo") - - + client.tag("dummy", "demo") # Validates if the image is tagged successfully. def test_tag_valid_image(self): - client.tag(constant.ALPINE,"demo",constant.ALPINE_SHORTNAME) + client.tag(constant.ALPINE, "demo", constant.ALPINE_SHORTNAME) alpine_image = client.inspect_image(constant.ALPINE) for x in alpine_image["RepoTags"]: - if("demo:alpine" in x): + if ("demo:alpine" in x): self.assertTrue self.assertFalse # Validates if name updates when the image is retagged. @unittest.skip("dosent work now") def test_retag_valid_image(self): - client.tag(constant.ALPINE_SHORTNAME, "demo","rename") + client.tag(constant.ALPINE_SHORTNAME, "demo", "rename") alpine_image = client.inspect_image(constant.ALPINE) self.assertNotIn("demo:test", alpine_image["RepoTags"]) # List Image - # List All Images +# List All Images + def test_list_images(self): allImages = client.images() self.assertEqual(len(allImages), 1) # Add more images client.pull(constant.BB) allImages = client.images() - self.assertEqual(len(allImages) , 2) - + self.assertEqual(len(allImages), 2) - # List images with filter - filters = {'reference':'alpine'} - allImages = client.images(filters = filters) - self.assertEqual(len(allImages) , 1) + # List images with filter + filters = {'reference': 'alpine'} + allImages = client.images(filters=filters) + self.assertEqual(len(allImages), 1) # Search Image + def test_search_image(self): response = client.search("alpine") for i in response: @@ -94,22 +94,25 @@ class TestImages(unittest.TestCase): # Image Exist (No docker-py support yet) # Remove Image + def test_remove_image(self): # Check for error with wrong image name with self.assertRaises(requests.HTTPError): client.remove_image("dummy") allImages = client.images() - self.assertEqual(len(allImages) , 1) + self.assertEqual(len(allImages), 1) alpine_image = client.inspect_image(constant.ALPINE) client.remove_image(alpine_image) allImages = client.images() - self.assertEqual(len(allImages) , 0) + self.assertEqual(len(allImages), 0) # Image History + def test_image_history(self): # Check for error with wrong image name with self.assertRaises(requests.HTTPError): - client.remove_image("dummy") + client.history("dummy") + imageHistory = client.history(constant.ALPINE) alpine_image = client.inspect_image(constant.ALPINE) for h in imageHistory: @@ -119,28 +122,37 @@ class TestImages(unittest.TestCase): # Prune Image (No docker-py support yet) + def test_get_image_dummy(self): + # FIXME: seems to be an error in the library + self.skipTest("Documentation and library do not match") + # Check for error with wrong image name + with self.assertRaises(docker.errors.ImageNotFound): + client.get_image("dummy") + # Export Image def test_export_image(self): client.pull(constant.BB) - file = os.path.join(constant.ImageCacheDir , "busybox.tar") if not os.path.exists(constant.ImageCacheDir): os.makedirs(constant.ImageCacheDir) - # Check for error with wrong image name - with self.assertRaises(requests.HTTPError): - client.get_image("dummy") - response = client.get_image(constant.BB) - image_tar = open(file,mode="wb") - image_tar.write(response.data) - image_tar.close() - os.stat(file) + + image = client.get_image(constant.BB) + + file = os.path.join(constant.ImageCacheDir, "busybox.tar") + tarball = open(file, mode="wb") + for frame in image: + tarball.write(frame) + tarball.close() + sz = os.path.getsize(file) + self.assertGreater(sz, 0) + # Import|Load Image def test_import_image(self): allImages = client.images() self.assertEqual(len(allImages), 1) - file = os.path.join(constant.ImageCacheDir , "busybox.tar") + file = os.path.join(constant.ImageCacheDir, "alpine.tar") client.import_image_from_file(filename=file) allImages = client.images() self.assertEqual(len(allImages), 2) diff --git a/test/test_dockerpy/test_info_version.py b/test/python/dockerpy/tests/test_info_version.py index be1a2aab9..e3ee18ec7 100644 --- a/test/test_dockerpy/test_info_version.py +++ b/test/python/dockerpy/tests/test_info_version.py @@ -1,11 +1,10 @@ import unittest -import docker -from docker import Client -from . import constant -from . import common + +from . import common, constant client = common.get_client() + class TestInfo_Version(unittest.TestCase): podman = None @@ -31,16 +30,15 @@ class TestInfo_Version(unittest.TestCase): common.terminate_connection(cls) return super().tearDownClass() - def test_Info(self): self.assertIsNotNone(client.info()) def test_info_container_details(self): info = client.info() - self.assertEqual(info["Containers"],1) + self.assertEqual(info["Containers"], 1) client.create_container(image=constant.ALPINE) info = client.info() - self.assertEqual(info["Containers"],2) + self.assertEqual(info["Containers"], 2) def test_version(self): self.assertIsNotNone(client.version()) diff --git a/test/system/015-help.bats b/test/system/015-help.bats index 14af8e1a4..3d05b44fe 100644 --- a/test/system/015-help.bats +++ b/test/system/015-help.bats @@ -34,13 +34,16 @@ function check_help() { dprint "$command_string --help" run_podman "$@" $cmd --help + local full_help="$output" # The line immediately after 'Usage:' gives us a 1-line synopsis - usage=$(echo "$output" | grep -A1 '^Usage:' | tail -1) + usage=$(echo "$full_help" | grep -A1 '^Usage:' | tail -1) [ -n "$usage" ] || die "podman $cmd: no Usage message found" # e.g. 'podman ps' should not show 'podman container ps' in usage - is "$usage" " $command_string .*" "Usage string matches command" + # Trailing space in usage handles 'podman system renumber' which + # has no ' [flags]' + is "$usage " " $command_string .*" "Usage string matches command" # If usage ends in '[command]', recurse into subcommands if expr "$usage" : '.*\[command\]$' >/dev/null; then @@ -59,6 +62,17 @@ function check_help() { die "'flags' must precede arguments in usage: $usage" fi + # Cross-check: if usage includes '[flags]', there must be a + # longer 'Flags:' section in the full --help output; vice-versa, + # if 'Flags:' is in full output, usage line must have '[flags]'. + if expr "$usage" : '.*\[flag' >/dev/null; then + if ! expr "$full_help" : ".*Flags:" >/dev/null; then + die "$command_string: Usage includes '[flags]' but has no 'Flags:' subsection" + fi + elif expr "$full_help" : ".*Flags:" >/dev/null; then + die "$command_string: --help has 'Flags:' section but no '[flags]' in synopsis" + fi + # If usage lists no arguments (strings in ALL CAPS), confirm # by running with 'invalid-arg' and expecting failure. if ! expr "$usage" : '.*[A-Z]' >/dev/null; then diff --git a/test/system/030-run.bats b/test/system/030-run.bats index eeecea2e5..bc6347012 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -201,4 +201,45 @@ echo $rand | 0 | $rand "podman will not overwrite existing cidfile" } +@test "podman run docker-archive" { + # Create an image that, when run, outputs a random magic string + expect=$(random_string 20) + run_podman run --name myc --entrypoint="[\"/bin/echo\",\"$expect\"]" $IMAGE + is "$output" "$expect" "podman run --entrypoint echo-randomstring" + + # Save it as a tar archive + run_podman commit myc myi + archive=$PODMAN_TMPDIR/archive.tar + run_podman save myi -o $archive + is "$output" "" "podman save" + + # Clean up image and container from container storage... + run_podman rmi myi + run_podman rm myc + + # ... then confirm we can run from archive. This re-imports the image + # and runs it, producing our random string as the last line. + run_podman run docker-archive:$archive + is "${lines[0]}" "Getting image source signatures" "podman run docker-archive, first line of output" + is "$output" ".*Copying blob" "podman run docker-archive" + is "$output" ".*Copying config" "podman run docker-archive" + is "$output" ".*Writing manifest" "podman run docker-archive" + is "${lines[-1]}" "$expect" "podman run docker-archive: expected random string output" + + # Clean up container as well as re-imported image + run_podman rm -a + run_podman rmi myi + + # Repeat the above, with podman-create and podman-start. + run_podman create docker-archive:$archive + cid=${lines[-1]} + + run_podman start --attach $cid + is "$output" "$expect" "'podman run' of 'podman-create docker-archive'" + + # Clean up. + run_podman rm $cid + run_podman rmi myi +} + # vim: filetype=sh diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index 9a6b39057..0e9d9132e 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -150,6 +150,18 @@ function random_ip() { pod_id_file=${PODMAN_TMPDIR}/pod-id-file + # Randomly-assigned ports in the 5xxx and 6xxx range + for port_in in $(shuf -i 5000-5999);do + if ! { exec 3<> /dev/tcp/127.0.0.1/$port_in; } &>/dev/null; then + break + fi + done + for port_out in $(shuf -i 6000-6999);do + if ! { exec 3<> /dev/tcp/127.0.0.1/$port_out; } &>/dev/null; then + break + fi + done + # Create a pod with all the desired options # FIXME: --ip=$ip fails: # Error adding network: failed to allocate all requested IPs @@ -161,6 +173,7 @@ function random_ip() { --dns "$dns_server" \ --dns-search "$dns_search" \ --dns-opt "$dns_opt" \ + --publish "$port_out:$port_in" \ --label "${labelname}=${labelvalue}" pod_id="$output" @@ -199,6 +212,34 @@ function random_ip() { run_podman pod ps --no-trunc --filter "label=${labelname}=${labelvalue}" --format '{{.ID}}' is "$output" "$pod_id" "pod ps --filter label=..." + # Test local port forwarding, as well as 'ps' output showing ports + # Run 'nc' in a container, waiting for input on the published port. + c_name=$(random_string 15) + run_podman run -d --pod mypod --name $c_name $IMAGE nc -l -p $port_in + cid="$output" + + # Try running another container also listening on the same port. + run_podman 1 run --pod mypod --name dsfsdfsdf $IMAGE nc -l -p $port_in + is "$output" "nc: bind: Address in use" \ + "two containers cannot bind to same port" + + # While the container is still running, run 'podman ps' (no --format) + # and confirm that the output includes the published port + run_podman ps --filter id=$cid + is "${lines[1]}" "${cid:0:12} $IMAGE nc -l -p $port_in .* 0.0.0.0:$port_out->$port_in/tcp $c_name" \ + "output of 'podman ps'" + + # send a random string to the container. This will cause the container + # to output the string to its logs, then exit. + teststring=$(random_string 30) + echo "$teststring" | nc 127.0.0.1 $port_out + + # Confirm that the container log output is the string we sent it. + run_podman logs $cid + is "$output" "$teststring" "test string received on container" + + # Clean up + run_podman rm $cid run_podman pod rm -f mypod } diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats index 4bee13414..b7035cdda 100644 --- a/test/system/250-systemd.bats +++ b/test/system/250-systemd.bats @@ -41,7 +41,7 @@ function teardown() { fi cname=$(random_string) - run_podman create --name $cname --detach $IMAGE top + run_podman create --name $cname --label "io.containers.autoupdate=image" --detach $IMAGE top run_podman generate systemd --new $cname echo "$output" > "$UNIT_FILE" @@ -64,6 +64,12 @@ function teardown() { run_podman logs $cname is "$output" ".*Load average:.*" "running container 'top'-like output" + # Exercise `podman auto-update`. + # TODO: this will at least run auto-update code but won't perform an update + # since the image didn't change. We need to improve on that and run + # an image from a local registry instead. + run_podman auto-update + # All good. Stop service, clean up. run $SYSTEMCTL stop "$SERVICE_NAME" if [ $status -ne 0 ]; then diff --git a/test/system/410-selinux.bats b/test/system/410-selinux.bats index 8a0477eff..1769730f0 100644 --- a/test/system/410-selinux.bats +++ b/test/system/410-selinux.bats @@ -63,4 +63,23 @@ function check_label() { check_label "--security-opt label=level:s0:c1,c2" "container_t" "s0:c1,c2" } +# pr #6752 +@test "podman selinux: inspect multiple labels" { + if [ ! -e /usr/sbin/selinuxenabled ] || ! /usr/sbin/selinuxenabled; then + skip "selinux disabled or not available" + fi + + run_podman run -d --name myc \ + --security-opt seccomp=unconfined \ + --security-opt label=type:spc_t \ + --security-opt label=level:s0 \ + $IMAGE sh -c 'while test ! -e /stop; do sleep 0.1; done' + run_podman inspect --format='{{ .HostConfig.SecurityOpt }}' myc + is "$output" "\[label=type:spc_t,label=level:s0 seccomp=unconfined]" \ + "'podman inspect' preserves all --security-opts" + + run_podman exec myc touch /stop + run_podman rm -f myc +} + # vim: filetype=sh diff --git a/test/test_dockerpy/README.md b/test/test_dockerpy/README.md deleted file mode 100644 index 32e426d58..000000000 --- a/test/test_dockerpy/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Dockerpy regression test - -Python test suite to validate Podman endpoints using dockerpy library - -Running tests -============= -To run the tests locally in your sandbox: - -#### Run the entire test - -``` -sudo PYTHONPATH=/usr/bin/python python -m dockerpy.images -``` - -Passing the -v option to your test script will instruct unittest.main() to enable a higher level of verbosity, and produce detailed output: - -``` -sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images -``` -#### Run a specific test class - -``` -sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images.TestImages -``` - -#### Run a specific test within the test class - -``` -sudo PYTHONPATH=/usr/bin/python python -m unittest -v dockerpy.images.TestImages.test_list_images -``` diff --git a/test/test_dockerpy/common.py b/test/test_dockerpy/common.py deleted file mode 100644 index 975b13dc6..000000000 --- a/test/test_dockerpy/common.py +++ /dev/null @@ -1,85 +0,0 @@ -import docker -import subprocess -import os -import sys -import time -from docker import Client -from . import constant - -alpineDict = { - "name": "docker.io/library/alpine:latest", - "shortName": "alpine", - "tarballName": "alpine.tar"} - -def get_client(): - client = docker.Client(base_url="http://localhost:8080",timeout=15) - return client - -client = get_client() - -def podman(): - binary = os.getenv("PODMAN_BINARY") - if binary is None: - binary = "bin/podman" - return binary - -def restore_image_from_cache(TestClass): - alpineImage = os.path.join(constant.ImageCacheDir , alpineDict["tarballName"]) - if not os.path.exists(alpineImage): - os.makedirs(constant.ImageCacheDir) - client.pull(constant.ALPINE) - response = client.get_image(constant.ALPINE) - image_tar = open(alpineImage,mode="wb") - image_tar.write(response.data) - image_tar.close() - else : - TestClass.podman = subprocess.run( - [ - podman(), "load", "-i", alpineImage - ], - shell=False, - stdin=subprocess.DEVNULL, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - ) - -def run_top_container(): - c = client.create_container(image=constant.ALPINE,command='/bin/sleep 5',name=constant.TOP) - client.start(container=c.get("Id")) - return c.get("Id") - -def enable_sock(TestClass): - TestClass.podman = subprocess.Popen( - [ - podman(), "system", "service", "tcp:localhost:8080", - "--log-level=debug", "--time=0" - ], - shell=False, - stdin=subprocess.DEVNULL, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - ) - time.sleep(2) - -def terminate_connection(TestClass): - TestClass.podman.terminate() - stdout, stderr = TestClass.podman.communicate(timeout=0.5) - if stdout: - print("\nService Stdout:\n" + stdout.decode('utf-8')) - if stderr: - print("\nService Stderr:\n" + stderr.decode('utf-8')) - - if TestClass.podman.returncode > 0: - sys.stderr.write("podman exited with error code {}\n".format( - TestClass.podman.returncode)) - sys.exit(2) - -def remove_all_containers(): - containers = client.containers(quiet=True) - for c in containers: - client.remove_container(container=c.get("Id"), force=True) - -def remove_all_images(): - allImages = client.images() - for image in allImages: - client.remove_image(image,force=True) diff --git a/test/test_dockerpy/constant.py b/test/test_dockerpy/constant.py deleted file mode 100644 index 8a3f1d984..000000000 --- a/test/test_dockerpy/constant.py +++ /dev/null @@ -1,13 +0,0 @@ -BB = "docker.io/library/busybox:latest" -NGINX = "docker.io/library/nginx:latest" -ALPINE = "docker.io/library/alpine:latest" -ALPINE_SHORTNAME = "alpine" -ALPINELISTTAG = "docker.io/library/alpine:3.10.2" -ALPINELISTDIGEST = "docker.io/library/alpine@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb" -ALPINEAMD64DIGEST = "docker.io/library/alpine@sha256:acd3ca9941a85e8ed16515bfc5328e4e2f8c128caa72959a58a127b7801ee01f" -ALPINEAMD64ID = "961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4" -ALPINEARM64DIGEST = "docker.io/library/alpine@sha256:db7f3dcef3d586f7dd123f107c93d7911515a5991c4b9e51fa2a43e46335a43e" -ALPINEARM64ID = "915beeae46751fc564998c79e73a1026542e945ca4f73dc841d09ccc6c2c0672" -infra = "k8s.gcr.io/pause:3.2" -TOP = "top" -ImageCacheDir = "/tmp/podman/imagecachedir" |