io.fabric8.jube.maven.BuildMojo Maven / Gradle / Ivy
/**
* Copyright 2005-2014 Red Hat, Inc.
*
* Red Hat licenses this file to you 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 io.fabric8.jube.maven;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.fabric8.jube.util.ImageMavenCoords;
import io.fabric8.jube.util.InstallHelper;
import io.fabric8.utils.Objects;
import io.fabric8.utils.Zips;
import org.apache.commons.io.FileUtils;
import org.apache.maven.archiver.MavenArchiveConfiguration;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.assembly.AssemblerConfigurationSource;
import org.apache.maven.plugin.assembly.InvalidAssemblerConfigurationException;
import org.apache.maven.plugin.assembly.archive.AssemblyArchiver;
import org.apache.maven.plugin.assembly.io.AssemblyReadException;
import org.apache.maven.plugin.assembly.io.AssemblyReader;
import org.apache.maven.plugin.assembly.model.Assembly;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.repository.RepositorySystem;
import org.apache.maven.shared.filtering.MavenFileFilter;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.fabric8.utils.PropertiesHelper.findPropertiesWithPrefix;
/**
* Builds a Jube image from a known base image.
*/
@Mojo(name = "build")
public class BuildMojo extends AbstractMojo {
public static final String DOCKER_IMAGE_PROPERTY = "docker.image";
public static final String DOCKER_BASE_IMAGE_PROPERTY = "docker.from";
public static final String JUBE_ASSEMBLY_DIR = "jube-assembly";
private static final transient Logger LOG = LoggerFactory.getLogger(BuildMojo.class);
@Parameter(property = "docker.image", defaultValue = "${project.groupId}/${project.artifactId}")
private String image;
@Parameter(property = "docker.from", defaultValue = "fabric8/java")
private String baseImage;
@Parameter(property = "exportDir", defaultValue = "/maven")
private String exportDir;
@Parameter
private Map environmentVariables;
@Parameter
private Map ports;
/**
* A descriptor to use for building the data assembly to be exported in an Docker image
*/
@Parameter(property = "docker.assemblyDescriptor")
private String assemblyDescriptor;
/**
* Reference to an assembly descriptor included.
*/
@Parameter(property = "docker.assemblyDescriptorRef", defaultValue = "artifact-with-dependencies")
private String assemblyDescriptorRef;
/**
* Name of the generated image zip file
*/
@Parameter(property = "jube.outFile", defaultValue = "${project.build.directory}/${project.artifactId}-${project.version}-image.zip")
private File outputZipFile;
/**
* The artifact type for attaching the generated image zip file to the project
*/
@Parameter(property = "jube.zip.artifactType", defaultValue = "zip")
private String artifactType = "zip";
/**
* The artifact classifier for attaching the generated image zip file to the project
*/
@Parameter(property = "jube.zip.artifactClassifier", defaultValue = "image")
private String artifactClassifier = "image";
/**
* Generates the SERVICE environment variable
*/
@Parameter(property = "fabric8.service", defaultValue = "${project.artifactId}")
private String service;
/**
* Generates the SERVICE_NAME environment variable
*/
@Parameter(property = "fabric8.serviceName", defaultValue = "${project.name}")
private String serviceName;
// ==============================================================================================================
// Parameters required from Maven when building an assembly.
@Parameter
private MavenArchiveConfiguration archive;
@Component
private MavenProject project;
@Component
private MavenSession session;
@Component
private MavenFileFilter mavenFileFilter;
@Component
private ArtifactResolver artifactResolver;
@Component
private RepositorySystem repositorySystem;
@Component
private ArtifactRepositoryFactory artifactRepositoryFactory;
@Parameter(defaultValue = "${localRepository}", readonly = true)
private ArtifactRepository localRepository;
@Parameter(defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true)
private List pomRemoteRepositories;
@Component
private AssemblyArchiver assemblyArchiver;
@Component
private AssemblyReader assemblyReader;
@Component
private ArchiverManager archiverManager;
@Component
private MavenProjectHelper projectHelper;
@Component
private ArtifactHandlerManager artifactHandlerManager;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
if (isIgnoreProject()) {
return;
}
getLog().info("Generating Jube image " + image + " from base image " + baseImage);
getLog().info("Assembly reference: " + assemblyDescriptorRef);
if (assemblyDescriptor == null && assemblyDescriptorRef == null) {
throw new MojoExecutionException("No assemblyDescriptor or assemblyDescriptorRef has been given");
}
System.out.println("Env vars: " + getEnvironmentVariables());
createAssembly();
}
/**
* Returns true if this project should be ignored
*/
protected boolean isIgnoreProject() {
return "pom".equals(project.getPackaging());
}
public Map getEnvironmentVariables() {
if (environmentVariables == null) {
environmentVariables = new HashMap<>();
}
if (environmentVariables.isEmpty()) {
environmentVariables = new HashMap<>();
Map lowerCaseProperties = findPropertiesWithPrefix(project.getProperties(), "docker.env.");
Set> entries = lowerCaseProperties.entrySet();
for (Map.Entry entry : entries) {
String key = entry.getKey();
if (key != null) {
environmentVariables.put(key.toUpperCase(), entry.getValue());
}
}
}
if (!environmentVariables.containsKey("SERVICE")) {
environmentVariables.put("SERVICE", service);
}
if (!environmentVariables.containsKey("SERVICE_NAME")) {
environmentVariables.put("SERVICE_NAME", serviceName);
}
return environmentVariables;
}
public void setEnvironmentVariables(Map environmentVariables) {
this.environmentVariables = environmentVariables;
}
public Map getPorts() {
if (ports == null) {
ports = new HashMap<>();
}
if (ports.isEmpty()) {
ports = findPropertiesWithPrefix(project.getProperties(), "docker.port.container.");
}
return ports;
}
protected void createAssembly() throws MojoFailureException, MojoExecutionException {
String extractBaseImageRef = "extractBaseImage";
String createZipRef = "createZip";
//String extractBaseImageRef = "internal/extractBaseImage.xml";
AssemblerConfigurationSource extractConfig = createAssemblyConfigurationSource(null, extractBaseImageRef);
AssemblerConfigurationSource projectConfig = createAssemblyConfigurationSource(assemblyDescriptor, assemblyDescriptorRef);
AssemblerConfigurationSource zipConfig = createAssemblyConfigurationSource(null, createZipRef);
Assembly assembly = null;
File buildDir = new File(project.getBasedir(), "target/jube");
try {
buildDir.mkdirs();
try {
unpackBaseImage(buildDir, false);
} catch (ArtifactResolutionException e) {
unpackBaseImage(buildDir, true);
} catch (ArtifactNotFoundException e) {
unpackBaseImage(buildDir, true);
}
writeEnvironmentVariables(buildDir);
writePorts(buildDir);
assembly = extractAssembly(projectConfig);
assembly.setId("docker");
if (exportDir.startsWith("/")) {
exportDir = exportDir.substring(1);
}
assemblyArchiver.createArchive(assembly, exportDir, "dir", projectConfig, false);
File assemblyDir = new File(project.getBasedir(), "target/" + JUBE_ASSEMBLY_DIR);
FileUtils.copyDirectory(assemblyDir, buildDir);
InstallHelper.chmodAllScripts(buildDir);
Zips.createZipFile(LOG, buildDir, outputZipFile);
getLog().info("Created image zip: " + outputZipFile);
attachArtifactToBuild();
} catch (InvalidAssemblerConfigurationException e) {
throw new MojoFailureException(assembly, "Assembly is incorrectly configured: " + assembly.getId(),
"Assembly: " + assembly.getId() + " is not configured correctly: "
+ e.getMessage());
} catch (Exception e) {
throw new MojoExecutionException("Failed to create assembly for image: " + e.getMessage(), e);
}
}
protected void attachArtifactToBuild() {
projectHelper.attachArtifact(project, artifactType, artifactClassifier, outputZipFile);
}
protected void writeEnvironmentVariables(File buildDir) throws IOException {
Map envMap = getEnvironmentVariables();
// make sure to write for both kind of platforms
File envScript = new File(buildDir, InstallHelper.ENVIRONMENT_VARIABLE_SCRIPT);
InstallHelper.writeEnvironmentVariables(envScript, envMap);
envScript = new File(buildDir, InstallHelper.ENVIRONMENT_VARIABLE_SCRIPT_WINDOWS);
InstallHelper.writeEnvironmentVariables(envScript, envMap);
}
protected void writePorts(File buildDir) throws IOException {
Map portMap = getPorts();
if (portMap.isEmpty()) {
return;
}
File envScript = new File(buildDir, InstallHelper.PORTS_PROPERTIES_FILE);
InstallHelper.writePorts(envScript, portMap);
}
protected void unpackBaseImage(File buildDir, boolean useDefaultPrefix) throws Exception {
String imageName = project.getProperties().getProperty(DOCKER_BASE_IMAGE_PROPERTY);
Objects.notNull(imageName, DOCKER_BASE_IMAGE_PROPERTY);
ImageMavenCoords baseImageCoords = ImageMavenCoords.parse(imageName, useDefaultPrefix);
String coords = baseImageCoords.getAetherCoords();
Artifact artifact = repositorySystem.createArtifactWithClassifier(baseImageCoords.getGroupId(),
baseImageCoords.getArtifactId(), baseImageCoords.getVersion(), baseImageCoords.getType(),
baseImageCoords.getClassifier());
getLog().info("Resolving Jube image: " + artifact);
ArtifactResolutionRequest request = new ArtifactResolutionRequest();
request.setArtifact(artifact);
request.setLocalRepository(localRepository);
request.setRemoteRepositories(pomRemoteRepositories);
ArtifactResolutionResult result = artifactResolver.resolve(request);
if (!result.isSuccess()) {
throw new ArtifactNotFoundException("Cannot download Jube image", artifact);
}
getLog().info("Resolved Jube image: " + artifact);
if (artifact.getFile() != null) {
File file = artifact.getFile();
getLog().info("File: " + file);
if (!file.exists() || file.isDirectory()) {
throw new MojoExecutionException("Resolved file for " + coords + " is not a valid file: " + file.getAbsolutePath());
}
getLog().info("Unpacking base image " + file.getAbsolutePath() + " to build dir: " + buildDir);
Zips.unzip(new FileInputStream(file), buildDir);
}
}
private AssemblerConfigurationSource createAssemblyConfigurationSource(String descriptor, String descriptorRef) {
String[] descriptors = null;
String[] descriptorRefs = null;
if (descriptor != null) {
descriptors = new String[]{descriptor};
} else if (descriptorRef != null) {
descriptorRefs = new String[]{descriptorRef};
}
return new JubeArchiveConfigurationSource(project, session, archive, mavenFileFilter, descriptors, descriptorRefs);
}
private Assembly extractAssembly(AssemblerConfigurationSource config) throws MojoExecutionException, MojoFailureException {
try {
List assemblies = assemblyReader.readAssemblies(config);
if (assemblies.size() != 1) {
throw new MojoFailureException("Only one assembly can be used for creating a Docker base image (and not " + assemblies.size() + ")");
}
return assemblies.get(0);
} catch (AssemblyReadException e) {
throw new MojoExecutionException("Error reading assembly: " + e.getMessage(), e);
} catch (InvalidAssemblerConfigurationException e) {
throw new MojoFailureException(assemblyReader, e.getMessage(), "Docker assembly configuration is invalid: " + e.getMessage());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy