]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
integration testing: initial Podman API code
authorVasek Sraier <git@vakabus.cz>
Thu, 4 Mar 2021 16:11:21 +0000 (17:11 +0100)
committerAleš Mrázek <ales.mrazek@nic.cz>
Fri, 8 Apr 2022 14:17:51 +0000 (16:17 +0200)
manager/integration/Dockerfile [new file with mode: 0644]
manager/integration/runner.py [new file with mode: 0644]
manager/poetry.lock
manager/pyproject.toml

diff --git a/manager/integration/Dockerfile b/manager/integration/Dockerfile
new file mode 100644 (file)
index 0000000..0605685
--- /dev/null
@@ -0,0 +1,3 @@
+FROM debian:latest
+
+CMD sleep 20 && echo "hello" && exit 5
diff --git a/manager/integration/runner.py b/manager/integration/runner.py
new file mode 100644 (file)
index 0000000..1cea092
--- /dev/null
@@ -0,0 +1,99 @@
+import subprocess
+import signal
+import uuid
+from typing import Optional, List
+import shutil
+import pathlib
+import tarfile
+import os
+import time
+import sys
+import requests
+
+SOCKET_DIR = pathlib.Path("/dev/shm")
+
+class PodmanService:
+    def __init__(self):
+        self._process: Optional[subprocess.Popen] = None
+    def __enter__(self):
+        self._process = subprocess.Popen("podman system service tcp:localhost:13579  --log-level=info --time=0", shell=True)
+        time.sleep(0.5)  # required to prevent connection
+        return PodmanServiceManager("http://localhost:13579")
+    def __exit__(self, ex_type, ex_value, ex_traceback):
+        failed_while_running = (self._process.poll() is not None)
+        self._process.send_signal(signal.SIGINT)
+
+        time.sleep(0.5) # fixes interleaved stacktraces with podman's output
+
+        if failed_while_running:
+            raise Exception("Failed to properly start the podman service", ex_value)
+
+class PodmanServiceManager:
+    """
+    Using HTTP Rest API new in version 2.0. Documentation here:
+    https://docs.podman.io/en/latest/_static/api.html
+    """
+    _API_VERSION = "v1.0.0"
+
+    def __init__(self, url):
+        self._url = url
+
+    def _create_url(self, path):
+        return self._url + '/' + PodmanServiceManager._API_VERSION + '/' + path
+    
+    @staticmethod
+    def _create_tar_achive(directory: pathlib.Path, outfile: pathlib.Path):
+        with tarfile.open(str(outfile), "w:gz") as tar_handle:
+            for root, _, files in os.walk(str(directory)):
+                for file in files:
+                    tar_handle.add(os.path.join(root, file))
+
+    def build_image(self, context_dir: pathlib.Path, image: str):
+        # create tar archive out of the context_dir (weird, but there is no other way to specify context)
+        tar = pathlib.Path("/tmp/context.tar.gz")
+        PodmanServiceManager._create_tar_achive(context_dir, tar)
+        try:
+            # send the API request
+            with open(tar, 'rb') as f:
+                response = requests.post(self._create_url('libpod/build'), params=[("t", image)], data=f)
+            response.raise_for_status()
+
+        finally:
+            # cleanup the tar file
+            tar.unlink()
+
+    def start_temporary_and_wait(self, image: str, command: List[str]) -> int:
+        # create the container
+        response = requests.post(self._create_url('libpod/containers/create'), json={
+                "command": command,
+                "image": image,
+                "remove": True,
+            }
+        )
+        response.raise_for_status()
+        container_id = response.json()['Id']
+
+        # start the container
+        response = requests.post(self._create_url(f'libpod/containers/{container_id}/start'))
+        response.raise_for_status()
+
+        # the container is doing something
+
+        # wait for the container
+        response = requests.post(self._create_url(f'libpod/containers/{container_id}/wait'), params=[('condition', 'exited')], timeout=None)
+        response.raise_for_status()
+        return int(response.text)
+
+
+
+
+def main():
+    with PodmanService() as manager:
+        IMAGE = "testenv"
+        manager.build_image(pathlib.Path("."), IMAGE)
+        res = manager.start_temporary_and_wait(IMAGE, ["bash", "-c", "exit 12"])
+        print("Exit code", res)
+
+
+if __name__ == "__main__":
+    main()
index 5e3e2a910f687fa1a74c85e99fc92e007879fd22..2ea8f77f132c31d4147b79b80a70afa6ab36ccdb 100644 (file)
@@ -108,6 +108,14 @@ typing-extensions = ">=3.7.4"
 colorama = ["colorama (>=0.4.3)"]
 d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
 
+[[package]]
+name = "certifi"
+version = "2020.12.5"
+description = "Python package for providing Mozilla's CA Bundle."
+category = "dev"
+optional = false
+python-versions = "*"
+
 [[package]]
 name = "chardet"
 version = "3.0.4"
@@ -224,11 +232,11 @@ gitdb = ">=4.0.1,<5"
 
 [[package]]
 name = "idna"
-version = "3.1"
+version = "2.10"
 description = "Internationalized Domain Names in Applications (IDNA)"
 category = "main"
 optional = false
-python-versions = ">=3.4"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "idna-ssl"
@@ -650,6 +658,24 @@ category = "dev"
 optional = false
 python-versions = "*"
 
+[[package]]
+name = "requests"
+version = "2.25.1"
+description = "Python HTTP for Humans."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+chardet = ">=3.0.2,<5"
+idna = ">=2.5,<3"
+urllib3 = ">=1.21.1,<1.27"
+
+[package.extras]
+security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
+socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
+
 [[package]]
 name = "requirements-detector"
 version = "0.7"
@@ -809,6 +835,19 @@ category = "main"
 optional = false
 python-versions = "*"
 
+[[package]]
+name = "urllib3"
+version = "1.26.3"
+description = "HTTP library with thread-safe connection pooling, file post, and more."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
+
+[package.extras]
+brotli = ["brotlipy (>=0.6.0)"]
+secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
+socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+
 [[package]]
 name = "virtualenv"
 version = "20.4.2"
@@ -873,7 +912,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.6.12"
-content-hash = "f88e69a2748e50bd111eeda6d8e56c7cdbcea2f419830a697a54e5e8502a1403"
+content-hash = "3c88907317606698cea3e6abbf6e5d84a68a32f942f90e3115f8a02f88539051"
 
 [metadata.files]
 aiohttp = [
@@ -942,6 +981,10 @@ bandit = [
 black = [
     {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"},
 ]
+certifi = [
+    {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"},
+    {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"},
+]
 chardet = [
     {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
     {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
@@ -1038,8 +1081,8 @@ gitpython = [
     {file = "GitPython-3.1.13.tar.gz", hash = "sha256:8621a7e777e276a5ec838b59280ba5272dd144a18169c36c903d8b38b99f750a"},
 ]
 idna = [
-    {file = "idna-3.1-py3-none-any.whl", hash = "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16"},
-    {file = "idna-3.1.tar.gz", hash = "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1"},
+    {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
+    {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
 ]
 idna-ssl = [
     {file = "idna-ssl-1.1.0.tar.gz", hash = "sha256:a933e3bb13da54383f9e8f35dc4f9cb9eb9b3b78c6b36f311254d6d0d92c6c7c"},
@@ -1319,6 +1362,10 @@ regex = [
     {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"},
     {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"},
 ]
+requests = [
+    {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"},
+    {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"},
+]
 requirements-detector = [
     {file = "requirements-detector-0.7.tar.gz", hash = "sha256:0d1e13e61ed243f9c3c86e6cbb19980bcb3a0e0619cde2ec1f3af70fdbee6f7b"},
 ]
@@ -1434,6 +1481,10 @@ typing-extensions = [
     {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"},
     {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"},
 ]
+urllib3 = [
+    {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"},
+    {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"},
+]
 virtualenv = [
     {file = "virtualenv-20.4.2-py2.py3-none-any.whl", hash = "sha256:2be72df684b74df0ea47679a7df93fd0e04e72520022c57b479d8f881485dbe3"},
     {file = "virtualenv-20.4.2.tar.gz", hash = "sha256:147b43894e51dd6bba882cf9c282447f780e2251cd35172403745fc381a0a80d"},
index 7841f3821270820e6a879c73acf96014426f5cb3..dab0a5dd1398ceae06325fd3c923757728867f33 100644 (file)
@@ -22,6 +22,7 @@ tox = "^3.21.4"
 tox-pyenv = "^1.1.0"
 poethepoet = "^0.9.0"
 prospector = {extras = ["with_mypy", "with_bandit"], version = "^1.3.1"}
+requests = "^2.25.1"
 
 [tool.poe.tasks]
 run = { cmd = "python -m knot_resolver_manager", help = "Run the manager" }