Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to label all started containers #177

Merged
merged 2 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions buildrunner/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def __init__(
local_images: bool,
platform: Optional[str],
global_config_overrides: dict,
container_labels: Optional[str] = None,
): # pylint: disable=too-many-statements,too-many-branches,too-many-locals,too-many-arguments
self.build_dir = build_dir
self.build_results_dir = build_results_dir
Expand Down Expand Up @@ -141,6 +142,7 @@ def __init__(
build_time=self.build_time,
tmp_files=self.tmp_files,
global_config_overrides=global_config_overrides,
container_labels=container_labels,
)
self.buildrunner_config = BuildRunnerConfig.get_instance()

Expand Down
10 changes: 10 additions & 0 deletions buildrunner/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ def parse_args(argv):
help="enables debug logging",
)

parser.add_argument(
"--container-labels",
default=None,
help=(
"arbitrary labels to add to every container started by buildrunner, "
"in the form of 'key1=value1,key2=value2'"
),
)

parser.add_argument(
"-n",
"--build-number",
Expand Down Expand Up @@ -396,6 +405,7 @@ def initialize_br(args: argparse.Namespace) -> BuildRunner:
local_images=args.local_images,
platform=args.platform,
global_config_overrides=_get_global_config_overrides(args),
container_labels=args.container_labels,
)


Expand Down
17 changes: 17 additions & 0 deletions buildrunner/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ def __init__(
log_generated_files: bool,
build_time: int,
global_config_overrides: dict,
# Arbitrary labels to add to all started containers, of the form key1=value1,key2=value2
container_labels: Optional[str] = None,
# May be passed in to add temporary files to this list as they are created
tmp_files: Optional[List[str]] = None,
# Used only from CLI commands that do not need a run config
Expand All @@ -83,6 +85,7 @@ def __init__(
self.build_time = build_time
if not self.build_time:
self.build_time = epoch_time()
self.container_labels = self._parse_container_labels(container_labels)
self.tmp_files = tmp_files

self.global_config = self._load_global_config(
Expand All @@ -99,6 +102,20 @@ def __init__(
self._load_run_config(run_config_file) if load_run_config else None
)

@staticmethod
def _parse_container_labels(container_labels_str: Optional[str]) -> dict:
container_labels = {}
if not container_labels_str:
return container_labels
for pair in container_labels_str.split(","):
if "=" not in pair:
raise BuildRunnerConfigurationError(
"Invalid container label format, must be key=value"
)
key, value = pair.split("=", 1)
container_labels[key] = value
return container_labels

def _load_global_config(
self, global_config_file: Optional[str], global_config_overrides: dict
) -> GlobalConfig:
Expand Down
6 changes: 4 additions & 2 deletions buildrunner/docker/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import six
import timeout_decorator

from buildrunner import BuildRunnerConfig
from buildrunner.docker import (
new_client,
force_remove_container,
Expand Down Expand Up @@ -79,10 +80,10 @@ def __init__(self, image_name, pull_image=True, platform=None):
def __init__(self, image_config, dockerd_url=None, log=None):
image_name = image_config.image_name
pull_image = image_config.pull_image
platform = image_config.platform
image_platform = image_config.platform

self.image_name = image_name.lower()
self.platform = platform
self.platform = image_platform
if log and self.image_name != image_name:
log.write(
f"Forcing image_name to lowercase: {image_name} => {self.image_name}\n"
Expand Down Expand Up @@ -230,6 +231,7 @@ def start(
"user": user,
"working_dir": working_dir,
"hostname": hostname,
"labels": BuildRunnerConfig.get_instance().container_labels,
"host_config": self.docker_client.create_host_config(
binds=_binds,
links=links,
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from setuptools import setup, find_packages


BASE_VERSION = "3.14"
BASE_VERSION = "3.15"

SOURCE_DIR = os.path.dirname(os.path.abspath(__file__))
BUILDRUNNER_DIR = os.path.join(SOURCE_DIR, "buildrunner")
Expand Down
21 changes: 20 additions & 1 deletion tests/test_caching.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from time import sleep
from unittest import mock

from buildrunner import BuildRunner
from buildrunner import BuildRunner, BuildRunnerConfig
from buildrunner.docker.runner import DockerRunner
from buildrunner.loggers import ConsoleLogger
import pytest
Expand All @@ -28,6 +28,25 @@ def _tar_safe_extractall(tar, path=".", members=None, *, numeric_owner=False):
tar.extractall(path, members, numeric_owner=numeric_owner)


@pytest.fixture(name="initialize_config", autouse=True)
def fixture_initialize_config(tmp_path):
buildrunner_path = tmp_path / "buildrunner.yaml"
buildrunner_path.write_text("steps: {'step1': {}}")
BuildRunnerConfig.initialize_instance(
build_id="123",
vcs=None,
build_dir=str(tmp_path),
global_config_file=None,
run_config_file=str(buildrunner_path),
build_time=0,
build_number=1,
push=False,
steps_to_run=None,
log_generated_files=False,
global_config_overrides={},
)


@pytest.fixture(name="runner")
def fixture_setup_runner():
image_config = DockerRunner.ImageConfig(
Expand Down
64 changes: 64 additions & 0 deletions tests/test_config_validation/test_container_labels.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import os
from unittest import mock

import pytest

from buildrunner import BuildRunner, BuildRunnerConfig


TEST_DIR = os.path.dirname(os.path.abspath(__file__))
BLANK_GLOBAL_CONFIG = os.path.join(TEST_DIR, "files/blank_global_config.yaml")


@pytest.mark.parametrize(
"container_labels, result_labels",
[
(None, {}),
("", {}),
("key1=val1", {"key1": "val1"}),
("key1=val1,key2=val2", {"key1": "val1", "key2": "val2"}),
("key1=val1=val3,key2=val2", {"key1": "val1=val3", "key2": "val2"}),
],
)
@mock.patch("buildrunner.detect_vcs")
def test_container_labels(
detect_vcs_mock,
container_labels,
result_labels,
tmp_path,
):
id_string = "main-921.ie02ed8.m1705616822"
type(detect_vcs_mock.return_value).id_string = mock.PropertyMock(
return_value=id_string
)
buildrunner_path = tmp_path / "buildrunner.yaml"
buildrunner_path.write_text(
"""
steps:
build-container:
build:
dockerfile: |
FROM {{ DOCKER_REGISTRY }}/nginx:latest
RUN printf '{{ BUILDRUNNER_BUILD_NUMBER }}' > /usr/share/nginx/html/index.html
"""
)
BuildRunner(
build_dir=str(tmp_path),
build_results_dir=str(tmp_path / "buildrunner.results"),
global_config_file=None,
run_config_file=str(buildrunner_path),
build_time=0,
build_number=1,
push=False,
cleanup_images=False,
cleanup_cache=False,
steps_to_run=None,
publish_ports=False,
log_generated_files=False,
docker_timeout=30,
local_images=False,
platform=None,
global_config_overrides={},
container_labels=container_labels,
)
assert BuildRunnerConfig.get_instance().container_labels == result_labels
Loading