diff --git a/buildman/container_cloud_config.py b/buildman/container_cloud_config.py index 2f882fe55..a94a99eff 100644 --- a/buildman/container_cloud_config.py +++ b/buildman/container_cloud_config.py @@ -5,12 +5,11 @@ Originally from https://github.com/DevTable/container-cloud-config """ import json -import os import logging - +import os from urllib.parse import quote as urlquote -from jinja2 import FileSystemLoader, Environment, StrictUndefined +from jinja2 import Environment, FileSystemLoader, StrictUndefined logger = logging.getLogger(__name__) @@ -37,7 +36,6 @@ class CloudConfigContext(object): password="", tag="latest", extra_args="", - command="", after_units=[], exec_start_post=[], exec_stop_post=[], @@ -65,7 +63,9 @@ class CloudConfigContext(object): raise path = os.path.join(os.path.dirname(__file__), "templates") - env = Environment(loader=FileSystemLoader(path), undefined=StrictUndefined) + env = Environment( + loader=FileSystemLoader(path), undefined=StrictUndefined, trim_blocks=True + ) self.populate_jinja_environment(env) template = env.get_template("dockersystemd.json") return template.render( @@ -76,7 +76,6 @@ class CloudConfigContext(object): password=password, tag=tag, extra_args=extra_args, - command=command, after_units=after_units, requires_units=requires_units, wants_units=wants_units, diff --git a/buildman/manager/test/test_executor.py b/buildman/manager/test/test_executor.py index 015605c9a..591d9d568 100644 --- a/buildman/manager/test/test_executor.py +++ b/buildman/manager/test/test_executor.py @@ -1,6 +1,10 @@ -from buildman.manager.executor import KubernetesPodmanExecutor +import json from unittest.mock import mock_open, patch + +import pytest + from _init import OVERRIDE_CONFIG_DIRECTORY +from buildman.manager.executor import BuilderExecutor, KubernetesPodmanExecutor def test_podman_executor_adding_cacerts(): @@ -19,3 +23,91 @@ def test_podman_executor_adding_cacerts(): mock_file.assert_called_with( OVERRIDE_CONFIG_DIRECTORY + "extra_ca_cert_additional.crt", "r" ) + + +@pytest.mark.parametrize( + "executor_config,expected_quay_builder_unit_contents", + [ + ( + { + "CONTAINER_RUNTIME": "docker", + }, + """[Unit] +Wants=docker.service network-online.target +After=docker.service network-online.target +Requires=docker.service + +[Service] +Type=oneshot +TimeoutStartSec=10800 +TimeoutStopSec=2000 + +ExecStartPre=/usr/bin/docker login -u quay_username -p quay_password quay.io +ExecStart=/usr/bin/docker run --user 0 --rm --net=host --privileged --env-file /root/overrides.list -v /var/run/docker.sock:/var/run/docker.sock -v /etc/pki/ca-trust-source/anchors:/certs --name quay-builder quay.io/example/quay-builder:worker_tag +ExecStopPost=/bin/sh -xc "/bin/sleep 120; /usr/bin/systemctl --no-block poweroff" + +[Install] +WantedBy=multi-user.target""", + ), + ( + { + "CONTAINER_RUNTIME": "podman", + }, + """[Unit] +Wants=podman.service network-online.target +After=podman.service network-online.target +Requires=podman.service + +[Service] +Type=oneshot +TimeoutStartSec=10800 +TimeoutStopSec=2000 + +ExecStartPre=/usr/bin/podman login -u quay_username -p quay_password quay.io +ExecStart=/usr/bin/podman run --user 0 --rm --privileged --env-file /root/overrides.list -v /var/run/podman/podman.sock:/var/run/podman/podman.sock -v /etc/pki/ca-trust-source/anchors:/certs -e CONTAINER_RUNTIME=podman -e DOCKER_HOST=unix:/var/run/podman/podman.sock --name quay-builder quay.io/example/quay-builder:worker_tag +ExecStopPost=/bin/sh -xc "/bin/sleep 120; /usr/bin/systemctl --no-block poweroff" + +[Install] +WantedBy=multi-user.target""", + ), + ( + { + "CONTAINER_RUNTIME": "podman", + "MAX_LIFETIME_S": 7200, + "DEBUG": True, + }, + """[Unit] +Wants=podman.service network-online.target +After=podman.service network-online.target +Requires=podman.service + +[Service] +Type=oneshot +TimeoutStartSec=7200 +TimeoutStopSec=2000 + +ExecStartPre=/usr/bin/podman login -u quay_username -p quay_password quay.io +ExecStart=/usr/bin/podman run --user 0 --rm --privileged --env-file /root/overrides.list -v /var/run/podman/podman.sock:/var/run/podman/podman.sock -v /etc/pki/ca-trust-source/anchors:/certs -e CONTAINER_RUNTIME=podman -e DOCKER_HOST=unix:/var/run/podman/podman.sock --name quay-builder quay.io/example/quay-builder:worker_tag + +[Install] +WantedBy=multi-user.target""", + ), + ], +) +def test_builder_cloud_config(executor_config, expected_quay_builder_unit_contents): + executor_config = { + "CA_CERT": b"ca_cert", + "QUAY_PASSWORD": "quay_password", + "QUAY_USERNAME": "quay_username", + "WORKER_IMAGE": "quay.io/example/quay-builder", + "WORKER_TAG": "worker_tag", + } | executor_config + executor = BuilderExecutor(executor_config, "registry_hostname", "manager_hostname") + generated_cloud_config_json = executor.generate_cloud_config( + "token", "build_uuid", "manager_hostname" + ) + generated_cloud_config = json.loads(generated_cloud_config_json) + quay_builder_unit = generated_cloud_config["systemd"]["units"][0] + assert quay_builder_unit["name"] == "quay-builder.service" + assert quay_builder_unit["enabled"] + assert quay_builder_unit["contents"] == expected_quay_builder_unit_contents diff --git a/buildman/templates/cloudconfig.json b/buildman/templates/cloudconfig.json index 25d551bdd..39150c202 100644 --- a/buildman/templates/cloudconfig.json +++ b/buildman/templates/cloudconfig.json @@ -156,7 +156,7 @@ short-name-mode="permissive" quay_username, quay_password, worker_tag, - extra_args='--privileged --env-file /root/overrides.list -v /var/run/podman/podman.sock:/var/run/podman/podman.sock -v /etc/pki/ca-trust-source/anchors:/certs -e DOCKER_HOST=unix:/var/run/podman/podman.sock', + extra_args='--privileged --env-file /root/overrides.list -v /var/run/podman/podman.sock:/var/run/podman/podman.sock -v /etc/pki/ca-trust-source/anchors:/certs -e CONTAINER_RUNTIME=podman -e DOCKER_HOST=unix:/var/run/podman/podman.sock', restart_policy='no', oneshot=True, timeout_start_sec=timeout_start_sec, @@ -168,7 +168,7 @@ short-name-mode="permissive" quay_username, quay_password, worker_tag, - extra_args='--privileged --env-file /root/overrides.list -v /var/run/podman/podman.sock:/var/run/podman/podman.sock -v /etc/pki/ca-trust-source/anchors:/certs -e DOCKER_HOST=unix:/var/run/podman/podman.sock', + extra_args='--privileged --env-file /root/overrides.list -v /var/run/podman/podman.sock:/var/run/podman/podman.sock -v /etc/pki/ca-trust-source/anchors:/certs -e CONTAINER_RUNTIME=podman -e DOCKER_HOST=unix:/var/run/podman/podman.sock', exec_stop_post=['/bin/sh -xc "/bin/sleep 120; /usr/bin/systemctl --no-block poweroff"'], restart_policy='no', oneshot=True, diff --git a/buildman/templates/dockersystemd.json b/buildman/templates/dockersystemd.json index 3ad4e00bc..f24f28678 100644 --- a/buildman/templates/dockersystemd.json +++ b/buildman/templates/dockersystemd.json @@ -10,28 +10,28 @@ Wants=docker.service network-online.target After=docker.service network-online.target Requires=docker.service {% endif %} -{% if onfailure_units -%} -OnFailure={% for failure in onfailure_units -%}{{ failure }} {% endfor %} -{%- endif %} -{% for after in after_units -%} +{% if onfailure_units %} +OnFailure={% for failure in onfailure_units %}{{ failure }} {% endfor %} +{% endif %} +{% for after in after_units %} After={{ after }} {% endfor %} -{% for requires in requires_units -%} +{% for requires in requires_units %} Requires={{ requires }} {% endfor %} -{% for wants in wants_units -%} +{% for wants in wants_units %} Wants={{ wants }} {% endfor %} [Service] -{% if env_file -%} +{% if env_file %} EnvironmentFile={{ env_file }} -{%- endif %} -{% if oneshot -%} +{% endif %} +{% if oneshot %} Type=oneshot -{% else -%} +{% else %} Restart={{ restart_policy }} -{%- endif %} +{% endif %} TimeoutStartSec={{ timeout_start_sec if timeout_start_sec else 600 }} TimeoutStopSec={{ timeout_stop_sec if timeout_stop_sec else 2000 }} @@ -39,26 +39,26 @@ TimeoutStopSec={{ timeout_stop_sec if timeout_stop_sec else 2000 }} {% if username and password %} ExecStartPre=/usr/bin/podman login -u {{ username }} -p {{ password }} {{ container|registry }} {% endif %} -ExecStart=/usr/bin/podman run --user 0 --rm {{ extra_args }} --name {{ name }} {{ container }}:{{ tag }} {{ command }} -{% for start_post in exec_start_post -%} +ExecStart=/usr/bin/podman run --user 0 --rm {{ extra_args }} --name {{ name }} {{ container }}:{{ tag }} +{% for start_post in exec_start_post %} ExecStartPost={{ start_post }} {% endfor %} -{% if not oneshot -%} +{% if not oneshot %} ExecStop=/usr/bin/podman stop {{ name }} -{%- endif %} +{% endif %} {% else %} {% if username and password %} ExecStartPre=/usr/bin/docker login -u {{ username }} -p {{ password }} {{ container|registry }} {% endif %} -ExecStart=/usr/bin/docker run --user 0 --rm {{ extra_args }} --name {{ name }} {{ container }}:{{ tag }} {{ command }} -{% for start_post in exec_start_post -%} +ExecStart=/usr/bin/docker run --user 0 --rm {{ extra_args }} --name {{ name }} {{ container }}:{{ tag }} +{% for start_post in exec_start_post %} ExecStartPost={{ start_post }} {% endfor %} -{% if not oneshot -%} +{% if not oneshot %} ExecStop=/usr/bin/docker stop {{ name }} -{%- endif %} {% endif %} -{% for stop_post in exec_stop_post -%} +{% endif %} +{% for stop_post in exec_stop_post %} ExecStopPost={{ stop_post }} {% endfor %} diff --git a/tox.ini b/tox.ini index 5479271ab..c3dcf9d06 100644 --- a/tox.ini +++ b/tox.ini @@ -23,7 +23,7 @@ setenv = commands = python --version alembic upgrade head - py.test --timeout=3600 -m {env:MARKERS} --cov-report=html --cov-report=term-missing -x --color no --verbose --ignore=buildman/ {env:FILE} -vv {posargs} + py.test --timeout=3600 -m {env:MARKERS} --cov-report=html --cov-report=term-missing -x --color no --verbose --ignore=buildman/test/test_buildman.py {env:FILE} -vv {posargs} [docker:mysql] image = mysql:5.7 @@ -54,7 +54,7 @@ allowlist_externals = /bin/sh commands = python --version /bin/sh -c "TEST_DATABASE_URI=mysql+pymysql://quay:quay@127.0.0.1:$MYSQL_3306_TCP_PORT/quay_ci alembic upgrade head" - /bin/sh -c 'TEST_DATABASE_URI=mysql+pymysql://quay:quay@127.0.0.1:$MYSQL_3306_TCP_PORT/quay_ci py.test --timeout=3600 -m {env:MARKERS} --cov-report=html --cov-report=term-missing -x --color no --verbose --ignore=buildman/ -vv {posargs}' + /bin/sh -c 'TEST_DATABASE_URI=mysql+pymysql://quay:quay@127.0.0.1:$MYSQL_3306_TCP_PORT/quay_ci py.test --timeout=3600 -m {env:MARKERS} --cov-report=html --cov-report=term-missing -x --color no --verbose --ignore=buildman/test/test_buildman.py -vv {posargs}' [docker:postgres] @@ -86,4 +86,4 @@ commands = python --version /bin/sh -c "docker exec $(docker ps -q -n 1) psql -U quay -d quay_ci -c 'CREATE EXTENSION IF NOT EXISTS pg_trgm;'" /bin/sh -c "TEST_DATABASE_URI=postgresql://quay:quay@127.0.0.1:$POSTGRES_5432_TCP_PORT/quay_ci alembic upgrade head" - /bin/sh -c 'TEST_DATABASE_URI=postgresql://quay:quay@127.0.0.1:$POSTGRES_5432_TCP_PORT/quay_ci py.test --timeout=3600 -m {env:MARKERS} --cov-report=html --cov-report=term-missing -x --color no --verbose --ignore=buildman/ -vv {posargs}' + /bin/sh -c 'TEST_DATABASE_URI=postgresql://quay:quay@127.0.0.1:$POSTGRES_5432_TCP_PORT/quay_ci py.test --timeout=3600 -m {env:MARKERS} --cov-report=html --cov-report=term-missing -x --color no --verbose --ignore=buildman/test/test_buildman.py -vv {posargs}'