From 982897e8a6fcbe61f6a1fc52d8bad2c93de22159 Mon Sep 17 00:00:00 2001 From: mpeddada1 Date: Thu, 6 Jun 2024 21:53:48 +0000 Subject: [PATCH] fix: allow pushing images with different arch/os to docker daemon --- .../tools/jib/api/JibIntegrationTest.java | 24 +++++------ .../tools/jib/builder/steps/StepsRunner.java | 28 ++++++------- .../jib/builder/steps/StepsRunnerTest.java | 41 +++++++++++++++---- 3 files changed, 56 insertions(+), 37 deletions(-) diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/JibIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/JibIntegrationTest.java index 4e49d1e12d..2f60763dc5 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/JibIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/api/JibIntegrationTest.java @@ -343,13 +343,9 @@ public void testBasicMultiPlatform_toDockerDaemon() } @Test - public void testBasicMultiPlatform_toDockerDaemon_noMatchingImage() { - ExecutionException exception = - assertThrows( - ExecutionException.class, - () -> - Jib.from( - RegistryImage.named( + public void testBasicMultiPlatform_toDockerDaemon_pickFirstPlatformWhenNoMatchingImage() throws IOException, InterruptedException, InvalidImageReferenceException, CacheDirectoryCreationException, ExecutionException, RegistryException { + Jib.from( + RegistryImage.named( "busybox@sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977")) .setPlatforms( ImmutableSet.of( @@ -359,11 +355,15 @@ public void testBasicMultiPlatform_toDockerDaemon_noMatchingImage() { Containerizer.to( DockerDaemonImage.named( dockerHost + ":5000/docker-daemon-multi-platform")) - .setAllowInsecureRegistries(true))); - assertThat(exception) - .hasCauseThat() - .hasMessageThat() - .startsWith("The configured platforms don't match the Docker Engine's OS and architecture"); + .setAllowInsecureRegistries(true)); + String os = + new Command("docker", "inspect", dockerHost + ":5000/docker-daemon-multi-platform", "--format", "{{.Os}}") + .run().replace("\n", ""); + String architecture = + new Command("docker", "inspect", dockerHost + ":5000/docker-daemon-multi-platform", "--format", "{{.Architecture}}") + .run().replace("\n", ""); + assertThat(os).isEqualTo("linux"); + assertThat(architecture).isEqualTo("s390x"); } @Test diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/StepsRunner.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/StepsRunner.java index be760a13eb..4c3e8adac2 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/StepsRunner.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/StepsRunner.java @@ -624,14 +624,9 @@ private void loadDocker( DockerInfoDetails dockerInfoDetails = dockerClient.info(); String osType = dockerInfoDetails.getOsType(); String architecture = normalizeArchitecture(dockerInfoDetails.getArchitecture()); - Optional builtImage = fetchBuiltImageForLocalBuild(osType, architecture); - Preconditions.checkState( - builtImage.isPresent(), - String.format( - "The configured platforms don't match the Docker Engine's OS and architecture (%s/%s)", - osType, architecture)); + Image builtImage = fetchBuiltImageForLocalBuild(osType, architecture); return new LoadDockerStep( - buildContext, progressDispatcherFactory, dockerClient, builtImage.get()) + buildContext, progressDispatcherFactory, dockerClient, builtImage) .call(); }); } @@ -669,21 +664,22 @@ String normalizeArchitecture(String architecture) { } @VisibleForTesting - Optional fetchBuiltImageForLocalBuild(String osType, String architecture) + Image fetchBuiltImageForLocalBuild(String osType, String architecture) throws InterruptedException, ExecutionException { if (results.baseImagesAndBuiltImages.get().size() > 1) { LOGGER.warning( String.format( - "Detected multi-platform configuration, only building the one that matches the local Docker Engine's os and architecture (%s/%s)", + "Detected multi-platform configuration, only building the one that matches the local Docker Engine's os and architecture (%s/%s) or " + + "the first platform specified", osType, architecture)); - } - for (Map.Entry> imageEntry : - results.baseImagesAndBuiltImages.get().entrySet()) { - Image image = imageEntry.getValue().get(); - if (image.getArchitecture().equals(architecture) && image.getOs().equals(osType)) { - return Optional.of(image); + for (Map.Entry> imageEntry : + results.baseImagesAndBuiltImages.get().entrySet()) { + Image image = imageEntry.getValue().get(); + if (image.getArchitecture().equals(architecture) && image.getOs().equals(osType)) { + return image; + } } } - return Optional.empty(); + return results.baseImagesAndBuiltImages.get().values().iterator().next().get(); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/StepsRunnerTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/StepsRunnerTest.java index 9436c7df4a..4e854afa92 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/StepsRunnerTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/StepsRunnerTest.java @@ -203,14 +203,14 @@ public void testFetchBuildImageForLocalBuild_matchingOsAndArch() Futures.immediateFuture(builtAmd64AndWindowsImage)))); stepsRunner.buildImages(progressDispatcherFactory); - Optional expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("windows", "amd64"); + Image expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("windows", "amd64"); - assertThat(expectedImage.get().getOs()).isEqualTo("windows"); - assertThat(expectedImage.get().getArchitecture()).isEqualTo("amd64"); + assertThat(expectedImage.getOs()).isEqualTo("windows"); + assertThat(expectedImage.getArchitecture()).isEqualTo("amd64"); } @Test - public void testFetchBuildImageForLocalBuild_differentOs() + public void testFetchBuildImageForLocalBuild_differentOs_buildImageForFirstPlatform() throws ExecutionException, InterruptedException { when(builtArm64AndLinuxImage.getArchitecture()).thenReturn("arm64"); when(builtArm64AndLinuxImage.getOs()).thenReturn("linux"); @@ -225,13 +225,15 @@ public void testFetchBuildImageForLocalBuild_differentOs() Futures.immediateFuture(builtAmd64AndWindowsImage)))); stepsRunner.buildImages(progressDispatcherFactory); - Optional expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("os", "arm64"); + Image expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("os", "arm64"); + + assertThat(expectedImage.getOs()).isEqualTo("linux"); + assertThat(expectedImage.getArchitecture()).isEqualTo("arm64"); - assertThat(expectedImage.isPresent()).isFalse(); } @Test - public void testFetchBuildImageForLocalBuild_differentArch() + public void testFetchBuildImageForLocalBuild_differentArch_buildImageForFirstPlatform() throws ExecutionException, InterruptedException { when(builtArm64AndLinuxImage.getArchitecture()).thenReturn("arm64"); when(builtAmd64AndWindowsImage.getArchitecture()).thenReturn("amd64"); @@ -245,9 +247,30 @@ public void testFetchBuildImageForLocalBuild_differentArch() Futures.immediateFuture(builtAmd64AndWindowsImage)))); stepsRunner.buildImages(progressDispatcherFactory); - Optional expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("linux", "arch"); + Image expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("linux", "arch"); + + assertThat(expectedImage.getArchitecture()).isEqualTo("arm64"); + } + + @Test + public void testFetchBuildImageForLocalBuild_singleImage_imagePlatformDifferentFromDockerEnv() + throws ExecutionException, InterruptedException { + when(builtArm64AndLinuxImage.getArchitecture()).thenReturn("arm64"); + when(builtArm64AndLinuxImage.getOs()).thenReturn("linux"); + + when(builtAmd64AndWindowsImage.getOs()).thenReturn("linux"); + when(executorService.submit(Mockito.any(Callable.class))) + .thenReturn( + Futures.immediateFuture( + ImmutableMap.of( + baseImage1, + Futures.immediateFuture(builtArm64AndLinuxImage)))); + stepsRunner.buildImages(progressDispatcherFactory); + + Image expectedImage = stepsRunner.fetchBuiltImageForLocalBuild("linux", "amd64"); - assertThat(expectedImage.isPresent()).isFalse(); + assertThat(expectedImage.getOs()).isEqualTo("linux"); + assertThat(expectedImage.getArchitecture()).isEqualTo("arm64"); } @Test