From e0fcb5d5ff41ad134fdbb9c3cdee7f2039a0385d Mon Sep 17 00:00:00 2001 From: Tad Cordle Date: Thu, 10 May 2018 16:32:54 -0400 Subject: [PATCH] Attach build to docker daemon functionality to maven goal (#266) --- .../tools/jib/maven/BuildDockerMojo.java | 111 +++++++++++++++++- .../tools/jib/maven/BuildDockerMojoIT.java | 72 ++++++++++++ 2 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/BuildDockerMojoIT.java diff --git a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/BuildDockerMojo.java b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/BuildDockerMojo.java index 2ee09b6690..ea074be0e8 100644 --- a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/BuildDockerMojo.java +++ b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/BuildDockerMojo.java @@ -16,17 +16,126 @@ package com.google.cloud.tools.jib.maven; +import com.google.cloud.tools.jib.builder.BuildConfiguration; +import com.google.cloud.tools.jib.builder.SourceFilesConfiguration; +import com.google.cloud.tools.jib.frontend.BuildDockerStepsRunner; +import com.google.cloud.tools.jib.frontend.BuildImageStepsExecutionException; +import com.google.cloud.tools.jib.frontend.CacheDirectoryCreationException; +import com.google.cloud.tools.jib.frontend.HelpfulSuggestions; +import com.google.cloud.tools.jib.image.ImageReference; +import com.google.cloud.tools.jib.image.InvalidImageReferenceException; +import com.google.cloud.tools.jib.registry.credentials.RegistryCredentials; +import com.google.common.base.Preconditions; +import java.nio.file.Path; +import java.nio.file.Paths; +import javax.annotation.Nullable; +import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; /** Builds a container image and exports to the default Docker daemon. */ @Mojo(name = "buildDocker", requiresDependencyResolution = ResolutionScope.RUNTIME_PLUS_SYSTEM) public class BuildDockerMojo extends JibPluginConfiguration { + /** + * Directory name for the cache. The directory will be relative to the build output directory. + * + *

TODO: Move to ProjectProperties. + */ + private static final String CACHE_DIRECTORY_NAME = "jib-cache"; + + private static final HelpfulSuggestions HELPFUL_SUGGESTIONS = + HelpfulSuggestionsProvider.get("Build image failed"); + + @Nullable + @Parameter(defaultValue = "${session}", readonly = true) + private MavenSession session; + + /** TODO: Consolidate with BuildImageMojo. */ @Override public void execute() throws MojoExecutionException, MojoFailureException { - getLog().warn("Doing maven jib:buildDocker!"); + ProjectProperties projectProperties = new ProjectProperties(getProject(), getLog()); + String inferredMainClass = projectProperties.getMainClass(getMainClass()); + + SourceFilesConfiguration sourceFilesConfiguration = + projectProperties.getSourceFilesConfiguration(); + + // Parses 'from' and 'to' into image reference. + ImageReference baseImage = getBaseImageReference(); + ImageReference targetImage = getTargetImageReference(); + + // Checks Maven settings for registry credentials. + MavenSettingsServerCredentials mavenSettingsServerCredentials = + new MavenSettingsServerCredentials(Preconditions.checkNotNull(session).getSettings()); + RegistryCredentials knownBaseRegistryCredentials = + mavenSettingsServerCredentials.retrieve(baseImage.getRegistry()); + + BuildConfiguration buildConfiguration = + BuildConfiguration.builder(new MavenBuildLogger(getLog())) + .setBaseImage(baseImage) + .setBaseImageCredentialHelperName(getBaseImageCredentialHelperName()) + .setKnownBaseRegistryCredentials(knownBaseRegistryCredentials) + .setTargetImage(targetImage) + .setMainClass(inferredMainClass) + .setJvmFlags(getJvmFlags()) + .setEnvironment(getEnvironment()) + .build(); + + // Uses a directory in the Maven build cache as the Jib cache. + Path cacheDirectory = Paths.get(getProject().getBuild().getDirectory(), CACHE_DIRECTORY_NAME); + try { + BuildDockerStepsRunner buildDockerStepsRunner = + BuildDockerStepsRunner.newRunner( + buildConfiguration, + sourceFilesConfiguration, + cacheDirectory, + getUseOnlyProjectCache()); + + getLog().info(""); + getLog().info("Building to docker daemon as " + targetImage); + getLog().info(""); + + buildDockerStepsRunner.buildDocker(HELPFUL_SUGGESTIONS); + + getLog().info(""); + getLog().info("Built image to Docker daemon as " + targetImage); + getLog().info(""); + + } catch (CacheDirectoryCreationException | BuildImageStepsExecutionException ex) { + throw new MojoExecutionException(ex.getMessage(), ex.getCause()); + } + } + + /** @return the {@link ImageReference} parsed from {@link #from}. */ + private ImageReference getBaseImageReference() throws MojoFailureException { + try { + ImageReference baseImage = ImageReference.parse(getBaseImage()); + + if (baseImage.usesDefaultTag()) { + getLog() + .warn( + "Base image '" + + baseImage + + "' does not use a specific image digest - build may not be reproducible"); + } + + return baseImage; + + } catch (InvalidImageReferenceException ex) { + throw new MojoFailureException("Parameter 'from' is invalid", ex); + } + } + + /** @return the {@link ImageReference} parsed from {@link #to}. */ + private ImageReference getTargetImageReference() throws MojoFailureException { + try { + return ImageReference.parse(getTargetImage()); + + } catch (InvalidImageReferenceException ex) { + throw new MojoFailureException("Parameter 'to' is invalid", ex); + } } } diff --git a/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/BuildDockerMojoIT.java b/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/BuildDockerMojoIT.java new file mode 100644 index 0000000000..b84e930c77 --- /dev/null +++ b/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/BuildDockerMojoIT.java @@ -0,0 +1,72 @@ +/* + * Copyright 2018 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.cloud.tools.jib.maven; + +import com.google.cloud.tools.jib.Command; +import java.io.IOException; +import java.nio.file.Path; +import org.apache.maven.it.VerificationException; +import org.apache.maven.it.Verifier; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; + +/** Integration tests for {@link BuildDockerMojo}. */ +public class BuildDockerMojoIT { + + @ClassRule public static final TestPlugin testPlugin = new TestPlugin(); + + @ClassRule + public static final TestProject simpleTestProject = new TestProject(testPlugin, "simple"); + + @ClassRule + public static final TestProject emptyTestProject = new TestProject(testPlugin, "empty"); + + /** + * Builds and runs jib:buildDocker on a project at {@code projectRoot} pushing to {@code + * imageReference}. + */ + private static String buildToDockerDaemonAndRun(Path projectRoot, String imageReference) + throws VerificationException, IOException, InterruptedException { + Verifier verifier = new Verifier(projectRoot.toString()); + verifier.setAutoclean(false); + verifier.executeGoal("package"); + + // Builds twice, and checks if the second build took less time. + verifier.executeGoal("jib:buildDocker"); + verifier.verifyErrorFreeLog(); + + return new Command("docker", "run", imageReference).run(); + } + + @Test + public void testExecute_simple() throws VerificationException, IOException, InterruptedException { + Assert.assertEquals( + "Hello, world\n", + buildToDockerDaemonAndRun( + simpleTestProject.getProjectRoot(), + "gcr.io/jib-integration-testing/simpleimage:maven")); + } + + @Test + public void testExecute_empty() throws InterruptedException, IOException, VerificationException { + Assert.assertEquals( + "", + buildToDockerDaemonAndRun( + emptyTestProject.getProjectRoot(), "gcr.io/jib-integration-testing/emptyimage:maven")); + } +}