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

Simplify and add additional tests for mp building #95

Merged
merged 1 commit into from
Nov 9, 2023
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
43 changes: 18 additions & 25 deletions buildrunner/docker/multiplatform_image_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,6 @@ def _build_single_image(
self,
name: str,
platform: str,
push: bool,
path: str,
file: str,
tags: List[str],
Expand All @@ -303,7 +302,6 @@ def _build_single_image(
Args:
name (str): The name of the image
platform (str): The platform to build the image for (e.g. linux/amd64)
push (bool): Whether to push the image to the registry.
path (str): The path to the Dockerfile.
file (str): The path/name of the Dockerfile (ie. <path>/Dockerfile).
tags (List[str]): The tags to apply to the image.
Expand Down Expand Up @@ -340,8 +338,7 @@ def _build_single_image(
builder=builder,
)
# Push after the initial load to support remote builders that cannot access the local registry
if push:
docker.push(tagged_names)
docker.push(tagged_names)

# Check that the images were built and in the registry
# Docker search is not currently implemented in python-on-wheels
Expand Down Expand Up @@ -397,7 +394,6 @@ def build_multiple_images(
file: str = "Dockerfile",
mp_image_name: str = None,
tags: List[str] = None,
push=True,
do_multiprocessing: bool = True,
build_args: dict = None,
inject: dict = None,
Expand All @@ -411,7 +407,6 @@ def build_multiple_images(
file (str, optional): The path/name of the Dockerfile (ie. <path>/Dockerfile). Defaults to "Dockerfile".
mp_image_name (str, optional): The name of the image. Defaults to None.
tags (List[str], optional): The tags to apply to the image. Defaults to None.
push (bool, optional): Whether to push the image to the registry. Defaults to True.
do_multiprocessing (bool, optional): Whether to use multiprocessing to build the images. Defaults to True.
build_args (dict, optional): The build args to pass to docker. Defaults to None.
inject (dict, optional): The files to inject into the build context. Defaults to None.
Expand Down Expand Up @@ -472,28 +467,26 @@ def get_path(file):
processes = []
for platform in platforms:
platform_image_name = f"{base_image_name}-{platform.replace('/', '-')}"
logger.debug(f"Building {platform_image_name} for {platform}")
process = Process(
target=self._build_single_image,
args=(
platform_image_name,
platform,
push,
path,
dockerfile,
tags,
build_args,
mp_image_name,
inject
)
build_single_image_args = (
platform_image_name,
platform,
path,
dockerfile,
tags,
build_args,
mp_image_name,
inject,
)
logger.debug(f"Building {platform_image_name} for {platform}")
if do_multiprocessing:
processes.append(process)
processes.append(Process(
target=self._build_single_image,
args=build_single_image_args,
))
else:
process.start()
process.join()
self._build_single_image(*build_single_image_args)

# Start and join processes in parallel (if not already done)
# Start and join processes in parallel if multiprocessing is enabled
for proc in processes:
proc.start()
for proc in processes:
Expand Down Expand Up @@ -525,12 +518,12 @@ def push(self, name: str, dest_names: List[str] = None) -> None:
retries = 5

src_images = self._intermediate_built_images[name]
# only need get tags for one image, since they should be identical
assert len(src_images) > 0, f"No images found for {name}"

# Append the tags to the names prior to pushing
if dest_names is None:
dest_names = name
# only need get tags for one image, since they should be identical
for tag in src_images[0].tags:
tagged_names.append(f"{dest_names}:{tag}")
else:
Expand Down
57 changes: 56 additions & 1 deletion tests/test_multiplatform.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
from typing import List
from unittest.mock import MagicMock, patch
from unittest.mock import ANY, MagicMock, call, patch

import pytest
from python_on_whales import Image, docker
Expand Down Expand Up @@ -464,6 +464,61 @@ def test_build_multiple_builds(mock_build, mock_pull, mock_push, mock_inspect, m
missing_images = actual_images_match_expected(built_images2, expected_image_names2)
assert missing_images == [], f'Failed to find {missing_images} in {[image.repo for image in built_images2]}'

assert mock_build.call_count == 4
prefix = mock_build.call_args.kwargs['tags'][0].split('buildrunner-mp')[0]
assert mock_build.call_args_list == [
call(
'tests/test-files/multiplatform',
tags=[f'{prefix}buildrunner-mp-uuid1-linux-amd64:latest'],
platforms=['linux/amd64'],
load=True,
file='tests/test-files/multiplatform/Dockerfile',
build_args={'DOCKER_REGISTRY': None},
builder=None,
),
call(
'tests/test-files/multiplatform',
tags=[f'{prefix}buildrunner-mp-uuid1-linux-arm64:latest'],
platforms=['linux/arm64'],
load=True,
file='tests/test-files/multiplatform/Dockerfile',
build_args={'DOCKER_REGISTRY': None},
builder=None,
),
call(
'tests/test-files/multiplatform',
tags=[f'{prefix}buildrunner-mp-uuid2-linux-amd64:latest'],
platforms=['linux/amd64'],
load=True,
file='tests/test-files/multiplatform/Dockerfile',
build_args={'DOCKER_REGISTRY': None},
builder=None,
),
call(
'tests/test-files/multiplatform',
tags=[f'{prefix}buildrunner-mp-uuid2-linux-arm64:latest'],
platforms=['linux/arm64'],
load=True,
file='tests/test-files/multiplatform/Dockerfile',
build_args={'DOCKER_REGISTRY': None},
builder=None,
),
]
assert mock_push.call_count == 4
assert mock_push.call_args_list == [
call([f'{prefix}buildrunner-mp-uuid1-linux-amd64:latest']),
call([f'{prefix}buildrunner-mp-uuid1-linux-arm64:latest']),
call([f'{prefix}buildrunner-mp-uuid2-linux-amd64:latest']),
call([f'{prefix}buildrunner-mp-uuid2-linux-arm64:latest']),
]
assert mock_pull.call_count == 4
assert mock_pull.call_args_list == [
call(f'{prefix}buildrunner-mp-uuid1-linux-amd64:latest'),
call(f'{prefix}buildrunner-mp-uuid1-linux-arm64:latest'),
call(f'{prefix}buildrunner-mp-uuid2-linux-amd64:latest'),
call(f'{prefix}buildrunner-mp-uuid2-linux-arm64:latest'),
]


@pytest.mark.parametrize("name, tags, platforms, expected_image_names",[
('test-build-tag-image-2000',
Expand Down
Loading