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

fix: multi-arch build should use provided repository #1629

Merged
merged 1 commit into from
Jan 12, 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
1 change: 1 addition & 0 deletions doc/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# ChangeLog
* **0.41-SNAPSHOT** :
- multi-arch build should use provided repository ([1597](https://github.com/fabric8io/docker-maven-plugin/issues/1597)) @merikan

* **0.40.3** (2022-12-18):
- image/squash option is taken into account when using buildx ([1605](https://github.com/fabric8io/docker-maven-plugin/pull/1605)) @kevinleturc
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/fabric8/maven/docker/BuildMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private void proceedWithDockerBuild(ServiceHub hub, BuildService.BuildContext bu
File buildArchiveFile = buildService.buildArchive(imageConfig, buildContext, resolveBuildArchiveParameter());
if (Boolean.FALSE.equals(shallBuildArchiveOnly())) {
if (imageConfig.isBuildX()) {
hub.getBuildXService().build(createProjectPaths(), imageConfig, getAuthConfig(imageConfig), buildArchiveFile);
hub.getBuildXService().build(createProjectPaths(), imageConfig, null, getAuthConfig(imageConfig), buildArchiveFile);
} else {
buildService.buildImage(imageConfig, pullManager, buildContext, buildArchiveFile);
if (!skipTag) {
Expand Down
28 changes: 14 additions & 14 deletions src/main/java/io/fabric8/maven/docker/service/BuildXService.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ public BuildXService(DockerAccess dockerAccess, DockerAssemblyManager dockerAsse
this.exec = exec;
}

public void build(ProjectPaths projectPaths, ImageConfiguration imageConfig, AuthConfig authConfig, File buildArchive) throws MojoExecutionException {
useBuilder(projectPaths, imageConfig, authConfig, buildArchive, this::buildAndLoadNativePlatform);
public void build(ProjectPaths projectPaths, ImageConfiguration imageConfig, String configuredRegistry, AuthConfig authConfig, File buildArchive) throws MojoExecutionException {
useBuilder(projectPaths, imageConfig, configuredRegistry, authConfig, buildArchive, this::buildAndLoadNativePlatform);
}

public void push(ProjectPaths projectPaths, ImageConfiguration imageConfig, AuthConfig authConfig) throws MojoExecutionException {
public void push(ProjectPaths projectPaths, ImageConfiguration imageConfig, String configuredRegistry, AuthConfig authConfig) throws MojoExecutionException {
BuildDirs buildDirs = new BuildDirs(projectPaths, imageConfig.getName());
File archive = new File(buildDirs.getTemporaryRootDirectory(), "docker-build.tar");
useBuilder(projectPaths, imageConfig, authConfig, archive, this::pushMultiPlatform);
useBuilder(projectPaths, imageConfig, configuredRegistry, authConfig, archive, this::pushMultiPlatform);
}

private <C> void useBuilder(ProjectPaths projectPaths, ImageConfiguration imageConfig, AuthConfig authConfig, C context, Builder<C> builder) throws MojoExecutionException {
private <C> void useBuilder(ProjectPaths projectPaths, ImageConfiguration imageConfig, String configuredRegistry, AuthConfig authConfig, C context, Builder<C> builder) throws MojoExecutionException {
BuildDirs buildDirs = new BuildDirs(projectPaths, imageConfig.getName());

Path configPath = getDockerStateDir(imageConfig.getBuildConfiguration(), buildDirs);
Expand All @@ -68,7 +68,7 @@ private <C> void useBuilder(ProjectPaths projectPaths, ImageConfiguration imageC
Path configJson = configPath.resolve("config.json");
try {
createConfigJson(configJson, authConfig);
builder.useBuilder(buildX, builderName, buildDirs, imageConfig, context);
builder.useBuilder(buildX, builderName, buildDirs, imageConfig, configuredRegistry, context);
} finally {
removeConfigJson(configJson);
}
Expand All @@ -92,23 +92,23 @@ private void removeConfigJson(Path configJson) {
}
}

private void buildAndLoadNativePlatform(List<String> buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, File buildArchive) throws MojoExecutionException {
private void buildAndLoadNativePlatform(List<String> buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, File buildArchive) throws MojoExecutionException {
List<String> platforms = imageConfig.getBuildConfiguration().getBuildX().getPlatforms();
// build and load the native image by re-building, image should be cached and build should be quick
String nativePlatform = dockerAccess.getNativePlatform();
if (platforms.contains(nativePlatform)) {
buildX(buildX, builderName, buildDirs, imageConfig, Collections.singletonList(nativePlatform), buildArchive, "--load");
buildX(buildX, builderName, buildDirs, imageConfig, configuredRegistry, Collections.singletonList(nativePlatform), buildArchive, "--load");
} else {
logger.info("Native platform not specified, no image built");
}
}

private void pushMultiPlatform(List<String> buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, File buildArchive) throws MojoExecutionException {
private void pushMultiPlatform(List<String> buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, File buildArchive) throws MojoExecutionException {
// build and push all images. The native platform may be re-built, image should be cached and build should be quick
buildX(buildX, builderName, buildDirs, imageConfig, imageConfig.getBuildConfiguration().getBuildX().getPlatforms(), buildArchive, "--push");
buildX(buildX, builderName, buildDirs, imageConfig, configuredRegistry, imageConfig.getBuildConfiguration().getBuildX().getPlatforms(), buildArchive, "--push");
}

private void buildX(List<String> buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, List<String> platforms, File buildArchive, String extraParam)
private void buildX(List<String> buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, List<String> platforms, File buildArchive, String extraParam)
throws MojoExecutionException {

BuildImageConfiguration buildConfiguration = imageConfig.getBuildConfiguration();
Expand All @@ -122,11 +122,11 @@ private void buildX(List<String> buildX, String builderName, BuildDirs buildDirs
cmdLine.add(String.join(",", platforms));
buildConfiguration.getTags().forEach(t -> {
cmdLine.add("--tag");
cmdLine.add(new ImageName(imageConfig.getName(), t).getFullName());
cmdLine.add(new ImageName(imageConfig.getName(), t).getFullName(configuredRegistry));
}
);
cmdLine.add("--tag");
cmdLine.add(imageConfig.getName());
cmdLine.add(new ImageName(imageConfig.getName()).getFullName(configuredRegistry));

Map<String, String> args = buildConfiguration.getArgs();
if (args != null) {
Expand Down Expand Up @@ -209,7 +209,7 @@ private String createBuilder(Path configPath, List<String> buildX, ImageConfigur
}

interface Builder<C> {
void useBuilder(List<String> buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, C context) throws MojoExecutionException;
void useBuilder(List<String> buildX, String builderName, BuildDirs buildDirs, ImageConfiguration imageConfig, String configuredRegistry, C context) throws MojoExecutionException;
}

public interface Exec {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void pushImages(ProjectPaths projectPaths, Collection<ImageConfiguration>

AuthConfig authConfig = createAuthConfig(true, imageName.getUser(), configuredRegistry, registryConfig);
if (imageConfig.isBuildX()) {
buildXService.push(projectPaths, imageConfig, authConfig);
buildXService.push(projectPaths, imageConfig, configuredRegistry, authConfig);
} else {
dockerPush(retries, skipTag, buildConfig, name, configuredRegistry, authConfig);
}
Expand Down
115 changes: 102 additions & 13 deletions src/test/java/io/fabric8/maven/docker/service/RegistryServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Map;

/**
Expand All @@ -44,6 +45,8 @@
class RegistryServiceTest {

private Exception actualException;
private String registry;
private ImageConfiguration imageConfiguration;

// pull
private String imageName;
Expand All @@ -52,15 +55,11 @@ class RegistryServiceTest {
private AutoPullMode autoPullMode;
private RegistryService registryService;
private boolean hasImage;
private String registry;
private Map<String, String> authConfig;

@TempDir
private File projectBaseDir;

// push
private ImageConfiguration imageConfiguration;

@Mock
private DockerAccess docker;

Expand Down Expand Up @@ -95,6 +94,7 @@ void setup() {
autoPullMode = null;
hasImage = false;
registry = null;
imageConfiguration = null;
}

@ParameterizedTest
Expand Down Expand Up @@ -266,14 +266,52 @@ void pushImage() throws DockerAccessException {
thenNoExceptionThrown();
}

@Test
void pushImageWithRegistry() throws DockerAccessException {
String registry = "myregistry.com";
givenAnImageConfiguration("user/test:1.0.1");
givenRegistry(registry);

whenPushImage();

thenImageHasBeenPushed();
thenRegistryWasUsedWhenPushing(registry);
thenNoExceptionThrown();
}

@Test
void pushImageWithImageRegistry() throws DockerAccessException {
String registry = "myregistry.com";
givenAnImageConfiguration(registry + "/" + "user/test:1.0.1");

whenPushImage();

thenImageHasBeenPushed();
thenRegistryWasUsedWhenPushing(registry);
thenNoExceptionThrown();
}

@Test
void pushImageWithImageConfigRegistry() throws DockerAccessException {
String registry = "myregistry.com";
givenAnImageConfiguration("user/test:1.0.1");
andImageConfigRegistry(registry);

whenPushImage();

thenImageHasBeenPushed();
thenRegistryWasUsedWhenPushing(registry);
thenNoExceptionThrown();
}

@Test
void pushBuildXImage() throws MojoExecutionException {
givenBuildxImageConfiguration("user/test:1.0.1", null, null, null);
givenCredentials("skroob", "12345");

whenPushImage();

thenBuildxImageHasBeenPushed(null, null, false);
thenBuildxImageHasBeenPushed(null, null, false, null);
thenNoExceptionThrown();
}

Expand All @@ -285,7 +323,7 @@ void pushBuildXImageWithDockerfile() throws MojoExecutionException {

whenPushImage();

thenBuildxImageHasBeenPushed(null, "Dockerfile", false);
thenBuildxImageHasBeenPushed(null, "Dockerfile", false, null);
thenNoExceptionThrown();
}

Expand All @@ -296,7 +334,7 @@ void pushBuildXImageProvidedBuilder() throws MojoExecutionException {

whenPushImage();

thenBuildxImageHasBeenPushed("provided-builder", null, false);
thenBuildxImageHasBeenPushed("provided-builder", null, false, null);
thenNoExceptionThrown();
}

Expand All @@ -307,7 +345,45 @@ void pushBuildXImageTag() throws MojoExecutionException {

whenPushImage();

thenBuildxImageHasBeenPushed(null, null, true);
thenBuildxImageHasBeenPushed(null, null, true, null);
thenNoExceptionThrown();
}

@Test
void pushBuildXImageWithRegistry() throws MojoExecutionException {
String registry = "myregistry.com";
givenBuildxImageConfiguration("user/test:1.0.1", null, null, "perri-air");
givenCredentials("King_Roland_of_Druidia", "12345");
givenRegistry(registry);

whenPushImage();

thenBuildxImageHasBeenPushed(null, null, true, registry);
thenNoExceptionThrown();
}

@Test
void pushBuildXImageWithImageRegistry() throws MojoExecutionException {
String registry = "myregistry.com";
givenBuildxImageConfiguration(registry + "/" + "user/test:1.0.1", null, null, "perri-air");
givenCredentials("King_Roland_of_Druidia", "12345");

whenPushImage();

thenBuildxImageHasBeenPushed(null, null, true, registry);
thenNoExceptionThrown();
}

@Test
void pushBuildXImageWithImageConfigRegistry() throws MojoExecutionException {
String registry = "myregistry.com";
givenBuildxImageConfiguration("user/test:1.0.1", null, null, "perri-air");
andImageConfigRegistry(registry);
givenCredentials("King_Roland_of_Druidia", "12345");

whenPushImage();

thenBuildxImageHasBeenPushed(null, null, true, registry);
thenNoExceptionThrown();
}

Expand Down Expand Up @@ -349,9 +425,13 @@ private void thenImageHasNotBeenPushed() throws DockerAccessException {
private void thenImageHasBeenPushed() throws DockerAccessException {
Mockito.verify(docker).pushImage(Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.anyInt());
}
private void thenRegistryWasUsedWhenPushing(String registry) throws DockerAccessException {
Mockito.verify(docker).pushImage(Mockito.anyString(), Mockito.any(), Mockito.eq(registry), Mockito.anyInt());
}

private void thenBuildxImageHasBeenPushed(String providedBuilder, String relativeDockerfile, boolean tag, String registry) throws MojoExecutionException {

private void thenBuildxImageHasBeenPushed(String providedBuilder, String relativeDockerfile, boolean tag) throws MojoExecutionException {
Path buildPath = projectBaseDir.toPath().resolve("target/docker").resolve("user/test/1.0.1");
Path buildPath = projectBaseDir.toPath().resolve("target/docker").resolve(imageConfiguration.getName().replace(":","/"));
String config = getOsDependentBuild(buildPath, "docker");
String buildDir = getOsDependentBuild(buildPath, "build");
String builderName = providedBuilder != null ? providedBuilder : "maven";
Expand All @@ -367,9 +447,10 @@ private void thenBuildxImageHasBeenPushed(String providedBuilder, String relativ
"build", "--progress=plain", "--builder", builderName,
"--platform", "linux/amd64,linux/arm64"));
if (tag) {
args.addAll(Arrays.asList("--tag", "user/test:perri-air"));
String tagName = imageConfiguration.getBuildConfiguration().getTags().get(0);
args.addAll(Arrays.asList("--tag", new ImageName(imageConfiguration.getName(), tagName).getFullName(registry)));
}
args.addAll(Arrays.asList("--tag", "user/test:1.0.1", "--push"));
args.addAll(Arrays.asList("--tag", new ImageName(imageConfiguration.getName()).getFullName(registry) , "--push"));

String[] cmds;
if (relativeDockerfile != null) {
Expand Down Expand Up @@ -426,7 +507,9 @@ private void whenPushImage() {
RegistryService.RegistryConfig registryConfig =
new RegistryService.RegistryConfig.Builder()
.authConfigFactory(authConfigFactory)
.authConfig(authConfig).build();
.authConfig(authConfig)
.registry(registry)
.build();
registryService.pushImages(projectPaths, Collections.singleton(imageConfiguration), 1, registryConfig, false);
} catch (Exception e) {
this.actualException = e;
Expand Down Expand Up @@ -480,6 +563,12 @@ private void givenImageNameAndBuildX(String imageName, BuildXConfiguration build
imageConfiguration = new ImageConfiguration.Builder().name(imageName).buildConfig(buildImageConfiguration).build();
}

private void andImageConfigRegistry(String registry) {
Objects.requireNonNull(imageConfiguration, "ImageConfiguration must first be set with `givenAnImage....`");
imageConfiguration.setRegistry(registry);
}


private void givenCredentials(String username, String password) throws MojoExecutionException {
authConfig.put(AuthConfig.AUTH_USERNAME, username);
authConfig.put(AuthConfig.AUTH_PASSWORD, password);
Expand Down