From 3149291a8a88ce484631ef0d8ec8ae782fa4e156 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 25 Sep 2024 19:27:51 +0200 Subject: [PATCH 1/6] fix(docker): make linux container multi-arch Signed-off-by: AtomicFS --- docker/linux/Dockerfile | 18 ++++++++++++------ tests/test_linux.sh | 1 + 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docker/linux/Dockerfile b/docker/linux/Dockerfile index f52c5d76..3a2e8673 100644 --- a/docker/linux/Dockerfile +++ b/docker/linux/Dockerfile @@ -35,9 +35,6 @@ RUN apt-get update && \ g++-${GCC_VERSION} \ gawk \ gcc-${GCC_VERSION} \ - gcc-${GCC_VERSION}-aarch64-linux-gnu \ - gcc-${GCC_VERSION}-arm-linux-gnueabi \ - gcc-${GCC_VERSION}-i686-linux-gnu \ git \ gnupg2 \ libelf-dev \ @@ -52,6 +49,13 @@ RUN apt-get update && \ wget \ zstd \ && \ + arch="$(dpkg --print-architecture)" && arch="${arch##*-}"; \ + if [ "${arch}" = 'amd64' ]; then \ + apt-get install -y --no-install-recommends \ + gcc-${GCC_VERSION}-aarch64-linux-gnu \ + gcc-${GCC_VERSION}-arm-linux-gnueabi \ + gcc-${GCC_VERSION}-i686-linux-gnu; \ + fi; \ apt-get install -y --no-install-recommends \ less \ nano \ @@ -63,9 +67,11 @@ RUN apt-get update && \ && \ update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${GCC_VERSION} 100 && \ update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 100 && \ - update-alternatives --install /usr/bin/aarch64-linux-gnu-gcc aarch64-linux-gnu-gcc /usr/bin/aarch64-linux-gnu-gcc-${GCC_VERSION} 100 && \ - update-alternatives --install /usr/bin/arm-linux-gnueabi-gcc arm-linux-gnueabi-gcc /usr/bin/arm-linux-gnueabi-gcc-${GCC_VERSION} 100 && \ - update-alternatives --install /usr/bin/i686-linux-gnu-gcc i686-linux-gnu-gcc /usr/bin/i686-linux-gnu-gcc-${GCC_VERSION} 100 && \ + if [ "${arch}" = 'amd64' ]; then \ + update-alternatives --install /usr/bin/aarch64-linux-gnu-gcc aarch64-linux-gnu-gcc /usr/bin/aarch64-linux-gnu-gcc-${GCC_VERSION} 100 && \ + update-alternatives --install /usr/bin/arm-linux-gnueabi-gcc arm-linux-gnueabi-gcc /usr/bin/arm-linux-gnueabi-gcc-${GCC_VERSION} 100 && \ + update-alternatives --install /usr/bin/i686-linux-gnu-gcc i686-linux-gnu-gcc /usr/bin/i686-linux-gnu-gcc-${GCC_VERSION} 100; \ + fi; \ gpg2 --locate-keys torvalds@kernel.org gregkh@kernel.org && \ rm -rf /var/lib/apt/lists/* diff --git a/tests/test_linux.sh b/tests/test_linux.sh index 6582f595..7ead5d69 100755 --- a/tests/test_linux.sh +++ b/tests/test_linux.sh @@ -42,5 +42,6 @@ fi # Make cd "${LINUX_BASE}" cp "${SCRIPT_DIR}/linux_${VERIFICATION_TEST_LINUX_VERSION}/linux.defconfig" ./arch/x86/configs/ci_defconfig +cp "${SCRIPT_DIR}/linux_${VERIFICATION_TEST_LINUX_VERSION}/linux.defconfig" ./arch/arm64/configs/ci_defconfig make ci_defconfig make -j "$(nproc)" From 7af07b20a15c0752ca06c6cc06d8b30dfdc0a4b8 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 25 Sep 2024 20:03:55 +0200 Subject: [PATCH 2/6] fix(docker): make edk2 container multi-arch Signed-off-by: AtomicFS --- docker/edk2/Dockerfile | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/docker/edk2/Dockerfile b/docker/edk2/Dockerfile index 0b57f176..574421c4 100644 --- a/docker/edk2/Dockerfile +++ b/docker/edk2/Dockerfile @@ -33,7 +33,10 @@ ENV TOOLSDIR=/tools ENV WORKSPACE_CORE=$TOOLSDIR/Edk2 ENV WORKSPACE=$TOOLSDIR/Edk2 -RUN dpkg --add-architecture i386 && \ +RUN arch="$(dpkg --print-architecture)" && arch="${arch##*-}"; \ + if [ "${arch}" = 'amd64' ]; then \ + dpkg --add-architecture i386; \ + fi; \ apt-get update && \ apt-get install -y --no-install-recommends \ ${PYTHON_PACKAGES} \ @@ -44,19 +47,22 @@ RUN dpkg --add-architecture i386 && \ flex \ g++-${GCC_VERSION} \ gcc-${GCC_VERSION} \ - ${GCC_CROSS_COMPILER_PACKAGES} \ git \ imagemagick \ - iucode-tool \ nasm \ nodejs \ openssh-client \ qemu-system-x86 \ uuid-dev \ wine-stable \ - wine32 \ wine64 \ && \ + if [ "${arch}" = 'amd64' ]; then \ + apt-get install -y --no-install-recommends \ + ${GCC_CROSS_COMPILER_PACKAGES} \ + iucode-tool \ + wine32; \ + fi; \ apt-get install -y --no-install-recommends \ less \ nano \ @@ -69,9 +75,11 @@ RUN dpkg --add-architecture i386 && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ mkdir -p "${TOOLSDIR}" && \ - update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 100 && \ - update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${GCC_VERSION} 100 && \ - \ + if [ "${arch}" = 'amd64' ]; then \ + update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 100 && \ + update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${GCC_VERSION} 100 && \ + update-alternatives --install /usr/local/bin/python python /usr/bin/python3; \ + fi; \ wget --quiet -O rustup.sh https://sh.rustup.rs && \ chmod +x ./rustup.sh && \ ./rustup.sh -y --profile minimal @@ -86,8 +94,12 @@ RUN apt-get update && \ clang \ llvm \ lld \ - gcc-multilib \ && \ + arch="$(dpkg --print-architecture)" && arch="${arch##*-}"; \ + if [ "${arch}" = 'amd64' ]; then \ + apt-get install -y --no-install-recommends \ + gcc-multilib; \ + fi; \ apt-get clean && \ rm -rf /var/lib/apt/lists/* From b193b3b9e8e8f7f7d451ac81c140a052357d4e93 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Tue, 1 Oct 2024 15:41:25 +0200 Subject: [PATCH 3/6] fix(docker): make coreboot container multi-arch Signed-off-by: AtomicFS --- docker/coreboot/Dockerfile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docker/coreboot/Dockerfile b/docker/coreboot/Dockerfile index 45f1c14e..56c3e974 100644 --- a/docker/coreboot/Dockerfile +++ b/docker/coreboot/Dockerfile @@ -19,7 +19,8 @@ ENV TOOLSDIR=/tools # Use coreboot mirror ENV BUILDGCC_OPTIONS=-m -RUN apt-get update && \ +RUN arch="$(dpkg --print-architecture)" && arch="${arch##*-}"; \ + apt-get update && \ apt-get install -y --no-install-recommends \ acpica-tools \ bc \ @@ -31,7 +32,6 @@ RUN apt-get update && \ git \ gnat \ imagemagick \ - iucode-tool \ libelf-dev \ libncurses5-dev \ libnss3-dev \ @@ -48,6 +48,10 @@ RUN apt-get update && \ uuid-dev \ zlib1g-dev \ && \ + if [ "${arch}" = 'amd64' ]; then \ + apt-get install -y --no-install-recommends \ + iucode-tool; \ + fi; \ apt-get install -y --no-install-recommends \ less \ nano \ From bf2e003e7bf569a5db4f5f2f2d84501aab839760 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Wed, 25 Sep 2024 18:52:00 +0200 Subject: [PATCH 4/6] feat(docker): make containers multi-arch Signed-off-by: AtomicFS --- .dagger-ci/daggerci/lib/orchestrator.py | 141 +++++++++++++----- .../daggerci/tests/test_orchestrator.py | 20 ++- 2 files changed, 119 insertions(+), 42 deletions(-) diff --git a/.dagger-ci/daggerci/lib/orchestrator.py b/.dagger-ci/daggerci/lib/orchestrator.py index af53e350..c4d3b0d1 100644 --- a/.dagger-ci/daggerci/lib/orchestrator.py +++ b/.dagger-ci/daggerci/lib/orchestrator.py @@ -8,6 +8,7 @@ import datetime import logging import os +import platform import re import sys from typing import Any @@ -41,6 +42,28 @@ class ContainerTestFailed(Exception): """ +def get_current_platform() -> str: + """ + Get platform string of current machine + Examples: 'linux/amd64' or 'windows/arm64' + """ + # Figure out Operating System, aka Platform + # Docs: https://docs.python.org/3/library/sys.html#sys.platform + current_platform = sys.platform.lower() + if current_platform in ("win32", "cygwin"): + current_platform = "windows" + + # Figure out CPU + # Docs: https://docs.python.org/3/library/platform.html#platform.machine + current_arch = platform.machine().lower() + if current_arch == "x86_64": + current_arch = "amd64" + if current_arch == "aarch64": + current_arch = "arm64" + + return f"{current_platform}/{current_arch}" + + class Orchestrator: """ The main class to abstract all actions @@ -133,6 +156,7 @@ def __init__( self.tags = [ self.tag_sha_short, re.sub(r"[\/-]", r"_", self.tag_branch), + get_current_platform(), # self.tag_timestamp, ] if self.tag_tag is not None: @@ -233,25 +257,15 @@ async def __build_test_publish__( # ======= # BUILD logging.info("%s/%s: BUILDING", top_element, dockerfile) - try: - built_docker = await self.__build__( - client=client, - dockerfile_dir=dockerfile_dir, - dockerfile_args=dockerfile_args, - ) - except dagger.ExecError as exc: - logging.error("Dagger execution error") - self.results.add(top_element, dockerfile, "build", False, exc.message) - return - except dagger.QueryError as exc: - logging.error( - "Dagger query error, try this: https://archive.docs.dagger.io/0.9/235290/troubleshooting/#dagger-pipeline-is-unable-to-resolve-host-names-after-network-configuration-changes" - ) - self.results.add( - top_element, dockerfile, "build", False, exc.debug_query() - ) # type: ignore [no-untyped-call] + variants = await self.__build__( + client=client, + dockerfile=dockerfile, + dockerfile_dir=dockerfile_dir, + dockerfile_args=dockerfile_args, + top_element=top_element, + ) + if not variants: return - self.results.add(top_element, dockerfile, "build") # add container specific labels into self.labels self.labels["org.opencontainers.image.description"] = ( @@ -262,22 +276,25 @@ async def __build_test_publish__( ) # add labels to the container - for name, val in self.labels.items(): - built_docker = await built_docker.with_label(name=name, value=val) + for built_docker in variants: + for name, val in self.labels.items(): + built_docker = await built_docker.with_label(name=name, value=val) logging.info("Docker container labels:") - for label in await built_docker.labels(): - logging.info("label: %s = %s", await label.name(), await label.value()) + for built_docker in variants: + for label in await built_docker.labels(): + logging.info("label: %s = %s", await label.name(), await label.value()) # ======= # TEST logging.info("%s/%s: TESTING", top_element, dockerfile) try: - await self.__test__( - client=client, - test_container=built_docker, - test_container_name=dockerfile, - ) + for built_docker in variants: + await self.__test__( + client=client, + test_container=built_docker, + test_container_name=dockerfile, + ) except ContainerTestFailed: self.results.add(top_element, dockerfile, "test", False) return @@ -294,7 +311,7 @@ async def __build_test_publish__( # pylint: enable=attribute-defined-outside-init try: await self.__publish__( - container=built_docker, + variants=variants, dockerfile=dockerfile, top_element=top_element, ) @@ -307,18 +324,63 @@ async def __build_test_publish__( self.results.add(top_element, dockerfile, "publish", False, "skip") async def __build__( - self, client: dagger.Client, dockerfile_dir: str, dockerfile_args: list[Any] - ) -> dagger.Container: + self, + client: dagger.Client, + dockerfile: str, + dockerfile_dir: str, + dockerfile_args: list[Any], + top_element: str, + ) -> list[dagger.Container]: # dockerfile_args: list[dagger.api.gen.BuildArg]) -> dagger.Container: # For some reason I get # "AttributeError: module 'dagger' has no attribute 'api'" + + # pylint: disable=too-many-arguments """ Does the actual building of docker container """ + + # Initially I wanted to use this setup to build all wanted platforms, but unfortunately + # there are issues with native emulation when building tool-chains for coreboot and edk2. + # For that reason we cannot build the multi-arch container as shown in cookbook + # https://docs.dagger.io/cookbook/#build-multi-arch-image + # :( + + platforms = [ + get_current_platform(), + ] context_dir = client.host().directory(dockerfile_dir) - return await context_dir.docker_build( # type: ignore [no-any-return] - build_args=dockerfile_args - ) + platform_variants = [] + + for p in platforms: + try: + logging.info("** building platform: %s", p) + container = await context_dir.docker_build( # type: ignore [no-any-return] + platform=dagger.Platform(p), + build_args=dockerfile_args, + ) + platform_variants.append(container) + except dagger.ExecError as exc: + logging.error("Dagger execution error") + self.results.add( + top_element, dockerfile, f"build {p}", False, exc.message + ) + return [] + except dagger.QueryError as exc: + logging.error( + "Dagger query error, try this: https://archive.docs.dagger.io/0.9/235290/troubleshooting/#dagger-pipeline-is-unable-to-resolve-host-names-after-network-configuration-changes" + ) + self.results.add( + top_element, + dockerfile, + f"build {p}", + False, + exc.debug_query(), + ) # type: ignore [no-untyped-call] + return [] + self.results.add(top_element, dockerfile, f"build {p}") + + return platform_variants async def __test__( self, @@ -384,18 +446,27 @@ async def __test__( # No return here, so the execution continues normally async def __publish__( - self, container: dagger.Container, dockerfile: str, top_element: str + self, + variants: list[dagger.Container], + dockerfile: str, + top_element: str, ) -> None: """ Publish the built container to container registry """ + + # Get the first container and use it as base + container = variants.pop(1) + for tag in self.tags: image_ref = await container.with_registry_auth( address=str(self.container_registry), username=str(self.container_registry_username), secret=self.secret_token, ).publish( - f"{self.container_registry}/{self.organization}/{self.project_name}/{dockerfile}:{tag}" + f"{self.container_registry}/{self.organization}/{self.project_name}/{dockerfile}:{tag}", + # add remaining containers: + platform_variants=variants, ) logging.info( "%s/%s: Published image to: %s", top_element, dockerfile, image_ref diff --git a/.dagger-ci/daggerci/tests/test_orchestrator.py b/.dagger-ci/daggerci/tests/test_orchestrator.py index 0fc9a4a4..0d78bad1 100644 --- a/.dagger-ci/daggerci/tests/test_orchestrator.py +++ b/.dagger-ci/daggerci/tests/test_orchestrator.py @@ -41,8 +41,14 @@ async def test__orchestrator__broken_dockerfile( result = await my_orchestrator.build_test_publish() assert "services" in result.results assert "coreboot_4.19" in result.results["services"] - assert "build" in result.results["services"]["coreboot_4.19"] - assert result.results["services"]["coreboot_4.19"]["build"] is False + + # because of multi-platform nature we have to be flexible + build_found = False + for key, _ in result.results["services"]["coreboot_4.19"].items(): + if re.match("build .*", key) and not re.match(".*_msg$", key): + build_found = True + assert result.results["services"]["coreboot_4.19"][key] is False + assert build_found @pytest.mark.slow @@ -148,7 +154,7 @@ async def test__orchestrator__multi_comprehensive_build( None, "branch1", None, - ["sha12ab", "branch1"], + ["sha12ab", "branch1", "linux/amd64"], ), ( "sha12ab", @@ -156,7 +162,7 @@ async def test__orchestrator__multi_comprehensive_build( "v1.0", "master", None, - ["sha12ab", "v1.0", "master", "latest"], + ["sha12ab", "v1.0", "master", "latest", "linux/amd64"], ), ( "sha12ab", @@ -164,7 +170,7 @@ async def test__orchestrator__multi_comprehensive_build( "v1.1.0-3-11dd3b9", "branch1", None, - ["sha12ab", "branch1"], + ["sha12ab", "branch1", "linux/amd64"], ), ( "sha12ab", @@ -172,7 +178,7 @@ async def test__orchestrator__multi_comprehensive_build( "v1.1.0-3-11dd3b9", "branch1", "34", - ["sha12ab", "branch1", "pull_request_34"], + ["sha12ab", "branch1", "pull_request_34", "linux/amd64"], ), ( "sha12ab", @@ -180,7 +186,7 @@ async def test__orchestrator__multi_comprehensive_build( "v1.1.0-3-11dd3b9", "feature/new-stuff", "34", - ["sha12ab", "feature_new_stuff", "pull_request_34"], + ["sha12ab", "feature_new_stuff", "pull_request_34", "linux/amd64"], ), ], ) From d32799f502a387aa1979b87541bbf08f83d4530e Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Mon, 7 Oct 2024 17:06:43 +0200 Subject: [PATCH 5/6] style: cosmetic change in edk2 test script Signed-off-by: AtomicFS --- tests/test_edk2.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_edk2.sh b/tests/test_edk2.sh index ef2359ff..1095beae 100755 --- a/tests/test_edk2.sh +++ b/tests/test_edk2.sh @@ -56,8 +56,8 @@ if [ "${VERIFICATION_TEST_EDK2_VERSION}" == "UDK2017" ]; then else # GCC5 is deprecated since edk2-stable202305 # For more information see https://github.com/9elements/firmware-action/issues/340 - CURRENT_VERSION=$( echo "${VERIFICATION_TEST_EDK2_VERSION}" | tr -cd '0-9' ) - if [ "${CURRENT_VERSION}" -ge "$( echo 'edk2-stable202305' | tr -cd '0-9' )" ]; then + CURRENT_VERSION=$(echo "${VERIFICATION_TEST_EDK2_VERSION}" | tr -cd '0-9') + if [ "${CURRENT_VERSION}" -ge "$(echo 'edk2-stable202305' | tr -cd '0-9')" ]; then echo "edk2-stable202305 or newer" build -D BOOTLOADER=COREBOOT -a IA32 -a X64 -t GCC -b DEBUG -p "${PAYLOAD}" -D BUILD_ARCH=X64 else From 2c343be093c12862f8e0b65ea4d32280b93d7c94 Mon Sep 17 00:00:00 2001 From: AtomicFS Date: Mon, 7 Oct 2024 18:08:17 +0200 Subject: [PATCH 6/6] ci(docker): make multi-arch containers Signed-off-by: AtomicFS --- .github/workflows/docker-build-and-test.yml | 45 ++++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-build-and-test.yml b/.github/workflows/docker-build-and-test.yml index 6872acce..b085c57d 100644 --- a/.github/workflows/docker-build-and-test.yml +++ b/.github/workflows/docker-build-and-test.yml @@ -31,11 +31,18 @@ permissions: jobs: build: - name: build_test_publish - runs-on: ubuntu-latest + name: build_${{ matrix.dockerfile }}_${{ matrix.os }} + runs-on: + group: ubuntu-runners + labels: [latest, 4core, ${{ matrix.arch }} ] timeout-minutes: 120 strategy: matrix: + arch: + [ + 'amd64', + 'arm64' + ] dockerfile: [ 'coreboot_4.19', @@ -123,3 +130,37 @@ jobs: GITHUB_REGISTRY: ${{ env.REGISTRY }} GITHUB_ACTOR: ${{ github.actor }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + merge-multi-arch: + name: merge_multiarch + runs-on: ubuntu-latest + strategy: + matrix: + dockerfile: + [ + 'coreboot_4.19', + 'coreboot_4.20.1', + 'coreboot_4.21', + 'coreboot_4.22.01', + 'coreboot_24.02', + 'coreboot_24.02.01', + 'coreboot_24.05', + 'edk2-stable202008', + 'edk2-stable202105', + 'edk2-stable202111', + 'edk2-stable202205', + 'edk2-stable202208', + 'edk2-stable202211', + 'edk2-stable202408', + 'linux_6.1.45', + 'linux_6.1.111', + 'linux_6.6.52', + 'linux_6.9.9', + 'linux_6.11', + 'udk2017', + 'uroot_0.14.0' + ] + needs: ['build'] + steps: + - run: | + echo "${{ matrix.dockerfile}}"