Skip to content

Commit

Permalink
Allow multiple tags for container-image
Browse files Browse the repository at this point in the history
  • Loading branch information
glefloch committed May 11, 2020
1 parent 8fd19b5 commit b5ccb8d
Show file tree
Hide file tree
Showing 17 changed files with 426 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
Expand Down Expand Up @@ -71,9 +73,11 @@ public void dockerBuildFromJar(DockerConfig dockerConfig,
log.info("Building docker image for jar.");

String image = containerImage.getImage();
List<String> additionalImageTags = containerImage.getAdditionalImageTags();

ImageIdReader reader = new ImageIdReader();
createContainerImage(containerImageConfig, dockerConfig, image, out, reader, false, pushRequest.isPresent());
createContainerImage(containerImageConfig, dockerConfig, image, additionalImageTags, out, reader, false,
pushRequest.isPresent());

artifactResultProducer.produce(new ArtifactResultBuildItem(null, "jar-container", Collections.emptyMap()));
}
Expand Down Expand Up @@ -106,13 +110,16 @@ public void dockerBuildFromNativeImage(DockerConfig dockerConfig,
log.info("Starting docker image build");

String image = containerImage.getImage();
List<String> additionalImageTags = containerImage.getAdditionalImageTags();

ImageIdReader reader = new ImageIdReader();
createContainerImage(containerImageConfig, dockerConfig, image, out, reader, true, pushRequest.isPresent());
createContainerImage(containerImageConfig, dockerConfig, image, additionalImageTags, out, reader, true,
pushRequest.isPresent());
artifactResultProducer.produce(new ArtifactResultBuildItem(null, "native-container", Collections.emptyMap()));
}

private void createContainerImage(ContainerImageConfig containerImageConfig, DockerConfig dockerConfig, String image,
List<String> additionalImageTags,
OutputTargetBuildItem out, ImageIdReader reader, boolean forNative, boolean pushRequested) {

DockerfilePaths dockerfilePaths = getDockerfilePaths(dockerConfig, forNative, out);
Expand All @@ -125,6 +132,10 @@ private void createContainerImage(ContainerImageConfig containerImageConfig, Doc

log.infof("Built container image %s (%s)\n", image, reader.getImageId());

if (!additionalImageTags.isEmpty()) {
createAdditionalTags(image, additionalImageTags);
}

if (pushRequested || containerImageConfig.push) {
String registry = "docker.io";
if (!containerImageConfig.registry.isPresent()) {
Expand All @@ -140,15 +151,34 @@ private void createContainerImage(ContainerImageConfig containerImageConfig, Doc
throw dockerException(new String[] { "-u", containerImageConfig.username.get(), "-p", "********" });
}
}
String[] pushArgs = { "push", image };
boolean pushSuccessful = ExecUtil.exec("docker", pushArgs);
if (!pushSuccessful) {
throw dockerException(pushArgs);

List<String> imagesToPush = new ArrayList<>(additionalImageTags);
imagesToPush.add(image);
for (String imageToPush : imagesToPush) {
pushImage(imageToPush);
}
}
}

private void createAdditionalTags(String image, List<String> additionalImageTags) {
for (String additionalTag : additionalImageTags) {
String[] tagArgs = { "tag", image, additionalTag };
boolean tagSuccessful = ExecUtil.exec("docker", tagArgs);
if (!tagSuccessful) {
throw dockerException(tagArgs);
}
log.info("Successfully pushed docker image " + image);
}
}

private void pushImage(String image) {
String[] pushArgs = { "push", image };
boolean pushSuccessful = ExecUtil.exec("docker", pushArgs);
if (!pushSuccessful) {
throw dockerException(pushArgs);
}
log.info("Successfully pushed docker image " + image);
}

private RuntimeException dockerException(String[] dockerArgs) {
return new RuntimeException(
"Execution of 'docker " + String.join(" ", dockerArgs) + "' failed. See docker output for more details");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import io.quarkus.container.image.deployment.ContainerImageConfig;
import io.quarkus.container.image.deployment.util.NativeBinaryUtil;
import io.quarkus.container.spi.ContainerImageBuildRequestBuildItem;
import io.quarkus.container.spi.ContainerImageInfoBuildItem;
import io.quarkus.container.spi.ContainerImageLabelBuildItem;
import io.quarkus.container.spi.ContainerImagePushRequestBuildItem;
import io.quarkus.deployment.Capabilities;
Expand Down Expand Up @@ -66,6 +67,7 @@ public CapabilityBuildItem capability() {

@BuildStep(onlyIf = { IsNormal.class, JibBuild.class }, onlyIfNot = NativeBuild.class)
public void buildFromJar(ContainerImageConfig containerImageConfig, JibConfig jibConfig,
ContainerImageInfoBuildItem containerImage,
JarBuildItem sourceJar,
MainClassBuildItem mainClass,
OutputTargetBuildItem outputTarget, ApplicationInfoBuildItem applicationInfo,
Expand All @@ -81,14 +83,15 @@ public void buildFromJar(ContainerImageConfig containerImageConfig, JibConfig ji

JibContainerBuilder jibContainerBuilder = createContainerBuilderFromJar(jibConfig,
sourceJar, outputTarget, mainClass, containerImageLabels);
JibContainer container = containerize(applicationInfo, containerImageConfig, jibContainerBuilder,
containerize(applicationInfo, containerImageConfig, containerImage, jibContainerBuilder,
pushRequest.isPresent());

artifactResultProducer.produce(new ArtifactResultBuildItem(null, "jar-container", Collections.emptyMap()));
}

@BuildStep(onlyIf = { IsNormal.class, JibBuild.class, NativeBuild.class })
public void buildFromNative(ContainerImageConfig containerImageConfig, JibConfig jibConfig,
ContainerImageInfoBuildItem containerImage,
NativeImageBuildItem nativeImage,
ApplicationInfoBuildItem applicationInfo,
Optional<ContainerImageBuildRequestBuildItem> buildRequest,
Expand All @@ -109,14 +112,18 @@ public void buildFromNative(ContainerImageConfig containerImageConfig, JibConfig
JibContainerBuilder jibContainerBuilder = createContainerBuilderFromNative(containerImageConfig, jibConfig,
nativeImage, containerImageLabels);

containerize(applicationInfo, containerImageConfig, jibContainerBuilder, pushRequest.isPresent());
containerize(applicationInfo, containerImageConfig, containerImage, jibContainerBuilder,
pushRequest.isPresent());

artifactResultProducer.produce(new ArtifactResultBuildItem(null, "native-container", Collections.emptyMap()));
}

private JibContainer containerize(ApplicationInfoBuildItem applicationInfo, ContainerImageConfig containerImageConfig,
JibContainerBuilder jibContainerBuilder, boolean pushRequested) {
Containerizer containerizer = createContainerizer(containerImageConfig, applicationInfo, pushRequested);
ContainerImageInfoBuildItem containerImage, JibContainerBuilder jibContainerBuilder, boolean pushRequested) {
Containerizer containerizer = createContainerizer(containerImageConfig, containerImage, applicationInfo, pushRequested);
for (String additionalTag : containerImage.getAdditionalTags()) {
containerizer.withAdditionalTag(additionalTag);
}
try {
log.info("Starting container image build");
JibContainer container = jibContainerBuilder.containerize(containerizer);
Expand All @@ -131,9 +138,17 @@ private JibContainer containerize(ApplicationInfoBuildItem applicationInfo, Cont
}

private Containerizer createContainerizer(ContainerImageConfig containerImageConfig,
ContainerImageInfoBuildItem containerImage,
ApplicationInfoBuildItem applicationInfo, boolean pushRequested) {
Containerizer containerizer;
ImageReference imageReference = getImageReference(containerImageConfig, applicationInfo);
ImageReference imageReference = getImageReference(containerImageConfig, containerImage, applicationInfo);

for (String additionalTag : containerImage.getAdditionalTags()) {
if (!ImageReference.isValidTag(additionalTag)) {
throw new IllegalArgumentException(
"The supplied container-image additional tag '" + additionalTag + "' is invalid");
}
}

if (pushRequested || containerImageConfig.push) {
if (!containerImageConfig.registry.isPresent()) {
Expand Down Expand Up @@ -181,6 +196,7 @@ private Logger.Level toJBossLoggingLevel(LogEvent.Level level) {
}

private ImageReference getImageReference(ContainerImageConfig containerImageConfig,
ContainerImageInfoBuildItem containerImage,
ApplicationInfoBuildItem applicationInfo) {

String registry = containerImageConfig.registry.orElse(null);
Expand All @@ -194,8 +210,8 @@ private ImageReference getImageReference(ContainerImageConfig containerImageConf
throw new IllegalArgumentException("The supplied container-image repository '" + repository + "' is invalid");
}

String tag = containerImageConfig.tag.orElse(applicationInfo.getVersion());
if (tag != null && !ImageReference.isValidTag(tag)) {
final String tag = containerImage.getTag();
if (!ImageReference.isValidTag(tag)) {
throw new IllegalArgumentException("The supplied container-image tag '" + tag + "' is invalid");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ public void s2iBuildFromJar(S2iConfig s2iConfig, ContainerImageConfig containerI
String namespace = Optional.ofNullable(kubernetesClient.getClient().getNamespace()).orElse("default");
LOG.info("Performing s2i binary build with jar on server: " + kubernetesClient.getClient().getMasterUrl()
+ " in namespace:" + namespace + ".");
String image = containerImage.getImage();

createContainerImage(kubernetesClient, openshiftYml.get(), s2iConfig, out.getOutputDirectory(), jar.getPath(),
out.getOutputDirectory().resolve("lib"));
Expand All @@ -220,8 +219,6 @@ public void s2iBuildFromNative(S2iConfig s2iConfig, ContainerImageConfig contain
LOG.info("Performing s2i binary build with native image on server: " + kubernetesClient.getClient().getMasterUrl()
+ " in namespace:" + namespace + ".");

String image = containerImage.getImage();

GeneratedFileSystemResourceBuildItem openshiftYml = generatedResources
.stream()
.filter(r -> r.getName().endsWith("kubernetes/openshift.yml"))
Expand Down Expand Up @@ -269,7 +266,7 @@ public static void createContainerImage(KubernetesClientBuildItem kubernetesClie
* Apply the s2i resources and wait until ImageStreamTags are created.
*
* @param client the client instance
* @param the resources to apply
* @param buildResources resources to apply
*/
private static void applyS2iResources(OpenShiftClient client, List<HasMetadata> buildResources) {
// Apply build resource requirements
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.container.image.deployment;

import java.util.List;
import java.util.Optional;

import io.quarkus.runtime.annotations.ConfigItem;
Expand All @@ -26,6 +27,12 @@ public class ContainerImageConfig {
@ConfigItem(defaultValue = "${quarkus.application.version:latest}")
public Optional<String> tag;

/**
* Additional tags of the container image.
*/
@ConfigItem
public Optional<List<String>> additionalTags;

/**
* The container registry to use
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.quarkus.container.image.deployment;

import java.util.Collections;

import io.quarkus.container.spi.ContainerImageInfoBuildItem;
import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.annotations.BuildStep;
Expand All @@ -16,7 +18,8 @@ public ContainerImageInfoBuildItem publishImageInfo(ApplicationInfoBuildItem app
return new ContainerImageInfoBuildItem(containerImageConfig.registry,
containerImageConfig.getEffectiveGroup(),
containerImageConfig.name.orElse(app.getName()),
containerImageConfig.tag.orElse(app.getVersion()));
containerImageConfig.tag.orElse(app.getVersion()),
containerImageConfig.additionalTags.orElse(Collections.emptyList()));
}

private void ensureSingleContainerImageExtension(Capabilities capabilities) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@

package io.quarkus.container.spi;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import io.quarkus.builder.item.SimpleBuildItem;

Expand All @@ -15,24 +19,41 @@ public final class ContainerImageInfoBuildItem extends SimpleBuildItem {
*/
public final Optional<String> registry;

private final String image;
private final String imagePrefix;

public ContainerImageInfoBuildItem(Optional<String> registry, Optional<String> group, String name, String tag) {
private final String tag;

private final Set<String> additionalTags;

public ContainerImageInfoBuildItem(Optional<String> registry, Optional<String> group, String name, String tag,
List<String> additionalTags) {
this.registry = registry;

StringBuilder sb = new StringBuilder();
registry.ifPresent(r -> sb.append(r).append(SLASH));
group.ifPresent(s -> sb.append(s).append(SLASH));

sb.append(name).append(COLN).append(tag);
this.image = sb.toString();
this.imagePrefix = sb.append(name).toString();
this.tag = tag;
this.additionalTags = new HashSet<>(additionalTags);
}

public Optional<String> getRegistry() {
return registry;
}

public String getImage() {
return image;
return imagePrefix + COLN + tag;
}

public String getTag() {
return tag;
}

public List<String> getAdditionalImageTags() {
return getAdditionalTags().stream().map(tag -> imagePrefix + COLN + tag).collect(Collectors.toList());
}

public Set<String> getAdditionalTags() {
return additionalTags;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
invoker.goals=clean package -Dquarkus.container-image.build=true
Loading

0 comments on commit b5ccb8d

Please sign in to comment.