001/* 002 * Copyright 2017-2022 original authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.micronaut.maven; 017 018import com.github.dockerjava.api.command.PushImageCmd; 019import com.github.dockerjava.api.model.AuthConfig; 020import com.google.cloud.tools.jib.api.Credential; 021import com.google.cloud.tools.jib.maven.MavenProjectProperties; 022import io.micronaut.maven.jib.JibConfigurationService; 023import io.micronaut.maven.services.ApplicationConfigurationService; 024import io.micronaut.maven.services.DockerService; 025import org.apache.maven.execution.MavenSession; 026import org.apache.maven.plugin.MojoExecution; 027import org.apache.maven.plugin.MojoExecutionException; 028import org.apache.maven.plugin.MojoFailureException; 029import org.apache.maven.plugins.annotations.Mojo; 030import org.apache.maven.project.MavenProject; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034import javax.inject.Inject; 035import java.io.File; 036import java.util.Optional; 037 038/** 039 * <p>Implementation of the <code>deploy</code> lifecycle for pushing Docker images</p> 040 * <p><strong>WARNING</strong>: this goal is not intended to be executed directly. Instead, Execute the <code>deploy</code> 041 * phase specifying the packaging type, eg:</p> 042 * 043 * <pre>mvn deploy -Dpackaging=docker-native</pre> 044 * 045 * @author Álvaro Sánchez-Mariscal 046 * @since 1.1 047 */ 048@Mojo(name = "docker-push") 049public class DockerPushMojo extends AbstractDockerMojo { 050 051 private static final Logger LOG = LoggerFactory.getLogger(DockerPushMojo.class); 052 053 @Inject 054 public DockerPushMojo(MavenProject mavenProject, JibConfigurationService jibConfigurationService, 055 ApplicationConfigurationService applicationConfigurationService, DockerService dockerService, 056 MavenSession mavenSession, MojoExecution mojoExecution) { 057 super(mavenProject, jibConfigurationService, applicationConfigurationService, dockerService, mavenSession, mojoExecution); 058 } 059 060 @Override 061 public void execute() throws MojoExecutionException, MojoFailureException { 062 Packaging packaging = Packaging.of(mavenProject.getPackaging()); 063 if (packaging == Packaging.DOCKER || packaging == Packaging.DOCKER_NATIVE || packaging == Packaging.DOCKER_CRAC) { 064 if (packaging == Packaging.DOCKER && !shouldBuildWithDockerfile(new File(mavenProject.getBasedir(), DockerfileMojo.DOCKERFILE))) { 065 if (validateJibDeployBuildGoal()) { 066 return; 067 } 068 } 069 var images = getTags(); 070 071 // getTags() will automatically generate an image name if none is specified 072 // To maintain error compatibility, check that an image name has been 073 // manually specified. 074 if (getConfiguredToImage().isPresent()) { 075 for (String taggedImage : images) { 076 getLog().info("Pushing image: " + taggedImage); 077 try (PushImageCmd pushImageCmd = dockerService.pushImageCmd(taggedImage)) { 078 Optional<Credential> toCredentials = jibConfigurationService.getToCredentials(); 079 Optional<Credential> credential = toCredentials.or(() -> jibConfigurationService.resolveCredentialForImage(taggedImage, LOG)); 080 credential.ifPresent(cred -> { 081 var username = cred.getUsername(); 082 var password = cred.getPassword(); 083 AuthConfig authConfig = dockerService.getAuthConfigFor(taggedImage, username, password); 084 pushImageCmd.withAuthConfig(authConfig); 085 }); 086 087 pushImageCmd.start().awaitCompletion(); 088 } catch (InterruptedException e) { 089 Thread.currentThread().interrupt(); 090 } catch (Exception e) { 091 throw new MojoExecutionException(e.getMessage(), e); 092 } 093 } 094 } else { 095 throw new MojoFailureException("The plugin " + MavenProjectProperties.PLUGIN_KEY + " is misconfigured. Missing <to> tag"); 096 } 097 } else { 098 throw new MojoFailureException("The <packaging> must be set to either [" + Packaging.DOCKER.id() + "], [" 099 + Packaging.DOCKER_NATIVE.id() + "] or [" + Packaging.DOCKER_CRAC.id() + "]"); 100 } 101 } 102 103 private boolean validateJibDeployBuildGoal() throws MojoExecutionException, MojoFailureException { 104 validateJibBuildGoal(); 105 if (JIB_BUILD_GOAL_BUILD.equals(jibBuildGoal)) { 106 String toImage = requireConfiguredToImageForJibRegistryBuild(); 107 getLog().info("Skipping Docker daemon push for " + toImage + " because jib.buildGoal=build publishes the image to the registry during the package phase."); 108 return true; 109 } 110 if (JIB_BUILD_GOAL_BUILD_TAR.equals(jibBuildGoal)) { 111 throw new MojoFailureException("jib.buildGoal=buildTar is not supported for deploy because it creates target/jib-image.tar instead of publishing to a registry. " 112 + "Use jib.buildGoal=build with jib.to.image for daemonless registry deploy, or omit jib.buildGoal/use dockerBuild for the Docker daemon push path."); 113 } 114 return false; 115 } 116 117}