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.api.ImageReference; 022import com.google.cloud.tools.jib.api.LogEvent; 023import com.google.cloud.tools.jib.frontend.CredentialRetrieverFactory; 024import com.google.cloud.tools.jib.maven.MavenProjectProperties; 025import com.google.cloud.tools.jib.registry.credentials.CredentialRetrievalException; 026import io.micronaut.maven.jib.JibConfigurationService; 027import io.micronaut.maven.services.ApplicationConfigurationService; 028import io.micronaut.maven.services.DockerService; 029import org.apache.maven.execution.MavenSession; 030import org.apache.maven.plugin.MojoExecution; 031import org.apache.maven.plugin.MojoExecutionException; 032import org.apache.maven.plugin.MojoFailureException; 033import org.apache.maven.plugins.annotations.Mojo; 034import org.apache.maven.project.MavenProject; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038import javax.inject.Inject; 039import java.util.Optional; 040import java.util.Set; 041import java.util.stream.Stream; 042 043/** 044 * <p>Implementation of the <code>deploy</code> lifecycle for pushing Docker images</p> 045 * <p><strong>WARNING</strong>: this goal is not intended to be executed directly. Instead, Execute the <code>deploy</code> 046 * phase specifying the packaging type, eg:</p> 047 * 048 * <pre>mvn deploy -Dpackaging=docker-native</pre> 049 * 050 * @author Álvaro Sánchez-Mariscal 051 * @since 1.1 052 */ 053@Mojo(name = "docker-push") 054public class DockerPushMojo extends AbstractDockerMojo { 055 056 private static final Logger LOG = LoggerFactory.getLogger(DockerPushMojo.class); 057 058 @Inject 059 public DockerPushMojo(MavenProject mavenProject, JibConfigurationService jibConfigurationService, 060 ApplicationConfigurationService applicationConfigurationService, DockerService dockerService, 061 MavenSession mavenSession, MojoExecution mojoExecution) { 062 super(mavenProject, jibConfigurationService, applicationConfigurationService, dockerService, mavenSession, mojoExecution); 063 } 064 065 @Override 066 public void execute() throws MojoExecutionException, MojoFailureException { 067 Packaging packaging = Packaging.of(mavenProject.getPackaging()); 068 if (packaging == Packaging.DOCKER || packaging == Packaging.DOCKER_NATIVE || packaging == Packaging.DOCKER_CRAC) { 069 Set<String> 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 (jibConfigurationService.getToImage().isPresent()) { 075 for (String taggedImage : images) { 076 getLog().info("Pushing image: " + taggedImage); 077 try (PushImageCmd pushImageCmd = dockerService.pushImageCmd(taggedImage)) { 078 ImageReference imageReference = ImageReference.parse(taggedImage); 079 CredentialRetrieverFactory factory = CredentialRetrieverFactory.forImage(imageReference, this::logEvent); 080 Credential credentialHelperCredential = Stream 081 .of(factory.wellKnownCredentialHelpers(), factory.googleApplicationDefaultCredentials()) 082 .map(retriever -> { 083 try { 084 return retriever.retrieve(); 085 } catch (CredentialRetrievalException e) { 086 return Optional.<Credential>empty(); 087 } 088 }) 089 .filter(Optional::isPresent) 090 .map(Optional::get) 091 .findFirst() 092 .orElse(factory.dockerConfig().retrieve().orElse(null)); 093 094 Credential credential = jibConfigurationService.getToCredentials().orElse(credentialHelperCredential); 095 if (credential != null) { 096 AuthConfig authConfig = dockerService.getAuthConfigFor(taggedImage, credential.getUsername(), credential.getPassword()); 097 pushImageCmd.withAuthConfig(authConfig); 098 } 099 100 pushImageCmd.start().awaitCompletion(); 101 } catch (InterruptedException e) { 102 Thread.currentThread().interrupt(); 103 } catch (Exception e) { 104 throw new MojoExecutionException(e.getMessage(), e); 105 } 106 } 107 } else { 108 throw new MojoFailureException("The plugin " + MavenProjectProperties.PLUGIN_KEY + " is misconfigured. Missing <to> tag"); 109 } 110 } else { 111 throw new MojoFailureException("The <packaging> must be set to either [" + Packaging.DOCKER.id() + "] or [" + Packaging.DOCKER_NATIVE.id() + "]"); 112 } 113 } 114 115 private void logEvent(LogEvent logEvent) { 116 if (logEvent.getLevel().equals(LogEvent.Level.DEBUG)) { 117 LOG.debug(logEvent.getMessage()); 118 } else { 119 LOG.info(logEvent.getMessage()); 120 } 121 } 122}