--- /dev/null
+node_modules/
+.mypy_cache/
+.pytest_cache/
+.tox/
+.git/
+.vscode/
+
+containers/
\ No newline at end of file
--- /dev/null
+# Container definition files
+
+All containers build configurations evolve from the `dev` container. If you want to change something, please do it mainly there. We consider **the `dev` container as a reference container**
+
+## Naming
+
+All containers defined here are named `knot-manager`. The directory name is the container's tag.
\ No newline at end of file
--- /dev/null
+FROM docker.io/debian:latest
+
+ENV \
+ # build:
+ BUILD_ONLY_PACKAGES='wget' \
+ # python:
+ PYTHONFAULTHANDLER=1 \
+ PYTHONUNBUFFERED=1 \
+ PYTHONHASHSEED=random \
+ PYTHONDONTWRITEBYTECODE=1 \
+ # pip:
+ PIP_NO_CACHE_DIR=off \
+ PIP_DISABLE_PIP_VERSION_CHECK=on \
+ PIP_DEFAULT_TIMEOUT=100 \
+ # poetry:
+ POETRY_VERSION=1.1.5 \
+ POETRY_NO_INTERACTION=1 \
+ POETRY_VIRTUALENVS_CREATE=false \
+ POETRY_CACHE_DIR='/var/cache/pypoetry' \
+ PATH="$PATH:/root/.poetry/bin" \
+ NODE_VERSION=node_14.x
+ENV LC_ALL=C.UTF-8
+
+# System deps:
+# System deps:
+RUN apt-get update \
+ && apt-get install --no-install-recommends -y \
+ bash \
+ build-essential git ca-certificates \
+ python3 python3-pip python3-dev python3-setuptools python3-wheel \
+ libcairo2-dev libgirepository1.0-dev \
+ gettext \
+ systemd \
+ curl \
+ dbus \
+ libcairo2-dev libgirepository1.0-dev \
+ # Defining build-time-only dependencies:
+ $BUILD_ONLY_PACKAGES \
+ # Install Knot Resolver
+ && wget https://secure.nic.cz/files/knot-resolver/knot-resolver-release.deb \
+ && dpkg -i knot-resolver-release.deb \
+ && rm knot-resolver-release.deb \
+ && apt-get update && apt-get install -y --no-install-recommends knot-resolver \
+ # Installing `poetry` package manager:
+ # https://github.com/python-poetry/poetry
+ && curl -sSL 'https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py' | python3 \
+ && poetry --version \
+ # Install test dependencies
+ && apt-get install --no-install-recommends procps curl \
+ && pip3 install requests requests-unixsocket \
+ # Removing build-time-only dependencies:
+ && apt-get remove -y $BUILD_ONLY_PACKAGES \
+ # Cleaning cache:
+ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
+ && apt-get clean -y && rm -rf /var/lib/apt/lists/*
+
+# Copy only requirements, to cache them in docker layer
+# no poetry.lock, because here we have a different python version
+COPY ./pyproject.toml ./yarn.lock ./package.json /code/
+
+WORKDIR /code
+
+# Install project dependencies
+RUN poetry --version \
+ # Aghghgh! The packaged pip is buggy and just plainly fails installing dependencies
+ # so here we update it
+ && python3 -m pip --version \
+ && python3 -m pip install -U pip \
+ && python3 -m pip --version \
+ # and install the dependencies
+ && poetry install --no-dev --no-interaction --no-ansi
+
+# Copy the remaining code
+COPY . /code
+
+CMD ["/bin/systemd"]
\ No newline at end of file
--- /dev/null
+# source: https://github.com/wemake-services/wemake-django-template/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/docker/django/Dockerfile
+
+# This Dockerfile uses multi-stage build to customize DEV and PROD images:
+# https://docs.docker.com/develop/develop-images/multistage-build/
+
+FROM docker.io/python:3.6.13-slim-buster
+
+# Agh, this would ideally be an ARG command, but podman has problems caching the build
+ENV KNOT_ENV=dev
+
+ENV \
+ # build:
+ BUILD_ONLY_PACKAGES='wget lsb-release gnupg' \
+ # python:
+ PYTHONFAULTHANDLER=1 \
+ PYTHONUNBUFFERED=1 \
+ PYTHONHASHSEED=random \
+ PYTHONDONTWRITEBYTECODE=1 \
+ # pip:
+ PIP_NO_CACHE_DIR=off \
+ PIP_DISABLE_PIP_VERSION_CHECK=on \
+ PIP_DEFAULT_TIMEOUT=100 \
+ # poetry:
+ POETRY_VERSION=1.1.5 \
+ POETRY_NO_INTERACTION=1 \
+ POETRY_VIRTUALENVS_CREATE=false \
+ POETRY_CACHE_DIR='/var/cache/pypoetry' \
+ PATH="$PATH:/root/.poetry/bin" \
+ NODE_VERSION=node_14.x
+
+
+# System deps:
+RUN apt-get update \
+ && apt-get install --no-install-recommends -y \
+ bash \
+ build-essential \
+ curl \
+ gettext \
+ git \
+ systemd \
+ dbus \
+ libcairo2-dev libgirepository1.0-dev \
+ # Defining build-time-only dependencies:
+ $BUILD_ONLY_PACKAGES \
+ # Install Knot Resolver
+ && wget https://secure.nic.cz/files/knot-resolver/knot-resolver-release.deb \
+ && dpkg -i knot-resolver-release.deb \
+ && rm knot-resolver-release.deb \
+ && apt-get update && apt-get install -y --no-install-recommends knot-resolver \
+ # Installing Yarn and NodeJS
+ && curl -sSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - \
+ && echo "deb https://deb.nodesource.com/$NODE_VERSION $(lsb_release -s -c) main" | tee /etc/apt/sources.list.d/nodesource.list \
+ && echo "deb-src https://deb.nodesource.com/$NODE_VERSION $(lsb_release -s -c) main" | tee -a /etc/apt/sources.list.d/nodesource.list \
+ && apt-get update && apt-get install --no-install-recommends --no-install-suggests -y nodejs \
+ && npm install -g yarn \
+ # Installing `poetry` package manager:
+ # https://github.com/python-poetry/poetry
+ && curl -sSL 'https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py' | python \
+ && poetry --version \
+ # Removing build-time-only dependencies:
+ && apt-get remove -y $BUILD_ONLY_PACKAGES \
+ # Cleaning cache:
+ && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
+ && apt-get clean -y && rm -rf /var/lib/apt/lists/*
+
+# Copy only requirements, to cache them in docker layer
+COPY ./poetry.lock ./pyproject.toml ./yarn.lock ./package.json /code/
+
+WORKDIR /code
+
+# Install project dependencies
+RUN echo "Running in $KNOT_ENV" \
+ && poetry install \
+ $(if [ "$KNOT_ENV" != 'dev' ]; then echo '--no-dev'; fi) \
+ --no-interaction --no-ansi \
+ && if test "$KNOT_ENV" = "dev"; then yarn install; fi
+
+# Copy the remaining code
+COPY . /code
+
+CMD ["/bin/systemd"]
\ No newline at end of file
import hashlib
import click
import json
+import toml
from _hashlib import HASH as Hash
from pathlib import Path, PurePath
return PurePath(str(result.stdout, encoding="utf8").strip())
+class Test:
+ _CONFIG_FILE = "test.toml"
+
+ def __init__(self, path: Path):
+ with open(path / Test._CONFIG_FILE, 'r') as f:
+ config = toml.load(f)
+
+ self._mounts = {}
+ gitroot: Path = _get_git_root()
+ for dst, src in config["mount"].items():
+ # note that we flip the meaning around to match podman's api
+ src = gitroot / src
+ dst = gitroot / dst
+ self._mounts[src] = dst
+
+ self.name = str(path.absolute().name)
+ self._cmd = [ str(x) for x in config["cmd"] ]
+ self._image = str(config["image"])
+
+
+ def run(self, manager: PodmanServiceManager, inspect_failed=False):
+ print(f"Running test {Colors.YELLOW}{self.name}{Colors.RESET}")
+ print("\tRunning...")
+ exit_code = manager.start_temporary_and_wait(
+ self._image,
+ self._cmd,
+ bind_mount_ro=self._mounts,
+ inspect_failed=inspect_failed,
+ )
+ if exit_code == 0:
+ print(f"\t{Colors.GREEN}Test succeeded{Colors.RESET}")
+ else:
+ print(
+ f"\t{Colors.RED}Test failed with exit code {exit_code}{Colors.RESET}"
+ )
+
class TestRunner:
_TEST_DIRECTORY = "tests"
_TEST_ENTRYPOINT = ["/test/run"]
If no TESTS are specified, runs them all.
"""
+
+ # Temporary hack
+ # build all test containers
+ ret = subprocess.call("poe build-containers", shell=True)
+ assert ret == 0
+
+ # Run the tests
with PodmanService() as manager:
for test_path in TestRunner._list_tests():
- test_name = test_path.absolute().name
+ test = Test(test_path)
- if len(tests) != 0 and test_name not in tests:
- print(f"Skipping test {Colors.YELLOW}{test_name}{Colors.RESET}")
+ if len(tests) != 0 and test.name not in tests:
+ print(f"Skipping test {Colors.YELLOW}{test.name}{Colors.RESET}")
continue
- print(f"Running test {Colors.YELLOW}{test_name}{Colors.RESET}")
- image = "knot_test_" + test_name
- print("\tBuilding...")
- manager.build_image(test_path, image)
- print("\tRunning...")
- exit_code = manager.start_temporary_and_wait(
- image,
- TestRunner._TEST_ENTRYPOINT,
- bind_mount_ro={
- _get_git_root(): PurePath("/repo"),
- test_path.absolute(): "/test",
- },
- inspect_failed=inspect_failed,
- )
- if exit_code == 0:
- print(f"\t{Colors.GREEN}Test succeeded{Colors.RESET}")
- else:
- print(
- f"\t{Colors.RED}Test failed with exit code {exit_code}{Colors.RESET}"
- )
+ test.run(manager)
if __name__ == "__main__":
+++ /dev/null
-FROM docker.io/debian:latest
-
-ENV LC_ALL=C.UTF-8
-
-# install project dependencies
-
-## build essentials
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y build-essential git ca-certificates
-
-## python
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y python3 python3-pip python3-dev
-
-## glib dependencies
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y libcairo2-dev libglib2.0-0 libgirepository1.0-dev
-
-## python setuptools
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y python3-setuptools
-
-## python libraries
-RUN pip3 install aiohttp strictyaml pydbus PyGObject jinja2
-
-## systemd
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y systemd
-
-## kresd
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y wget
-RUN wget https://secure.nic.cz/files/knot-resolver/knot-resolver-release.deb && dpkg -i knot-resolver-release.deb
-RUN apt-get update && apt-get install -y knot-resolver
-
-# dbus
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y dbus
-
-
-# install test dependencies
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y curl
-RUN pip3 install requests requests-unixsocket
-
-CMD ["/bin/systemd"]
After=dbus
[Service]
-WorkingDirectory=/repo
+WorkingDirectory=/code
ExecStart=/usr/bin/python3 -m knot_resolver_manager
KillSignal=SIGINT
--- /dev/null
+image = "knot-manager:debian"
+cmd = ["/test/run"]
+
+[mount]
+"/test" = "integration/tests/basic_startup"
\ No newline at end of file
+++ /dev/null
-FROM docker.io/debian:latest
-
-ENV LC_ALL=C.UTF-8
-
-# install project dependencies
-
-## build essentials
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y build-essential git ca-certificates
-
-## python
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y python3 python3-pip python3-dev
-
-## glib dependencies
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y libcairo2-dev libglib2.0-0 libgirepository1.0-dev
-
-## python setuptools
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y python3-setuptools
-
-## python libraries
-RUN pip3 install aiohttp strictyaml pydbus PyGObject jinja2
-
-## systemd
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y systemd
-
-## kresd
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y wget
-RUN wget https://secure.nic.cz/files/knot-resolver/knot-resolver-release.deb && dpkg -i knot-resolver-release.deb
-RUN apt-get update && apt-get install -y knot-resolver
-
-# dbus
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y dbus
-
-
-# install test dependencies
-RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y curl procps
-RUN pip3 install requests requests-unixsocket
-
-CMD ["/bin/systemd"]
After=dbus
[Service]
-WorkingDirectory=/repo
+WorkingDirectory=/code
ExecStart=/usr/bin/python3 -m knot_resolver_manager
KillSignal=SIGINT
--- /dev/null
+image = "knot-manager:debian"
+cmd = ["/test/run"]
+
+[mount]
+"/test" = "integration/tests/worker_count"
\ No newline at end of file
[metadata]
lock-version = "1.1"
python-versions = "^3.6.12"
-content-hash = "bc022eb5ed23d94fdafda9c9756ec70c61f4fe675889a9cb1dfaa31b0e85f84b"
+content-hash = "939e224639141a5d45cc48343ffeb9f8daf50f4c856a2c43c0538ffa66423bc0"
[metadata.files]
aiohttp = [
requests = "^2.25.1"
requests-unixsocket = "^0.2.0"
click = "^7.1.2"
+toml = "^0.10.2"
[tool.poe.tasks]
run = { cmd = "python -m knot_resolver_manager", help = "Run the manager" }
format = { cmd = "poetry run black knot_resolver_manager/ tests/", help = "Run 'Black' code formater" }
fixdeps = { shell = "poetry install; yarn install", help = "Install/update dependencies according to configuration files"}
commit = { shell = "scripts/commit", help = "Invoke every single check before commiting" }
+build-containers = { shell = "scripts/build-containers", help = "Build all containers" }
clean = """
rm -rf .coverage
.mypy_cache
--- /dev/null
+#!/bin/bash
+
+# fail early
+set -e
+
+# ensure consistent behaviour
+src_dir="$(dirname "$(realpath "$0")")"
+source $src_dir/_env.sh
+
+
+# build the actual containers
+for tag in $(find containers -maxdepth 1 -type d -printf '%f\n' | grep -v containers); do
+ podman build -t "knot-manager:$tag" -f "containers/$tag/Containerfile" .
+done
\ No newline at end of file