diff --git a/doc/changelog.md b/doc/changelog.md index f1be2fd22..97413556f 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -1,6 +1,16 @@ # ChangeLog -* **0.27-SNAPSHOT** +* **1.0-SNAPSHOT** [next gen docker-maven-plugin] + - Removed deprecated configuration and renamed configuration + - `` has been removed. Use `` or `` instead + - `` has been removed. Use `` instead. + - `` has been removed. Use `` instead + - `` has been removed. Use `ignore` has been renamed `` and semantics has been changed slightly. You can have now a Dockerfile from outside the context directory. + - `` has been removed in favor of `` + - `` removed, use `` for network configuration + +* **0.27-SNAPSHOT** [patch releases] - Update to JMockit 1.43 - Compiles with Java 11 - Update to jnr-unixsocket version to 0.21 (#1089) diff --git a/pom.xml b/pom.xml index 8ecb686d9..c6f201c3c 100644 --- a/pom.xml +++ b/pom.xml @@ -122,6 +122,12 @@ 1.1 + + org.apache.commons + commons-compress + 1.17 + + com.google.code.gson gson @@ -523,6 +529,18 @@ + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.1 + + + -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar + + + + @@ -574,7 +592,7 @@ org.apache.maven.plugins maven-surefire-plugin - ${surefire.version} + ${surefire.version} diff --git a/samples/data-jolokia/pom.xml b/samples/data-jolokia/pom.xml index a36ae0312..96a82da31 100644 --- a/samples/data-jolokia/pom.xml +++ b/samples/data-jolokia/pom.xml @@ -37,7 +37,7 @@ 8 tomcat docker.io/fabric8/${server.name}-${server.version}:latest - 1.3.2 + 1.3.6 UTF-8 UTF-8 @@ -96,7 +96,6 @@ server ${image} - none data @@ -105,7 +104,7 @@ -Xmx32m - 1 + 1 ${project.basedir}/src/main/docker/environment.properties @@ -169,6 +168,9 @@ assembly.xml + + %a-%t + 5000 both @@ -255,7 +257,7 @@ -Xmx32m - 1 + 1 - ${project.basedir}/src/main/docker + ${project.basedir}/src/main/docker rootWar @@ -74,4 +74,48 @@ + + + + alternate + + + + io.fabric8 + docker-maven-plugin + + + + + Dockerfile-2 + + + + + + + + + + + outside + + + + io.fabric8 + docker-maven-plugin + + + + + ${project.basedir}/Dockerfile-3 + + + + + + + + + diff --git a/samples/dockerfile/src/main/docker/Dockerfile b/samples/dockerfile/src/main/docker/Dockerfile index 12baec1fa..4b34353a4 100644 --- a/samples/dockerfile/src/main/docker/Dockerfile +++ b/samples/dockerfile/src/main/docker/Dockerfile @@ -1,7 +1,9 @@ # Sample Dockerfile for use with the Docker file mode FROM ${base} -ENV SAMPLE_BUILD_MODE=dockerfile +ENV SAMPLE_BUILD_MODE=dockerfile \ + DOCKERFILE_NAME="src/main/Dockerfile" + LABEL PROJECT_NAME=hello-world \ PROJECT=${project.artifactId} diff --git a/samples/dockerfile/src/main/docker/Dockerfile-2 b/samples/dockerfile/src/main/docker/Dockerfile-2 new file mode 100644 index 000000000..42d6aba73 --- /dev/null +++ b/samples/dockerfile/src/main/docker/Dockerfile-2 @@ -0,0 +1,14 @@ +# Sample Dockerfile for use with the Docker file mode +FROM ${base} + +ENV SAMPLE_BUILD_MODE=dockerfile \ + DOCKERFILE_NAME="src/main/Dockerfile-2" + +# Arbitrary files can be added +ADD welcome.txt / + +# In maven/ the files as specified in the section is stored +# and need to be added manually +COPY maven/ /var/lib/jetty/webapps/ + +EXPOSE 8080 diff --git a/samples/dockerfile/src/main/java/io/fabric8/dmp/samples/dockerfile/HelloWorldServlet.java b/samples/dockerfile/src/main/java/io/fabric8/dmp/samples/dockerfile/HelloWorldServlet.java index fff1edc3c..fca26625c 100644 --- a/samples/dockerfile/src/main/java/io/fabric8/dmp/samples/dockerfile/HelloWorldServlet.java +++ b/samples/dockerfile/src/main/java/io/fabric8/dmp/samples/dockerfile/HelloWorldServlet.java @@ -20,7 +20,7 @@ public class HelloWorldServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String txt = FileUtils.readFileToString(new File("/welcome.txt"), Charset.defaultCharset()); - resp.getWriter().append(txt).flush(); + resp.getWriter().append(txt).append("\nFile: ").append(System.getenv("DOCKERFILE_NAME")).flush(); resp.setHeader("Content-Type", "plain/text"); } } diff --git a/src/main/java/io/fabric8/maven/docker/AbstractBuildSupportMojo.java b/src/main/java/io/fabric8/maven/docker/AbstractBuildSupportMojo.java index d58514a64..84f010805 100644 --- a/src/main/java/io/fabric8/maven/docker/AbstractBuildSupportMojo.java +++ b/src/main/java/io/fabric8/maven/docker/AbstractBuildSupportMojo.java @@ -3,10 +3,11 @@ import java.util.List; import java.util.Map; -import io.fabric8.maven.docker.service.BuildService; -import io.fabric8.maven.docker.util.MojoParameters; +import io.fabric8.maven.docker.build.maven.MavenArchiveService; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; +import io.fabric8.maven.docker.build.maven.MavenRegistryContext; +import io.fabric8.maven.docker.config.build.ImagePullPolicy; import org.apache.maven.archiver.MavenArchiveConfiguration; -import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; @@ -25,41 +26,50 @@ abstract public class AbstractBuildSupportMojo extends AbstractDockerMojo { // See also here: http://maven.40175.n5.nabble.com/Mojo-Java-1-5-Component-MavenProject-returns-null-vs-JavaDoc-parameter-expression-quot-project-quot-s-td5733805.html @Parameter - private MavenArchiveConfiguration archive; + protected MavenArchiveConfiguration archive; @Component - private MavenFileFilter mavenFileFilter; + protected MavenFileFilter mavenFileFilter; @Component - private MavenReaderFilter mavenFilterReader; + protected MavenReaderFilter mavenReaderFilter; @Parameter - private Map buildArgs; + protected Map buildArgs; @Parameter(property = "docker.pull.registry") - private String pullRegistry; + protected String pullRegistry; @Parameter(property = "docker.source.dir", defaultValue="src/main/docker") - private String sourceDirectory; + protected String sourceDirectory; @Parameter(property = "docker.target.dir", defaultValue="target/docker") - private String outputDirectory; + protected String outputDirectory; @Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true ) - private List reactorProjects; + protected List reactorProjects; - protected BuildService.BuildContext getBuildContext() throws MojoExecutionException { - return new BuildService.BuildContext.Builder() - .buildArgs(buildArgs) - .mojoParameters(createMojoParameters()) - .registryConfig(getRegistryConfig(pullRegistry)) - .build(); - } + protected MavenBuildContext getBuildContext(MavenArchiveService archiveService) { - protected MojoParameters createMojoParameters() { - return new MojoParameters(session, project, archive, mavenFileFilter, mavenFilterReader, - settings, sourceDirectory, outputDirectory, reactorProjects); - } + MavenRegistryContext registryContext = new MavenRegistryContext.Builder() + .authRegistryAuthFactory(registryAuthFactory) + .defaultImagePullPolicy(imagePullPolicy != null ? ImagePullPolicy.fromString(imagePullPolicy) : null) + .pullRegistry(pullRegistry) + .build(); + return new MavenBuildContext.Builder() + .project(project) + .sourceDirectory(sourceDirectory) + .outputDirectory(outputDirectory) + .session(session) + .settings(settings) + .mavenFileFilter(mavenFileFilter) + .mavenReaderFilter(mavenReaderFilter) + .reactorProjects(reactorProjects) + .archiveConfiguration(archive) + .archiveService(archiveService) + .registryContext(registryContext) + .build(); + } } diff --git a/src/main/java/io/fabric8/maven/docker/AbstractDockerMojo.java b/src/main/java/io/fabric8/maven/docker/AbstractDockerMojo.java index 012457dbf..2b80f9385 100644 --- a/src/main/java/io/fabric8/maven/docker/AbstractDockerMojo.java +++ b/src/main/java/io/fabric8/maven/docker/AbstractDockerMojo.java @@ -2,28 +2,36 @@ import java.io.File; import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.Properties; +import java.util.Map; import io.fabric8.maven.docker.access.DockerAccess; import io.fabric8.maven.docker.access.ExecException; -import io.fabric8.maven.docker.config.BuildImageConfiguration; -import io.fabric8.maven.docker.config.ConfigHelper; +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuthFactory; +import io.fabric8.maven.docker.build.auth.extended.EcrExtendedRegistryAuthHandler; +import io.fabric8.maven.docker.build.docker.DockerRegistryAuthHandler; +import io.fabric8.maven.docker.build.auth.handler.FromConfigRegistryAuthHandler; +import io.fabric8.maven.docker.build.auth.handler.OpenShiftRegistryAuthHandler; +import io.fabric8.maven.docker.build.maven.SettingsRegistrysAuthHandler; +import io.fabric8.maven.docker.build.auth.handler.SystemPropertyRegistryAuthHandler; +import io.fabric8.maven.docker.util.ConfigHelper; import io.fabric8.maven.docker.config.DockerMachineConfiguration; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.RegistryAuthConfiguration; -import io.fabric8.maven.docker.config.VolumeConfiguration; +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.config.maven.RegistryAuthConfiguration; import io.fabric8.maven.docker.config.handler.ImageConfigResolver; +import io.fabric8.maven.docker.config.maven.MavenImageConfiguration; +import io.fabric8.maven.docker.config.run.VolumeConfiguration; import io.fabric8.maven.docker.log.LogDispatcher; import io.fabric8.maven.docker.log.LogOutputSpecFactory; import io.fabric8.maven.docker.service.DockerAccessFactory; -import io.fabric8.maven.docker.service.ImagePullManager; -import io.fabric8.maven.docker.service.RegistryService; import io.fabric8.maven.docker.service.ServiceHub; import io.fabric8.maven.docker.service.ServiceHubFactory; import io.fabric8.maven.docker.util.AnsiLogger; -import io.fabric8.maven.docker.util.AuthConfigFactory; import io.fabric8.maven.docker.util.EnvUtil; import io.fabric8.maven.docker.util.GavLabel; import io.fabric8.maven.docker.util.ImageNameFormatter; @@ -39,9 +47,16 @@ import org.apache.maven.settings.Settings; import org.codehaus.plexus.PlexusConstants; import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.context.Context; import org.codehaus.plexus.context.ContextException; import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable; +import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; + +import static io.fabric8.maven.docker.build.auth.RegistryAuth.AUTH; +import static io.fabric8.maven.docker.build.auth.RegistryAuth.EMAIL; +import static io.fabric8.maven.docker.build.auth.RegistryAuth.PASSWORD; +import static io.fabric8.maven.docker.build.auth.RegistryAuth.USERNAME; /** * Base class for this plugin. @@ -177,7 +192,7 @@ public abstract class AbstractDockerMojo extends AbstractMojo implements Context * Image configurations configured directly. */ @Parameter - private List images; + private List images; // Docker-machine configuration @Parameter @@ -187,8 +202,11 @@ public abstract class AbstractDockerMojo extends AbstractMojo implements Context // mangle the image configurations. private List resolvedImages; + // will be initialized and remembered for creating the authconfigfactory later + private PlexusContainer plexusContainer; + // Handler dealing with authentication credentials - private AuthConfigFactory authConfigFactory; + protected RegistryAuthFactory registryAuthFactory; protected Logger log; @@ -206,12 +224,13 @@ public abstract class AbstractDockerMojo extends AbstractMojo implements Context public void execute() throws MojoExecutionException, MojoFailureException { if (!skip) { log = new AnsiLogger(getLog(), useColor, verbose, !settings.getInteractiveMode(), getLogPrefix()); - authConfigFactory.setLog(log); + registryAuthFactory = createRegistryAuthFactory(); imageConfigResolver.setLog(log); LogOutputSpecFactory logSpecFactory = new LogOutputSpecFactory(useColor, logStdout, logDate); - ConfigHelper.validateExternalPropertyActivation(project, images); + List imageConfigs = convertToPlainImageConfigurations(images); + ConfigHelper.validateExternalPropertyActivation(project, imageConfigs); DockerAccess access = null; try { @@ -237,6 +256,62 @@ public void execute() throws MojoExecutionException, MojoFailureException { } } + private RegistryAuthFactory createRegistryAuthFactory() { + + RegistryAuthConfig registryAuthConfig = createRegistryAuthConfig(); + + return new RegistryAuthFactory.Builder() + .decryptor(this::decrypt) + .defaultRegistry(registry) + .log(log) + .addRegistryAuthHandler(new SystemPropertyRegistryAuthHandler(registryAuthConfig, log)) + .addRegistryAuthHandler(new OpenShiftRegistryAuthHandler(registryAuthConfig, log)) + .addRegistryAuthHandler(new FromConfigRegistryAuthHandler(registryAuthConfig, log)) + .addRegistryAuthHandler(new SettingsRegistrysAuthHandler(settings, log)) + .addRegistryAuthHandler(new DockerRegistryAuthHandler(log)) + .addExtendedRegistryAuthHandler(new EcrExtendedRegistryAuthHandler(log)) + .build(); + } + + private RegistryAuthConfig createRegistryAuthConfig() { + + RegistryAuthConfig.Builder builder = + new RegistryAuthConfig.Builder() + .skipExtendedAuthentication(skipExtendedAuth) + .propertyPrefix("docker"); + + if (authConfig != null) { + builder + .addDefaultConfig(USERNAME, authConfig.getUsername()) + .addDefaultConfig(PASSWORD, authConfig.getPassword()) + .addDefaultConfig(EMAIL, authConfig.getEmail()) + .addDefaultConfig(AUTH, authConfig.getAuthToken()); + addKindMap(builder, RegistryAuthConfig.Kind.PULL, authConfig.getPull()); + addKindMap(builder, RegistryAuthConfig.Kind.PUSH, authConfig.getPush()); + } + return builder.build(); + } + + private String decrypt(String password) { + try { + // Done by reflection since I have classloader issues otherwise + Object secDispatcher = plexusContainer.lookup(SecDispatcher.ROLE, "maven"); + Method method = secDispatcher.getClass().getMethod("decrypt", String.class); + return (String) method.invoke(secDispatcher, password); + } catch (ComponentLookupException e) { + throw new IllegalStateException("Error looking security dispatcher", e); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException("Cannot decrypt password: " + e.getCause(), e); + } + } + + private List convertToPlainImageConfigurations(List images) { + if (images == null) { + return null; + } + return new ArrayList<>(images); + } + private void logException(Exception exp) { if (exp.getCause() != null) { log.error("%s [%s]", exp.getMessage(), exp.getCause().getMessage()); @@ -258,14 +333,14 @@ protected DockerAccessFactory.DockerAccessContext getDockerAccessContext() { .build(); } - protected RegistryService.RegistryConfig getRegistryConfig(String specificRegistry) throws MojoExecutionException { - return new RegistryService.RegistryConfig.Builder() - .settings(settings) - .authConfig(authConfig != null ? authConfig.toMap() : null) - .authConfigFactory(authConfigFactory) - .skipExtendedAuth(skipExtendedAuth) - .registry(specificRegistry != null ? specificRegistry : registry) - .build(); + + private void addKindMap(RegistryAuthConfig.Builder builder, RegistryAuthConfig.Kind kind, Map kindMap) { + if (kindMap != null) { + builder.addKindConfig(kind, USERNAME, (String) kindMap.get(USERNAME)); + builder.addKindConfig(kind, PASSWORD, (String) kindMap.get(PASSWORD)); + builder.addKindConfig(kind, EMAIL, (String) kindMap.get(EMAIL)); + builder.addKindConfig(kind, AUTH, (String) kindMap.get(AUTH)); + } } /** @@ -307,14 +382,9 @@ private String initImageConfiguration(Date buildTimeStamp) { // Resolve images resolvedImages = ConfigHelper.resolveImages( log, - images, // Unresolved images - new ConfigHelper.Resolver() { - @Override - public List resolve(ImageConfiguration image) { - return imageConfigResolver.resolve(image, project, session); - } - }, - filter, // A filter which image to process + convertToPlainImageConfigurations(images), // Unresolved images + image -> imageConfigResolver.resolve(image, project, session), + filter, // A filter which image to process this); // customizer (can be overwritten by a subclass) // Check for simple Dockerfile mode @@ -381,7 +451,7 @@ protected List getVolumes() { @Override public void contextualize(Context context) throws ContextException { - authConfigFactory = new AuthConfigFactory((PlexusContainer) context.get(PlexusConstants.PLEXUS_KEY)); + plexusContainer = (PlexusContainer) context.get(PlexusConstants.PLEXUS_KEY); } // ================================================================================= @@ -400,26 +470,6 @@ protected LogDispatcher getLogDispatcher(ServiceHub hub) { return dispatcher; } - public ImagePullManager getImagePullManager(String imagePullPolicy, String autoPull) { - return new ImagePullManager(getSessionCacheStore(), imagePullPolicy, autoPull); - } - - private ImagePullManager.CacheStore getSessionCacheStore() { - return new ImagePullManager.CacheStore() { - @Override - public String get(String key) { - Properties userProperties = session.getUserProperties(); - return userProperties.getProperty(key); - } - - @Override - public void put(String key, String value) { - Properties userProperties = session.getUserProperties(); - userProperties.setProperty(key, value); - } - }; - } - private ImageConfiguration createSimpleDockerfileConfig(File dockerFile) { // No configured name, so create one from maven GAV String name = EnvUtil.getPropertiesWithSystemOverrides(project).getProperty("docker.name"); @@ -428,8 +478,8 @@ private ImageConfiguration createSimpleDockerfileConfig(File dockerFile) { name = "%g/%a:%l"; } - BuildImageConfiguration buildConfig = - new BuildImageConfiguration.Builder() + BuildConfiguration buildConfig = + new BuildConfiguration.Builder() .dockerFile(dockerFile.getPath()) .build(); @@ -440,8 +490,8 @@ private ImageConfiguration createSimpleDockerfileConfig(File dockerFile) { } private ImageConfiguration addSimpleDockerfileConfig(ImageConfiguration image, File dockerfile) { - BuildImageConfiguration buildConfig = - new BuildImageConfiguration.Builder() + BuildConfiguration buildConfig = + new BuildConfiguration.Builder() .dockerFile(dockerfile.getPath()) .build(); return new ImageConfiguration.Builder(image).buildConfig(buildConfig).build(); diff --git a/src/main/java/io/fabric8/maven/docker/BuildMojo.java b/src/main/java/io/fabric8/maven/docker/BuildMojo.java index 4db8b6583..0d59952e1 100644 --- a/src/main/java/io/fabric8/maven/docker/BuildMojo.java +++ b/src/main/java/io/fabric8/maven/docker/BuildMojo.java @@ -11,10 +11,10 @@ import java.util.Enumeration; import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.config.BuildImageConfiguration; +import io.fabric8.maven.docker.build.docker.DockerBuildService; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.service.BuildService; -import io.fabric8.maven.docker.service.ImagePullManager; +import io.fabric8.maven.docker.config.build.BuildConfiguration; import io.fabric8.maven.docker.service.ServiceHub; import io.fabric8.maven.docker.util.EnvUtil; import org.apache.maven.plugin.MojoExecutionException; @@ -61,31 +61,6 @@ protected void executeInternal(ServiceHub hub) throws IOException, MojoExecution } } - protected void buildAndTag(ServiceHub hub, ImageConfiguration imageConfig) - throws MojoExecutionException, IOException { - - EnvUtil.storeTimestamp(getBuildTimestampFile(), getBuildTimestamp()); - - BuildService.BuildContext buildContext = getBuildContext(); - ImagePullManager pullManager = getImagePullManager(determinePullPolicy(imageConfig.getBuildConfiguration()), autoPull); - BuildService buildService = hub.getBuildService(); - - buildService.buildImage(imageConfig, pullManager, buildContext); - if (!skipTag) { - buildService.tagImage(imageConfig.getName(), imageConfig); - } - } - - // We ignore an already existing date file and always return the current date - - @Override - protected Date getReferenceDate() { - return new Date(); - } - private String determinePullPolicy(BuildImageConfiguration buildConfig) { - return buildConfig != null && buildConfig.getImagePullPolicy() != null ? buildConfig.getImagePullPolicy() : imagePullPolicy; - } - /** * Helper method to process an ImageConfiguration. * @@ -95,10 +70,10 @@ private String determinePullPolicy(BuildImageConfiguration buildConfig) { * @throws MojoExecutionException */ private void processImageConfig(ServiceHub hub, ImageConfiguration aImageConfig) throws IOException, MojoExecutionException { - BuildImageConfiguration buildConfig = aImageConfig.getBuildConfiguration(); + BuildConfiguration buildConfig = aImageConfig.getBuildConfiguration(); if (buildConfig != null) { - if(buildConfig.skip()) { + if(buildConfig.getSkip() != null && buildConfig.getSkip()) { log.info("%s : Skipped building", aImageConfig.getDescription()); } else { buildAndTag(hub, aImageConfig); @@ -106,6 +81,27 @@ private void processImageConfig(ServiceHub hub, ImageConfiguration aImageConfig) } } + protected void buildAndTag(ServiceHub hub, ImageConfiguration imageConfig) + throws MojoExecutionException, IOException { + + EnvUtil.storeTimestamp(getBuildTimestampFile(), getBuildTimestamp()); + + MavenBuildContext buildContext = getBuildContext(hub.getArchiveService()); + DockerBuildService buildService = hub.getBuildService(); + + buildService.buildImage(imageConfig, buildContext, buildArgs); + if (!skipTag) { + buildService.tagImage(imageConfig.getName(), imageConfig); + } + } + + // We ignore an already existing date file and always return the current date + @Override + protected Date getReferenceDate() { + return new Date(); + } + + // check for a run-java.sh dependency an extract the script to target/ if found private void executeBuildPlugins() { try { diff --git a/src/main/java/io/fabric8/maven/docker/PushMojo.java b/src/main/java/io/fabric8/maven/docker/PushMojo.java index 07f38ed55..2cff17eaa 100644 --- a/src/main/java/io/fabric8/maven/docker/PushMojo.java +++ b/src/main/java/io/fabric8/maven/docker/PushMojo.java @@ -1,9 +1,10 @@ package io.fabric8.maven.docker; -import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.service.ServiceHub; +import java.io.IOException; -import org.apache.maven.plugin.MojoExecutionException; +import io.fabric8.maven.docker.build.maven.MavenRegistryContext; +import io.fabric8.maven.docker.config.ImageConfiguration; +import io.fabric8.maven.docker.service.ServiceHub; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; @@ -22,13 +23,13 @@ public class PushMojo extends AbstractDockerMojo { @Parameter(property = "docker.skip.push", defaultValue = "false") private boolean skipPush; - - /** + + /** * Skip building tags */ @Parameter(property = "docker.skip.tag", defaultValue = "false") private boolean skipTag; - + @Parameter(property = "docker.push.retries", defaultValue = "0") private int retries; @@ -36,11 +37,18 @@ public class PushMojo extends AbstractDockerMojo { * {@inheritDoc} */ @Override - public void executeInternal(ServiceHub hub) throws DockerAccessException, MojoExecutionException { + public void executeInternal(ServiceHub hub) throws IOException { if (skipPush) { return; } - hub.getRegistryService().pushImages(getResolvedImages(), retries, getRegistryConfig(pushRegistry), skipTag); + MavenRegistryContext registryContext = new MavenRegistryContext.Builder() + .authRegistryAuthFactory(registryAuthFactory) + .pushRegistry(pushRegistry) + .build(); + + for (ImageConfiguration imageConfig : getResolvedImages()) { + hub.getRegistryService().pushImage(imageConfig, retries, skipTag, registryContext); + } } } diff --git a/src/main/java/io/fabric8/maven/docker/RemoveMojo.java b/src/main/java/io/fabric8/maven/docker/RemoveMojo.java index 8585c6b8a..33d5cf399 100644 --- a/src/main/java/io/fabric8/maven/docker/RemoveMojo.java +++ b/src/main/java/io/fabric8/maven/docker/RemoveMojo.java @@ -19,7 +19,7 @@ import io.fabric8.maven.docker.config.ImageConfiguration; import io.fabric8.maven.docker.service.QueryService; import io.fabric8.maven.docker.service.ServiceHub; -import io.fabric8.maven.docker.util.ImageName; +import io.fabric8.maven.docker.config.ImageName; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; @@ -52,13 +52,13 @@ public class RemoveMojo extends AbstractDockerMojo { @Parameter(property = "docker.removeMode") private String removeMode; - - /** + + /** * Skip building tags */ @Parameter(property = "docker.skip.tag", defaultValue = "false") private boolean skipTag; - + @Override protected void executeInternal(ServiceHub hub) throws DockerAccessException { for (ImageConfiguration image : getResolvedImages()) { diff --git a/src/main/java/io/fabric8/maven/docker/SaveMojo.java b/src/main/java/io/fabric8/maven/docker/SaveMojo.java index 7a89c2b2e..6a5c983f9 100644 --- a/src/main/java/io/fabric8/maven/docker/SaveMojo.java +++ b/src/main/java/io/fabric8/maven/docker/SaveMojo.java @@ -5,18 +5,17 @@ import java.util.List; import java.util.Properties; -import io.fabric8.maven.docker.config.ArchiveCompression; -import io.fabric8.maven.docker.util.ImageName; +import io.fabric8.maven.docker.access.DockerAccessException; +import io.fabric8.maven.docker.config.ImageConfiguration; +import io.fabric8.maven.docker.config.build.ArchiveCompression; +import io.fabric8.maven.docker.service.ServiceHub; +import io.fabric8.maven.docker.config.ImageName; import org.apache.maven.plugin.MojoExecutionException; 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.MavenProjectHelper; -import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.service.ServiceHub; - @Mojo(name = "save") public class SaveMojo extends AbstractDockerMojo { @@ -51,7 +50,7 @@ protected void executeInternal(ServiceHub serviceHub) throws DockerAccessExcepti throw new MojoExecutionException("No image " + imageName + " exists"); } - serviceHub.getDockerAccess().saveImage(imageName, fileName, ArchiveCompression.fromFileName(fileName)); + serviceHub.getDockerAccess().saveImage(imageName, fileName); } diff --git a/src/main/java/io/fabric8/maven/docker/SourceMojo.java b/src/main/java/io/fabric8/maven/docker/SourceMojo.java index c6acad3eb..8491664dd 100644 --- a/src/main/java/io/fabric8/maven/docker/SourceMojo.java +++ b/src/main/java/io/fabric8/maven/docker/SourceMojo.java @@ -17,17 +17,15 @@ */ import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; -import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.config.BuildImageConfiguration; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.BuildImageSelectMode; +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.config.build.BuildImageSelectMode; import io.fabric8.maven.docker.service.ServiceHub; -import io.fabric8.maven.docker.util.MojoParameters; - -import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; @@ -65,13 +63,13 @@ public class SourceMojo extends AbstractBuildSupportMojo { private BuildImageSelectMode sourceMode = BuildImageSelectMode.first; @Override - protected void executeInternal(ServiceHub hub) throws DockerAccessException, MojoExecutionException { - MojoParameters params = createMojoParameters(); + protected void executeInternal(ServiceHub hub) throws IOException { + MavenBuildContext context = getBuildContext(hub.getArchiveService()); List imageConfigs = new ArrayList<>(); for (ImageConfiguration imageConfig : getResolvedImages()) { - BuildImageConfiguration buildConfig = imageConfig.getBuildConfiguration(); + BuildConfiguration buildConfig = imageConfig.getBuildConfiguration(); if (buildConfig != null) { - if (buildConfig.skip()) { + if (buildConfig.getSkip() != null && buildConfig.getSkip()) { log.info("%s: Skipped creating source",imageConfig.getDescription()); } else { imageConfigs.add(imageConfig); @@ -80,12 +78,12 @@ protected void executeInternal(ServiceHub hub) throws DockerAccessException, Moj } if (sourceMode == BuildImageSelectMode.first && imageConfigs.size() > 0) { ImageConfiguration imageConfig = imageConfigs.get(0); - File dockerTar = hub.getArchiveService().createDockerBuildArchive(imageConfig, params); + File dockerTar = hub.getArchiveService().createDockerBuildArchive(imageConfig, context); projectHelper.attachArtifact(project, getArchiveType(imageConfig), getClassifier(null), dockerTar); } else { for (ImageConfiguration imageConfig : imageConfigs) { - File dockerTar = hub.getArchiveService().createDockerBuildArchive(imageConfig, params); + File dockerTar = hub.getArchiveService().createDockerBuildArchive(imageConfig, context); String alias = imageConfig.getAlias(); if (alias == null) { throw new IllegalArgumentException( diff --git a/src/main/java/io/fabric8/maven/docker/StartMojo.java b/src/main/java/io/fabric8/maven/docker/StartMojo.java index 85f473dcc..1b7d239f0 100644 --- a/src/main/java/io/fabric8/maven/docker/StartMojo.java +++ b/src/main/java/io/fabric8/maven/docker/StartMojo.java @@ -23,20 +23,22 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import com.google.common.util.concurrent.MoreExecutors; import io.fabric8.maven.docker.access.DockerAccessException; import io.fabric8.maven.docker.access.ExecException; import io.fabric8.maven.docker.access.PortMapping; +import io.fabric8.maven.docker.build.RegistryContext; +import io.fabric8.maven.docker.build.maven.MavenRegistryContext; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.NetworkConfig; -import io.fabric8.maven.docker.config.RunImageConfiguration; -import io.fabric8.maven.docker.config.RunVolumeConfiguration; -import io.fabric8.maven.docker.config.VolumeConfiguration; +import io.fabric8.maven.docker.config.build.ImagePullPolicy; +import io.fabric8.maven.docker.config.run.NetworkConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import io.fabric8.maven.docker.config.run.RunVolumeConfiguration; +import io.fabric8.maven.docker.config.run.VolumeConfiguration; import io.fabric8.maven.docker.log.LogDispatcher; -import io.fabric8.maven.docker.service.ImagePullManager; import io.fabric8.maven.docker.service.QueryService; -import io.fabric8.maven.docker.service.RegistryService; import io.fabric8.maven.docker.service.RunService; import io.fabric8.maven.docker.service.ServiceHub; import io.fabric8.maven.docker.service.helper.StartContainerExecutor; @@ -274,7 +276,7 @@ private void startImage(final ImageConfiguration imageConfig, final RunService runService = hub.getRunService(); final Properties projProperties = project.getProperties(); - final RunImageConfiguration runConfig = imageConfig.getRunConfiguration(); + final RunConfiguration runConfig = imageConfig.getRunConfiguration(); final PortMapping portMapping = runService.createPortMapping(runConfig, projProperties); final LogDispatcher dispatcher = getLogDispatcher(hub); @@ -315,7 +317,7 @@ private List getImagesWhoseDependenciesHasStarted(Queue allDependencies = imageWaitingToStart.getDependencies(); + List allDependencies = StartOrderResolver.getDependencies(imageWaitingToStart); List aliasDependencies = filterOutNonAliases(aliases, allDependencies); if (containersStarted.containsAll(aliasDependencies)) { ret.add(imageWaitingToStart); @@ -324,25 +326,33 @@ private List getImagesWhoseDependenciesHasStarted(Queue prepareStart(ServiceHub hub, QueryService queryService, RunService runService, Set imageAliases) - throws DockerAccessException, MojoExecutionException { + throws IOException { final Queue imagesWaitingToStart = new ArrayDeque<>(); - for (StartOrderResolver.Resolvable resolvable : runService.getImagesConfigsInOrder(queryService, getResolvedImages())) { - final ImageConfiguration imageConfig = (ImageConfiguration) resolvable; + for (ImageConfiguration imageConfig : runService.getImagesConfigsInOrder(getResolvedImages())) { // Still to check: How to work with linking, volumes, etc .... //String imageName = new ImageName(imageConfig.getName()).getFullNameWithTag(registry); - RunImageConfiguration runConfig = imageConfig.getRunConfiguration(); + RunConfiguration runConfig = imageConfig.getRunConfiguration(); + + if (runConfig.getSkip() != null && runConfig.getSkip()) { + log.info("%s: Skipped running", imageConfig.getDescription()); + continue; + } - RegistryService.RegistryConfig registryConfig = getRegistryConfig(pullRegistry); - ImagePullManager pullManager = getImagePullManager(determinePullPolicy(runConfig), autoPull); + String policyS = runConfig.getImagePullPolicy() != null ? runConfig.getImagePullPolicy() : this.imagePullPolicy; + ImagePullPolicy policy = policyS != null ? ImagePullPolicy.fromString(policyS) : ImagePullPolicy.IfNotPresent; - hub.getRegistryService().pullImageWithPolicy(imageConfig.getName(), pullManager, registryConfig, - queryService.hasImage(imageConfig.getName())); + RegistryContext registryContext = new MavenRegistryContext.Builder() + .pullRegistry(pullRegistry) + .authRegistryAuthFactory(registryAuthFactory) + .build(); + hub.getRegistryService().pullImage(imageConfig.getName(), policy, registryContext); - NetworkConfig config = runConfig.getNetworkingConfig(); + NetworkConfiguration config = runConfig.getNetworkingConfig(); List bindMounts = extractBindMounts(runConfig.getVolumeConfiguration()); List volumes = getVolumes(); if(!bindMounts.isEmpty() && volumes != null) { @@ -364,18 +374,10 @@ private List extractBindMounts(RunVolumeConfiguration volumeConfiguratio return volumeConfiguration.getBind() != null ? volumeConfiguration.getBind() : Collections.emptyList(); } - private String determinePullPolicy(RunImageConfiguration runConfig) { - return runConfig.getImagePullPolicy() != null ? runConfig.getImagePullPolicy() : imagePullPolicy; - } - private List filterOutNonAliases(Set imageAliases, List dependencies) { - List ret = new ArrayList<>(); - for (String alias : dependencies) { - if (imageAliases.contains(alias)) { - ret.add(alias); - } - } - return ret; + return dependencies.stream() + .filter(imageAliases::contains) + .collect(Collectors.toList()); } private ExecutorService getExecutorService() { diff --git a/src/main/java/io/fabric8/maven/docker/StopMojo.java b/src/main/java/io/fabric8/maven/docker/StopMojo.java index 46218c780..54567f4cb 100644 --- a/src/main/java/io/fabric8/maven/docker/StopMojo.java +++ b/src/main/java/io/fabric8/maven/docker/StopMojo.java @@ -9,7 +9,7 @@ import io.fabric8.maven.docker.access.ExecException; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.NetworkConfig; +import io.fabric8.maven.docker.config.run.NetworkConfiguration; import io.fabric8.maven.docker.log.LogDispatcher; import io.fabric8.maven.docker.model.Container; import io.fabric8.maven.docker.model.Network; @@ -125,7 +125,7 @@ private Set getNetworksToRemove(QueryService queryService, GavLabel gav for (ImageConfiguration image : getResolvedImages()) { - final NetworkConfig config = image.getRunConfiguration().getNetworkingConfig(); + final NetworkConfiguration config = image.getRunConfiguration().getNetworkingConfig(); if (!config.isCustomNetwork() || config.getName() == null) { continue; } diff --git a/src/main/java/io/fabric8/maven/docker/VolumeCreateMojo.java b/src/main/java/io/fabric8/maven/docker/VolumeCreateMojo.java index f437e699f..f225cfad7 100644 --- a/src/main/java/io/fabric8/maven/docker/VolumeCreateMojo.java +++ b/src/main/java/io/fabric8/maven/docker/VolumeCreateMojo.java @@ -2,7 +2,7 @@ import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.config.VolumeConfiguration; +import io.fabric8.maven.docker.config.run.VolumeConfiguration; import io.fabric8.maven.docker.service.ServiceHub; import io.fabric8.maven.docker.service.VolumeService; import org.apache.maven.plugin.MojoExecutionException; diff --git a/src/main/java/io/fabric8/maven/docker/VolumeRemoveMojo.java b/src/main/java/io/fabric8/maven/docker/VolumeRemoveMojo.java index 6b0976665..4e465c165 100644 --- a/src/main/java/io/fabric8/maven/docker/VolumeRemoveMojo.java +++ b/src/main/java/io/fabric8/maven/docker/VolumeRemoveMojo.java @@ -2,10 +2,9 @@ import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.config.VolumeConfiguration; +import io.fabric8.maven.docker.config.run.VolumeConfiguration; import io.fabric8.maven.docker.service.ServiceHub; import io.fabric8.maven.docker.service.VolumeService; - import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; diff --git a/src/main/java/io/fabric8/maven/docker/WatchMojo.java b/src/main/java/io/fabric8/maven/docker/WatchMojo.java index 04d4c0d64..5acd9850d 100644 --- a/src/main/java/io/fabric8/maven/docker/WatchMojo.java +++ b/src/main/java/io/fabric8/maven/docker/WatchMojo.java @@ -17,8 +17,8 @@ import java.io.IOException; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; import io.fabric8.maven.docker.config.WatchMode; -import io.fabric8.maven.docker.service.BuildService; import io.fabric8.maven.docker.service.ServiceHub; import io.fabric8.maven.docker.service.WatchService; import io.fabric8.maven.docker.util.ContainerNamingUtil; @@ -77,7 +77,7 @@ public class WatchMojo extends AbstractBuildSupportMojo { protected synchronized void executeInternal(ServiceHub hub) throws IOException, MojoExecutionException { - BuildService.BuildContext buildContext = getBuildContext(); + MavenBuildContext buildContext = getBuildContext(hub.getArchiveService()); WatchService.WatchContext watchContext = getWatchContext(hub); hub.getWatchService().watch(watchContext, buildContext, getResolvedImages()); @@ -94,12 +94,14 @@ protected WatchService.WatchContext getWatchContext(ServiceHub hub) throws IOExc .keepRunning(keepRunning) .removeVolumes(removeVolumes) .containerNamePattern(containerNamePattern) + .buildArgs(buildArgs) .buildTimestamp(getBuildTimestamp()) .pomLabel(getGavLabel()) - .mojoParameters(createMojoParameters()) .follow(follow()) .showLogs(showLogs()) .serviceHubFactory(serviceHubFactory) + .properties(project.getProperties()) + .basedir(project.getBasedir()) .hub(hub) .dispatcher(getLogDispatcher(hub)) .build(); diff --git a/src/main/java/io/fabric8/maven/docker/access/AuthConfig.java b/src/main/java/io/fabric8/maven/docker/access/AuthConfig.java deleted file mode 100644 index 4c8f317d9..000000000 --- a/src/main/java/io/fabric8/maven/docker/access/AuthConfig.java +++ /dev/null @@ -1,108 +0,0 @@ -package io.fabric8.maven.docker.access; - -import com.google.gson.JsonObject; - -import org.apache.commons.codec.binary.Base64; - -import java.io.UnsupportedEncodingException; -import java.util.Map; - -/** - * Configuration object holding auth information for - * pushing to Docker - * - * @author roland - * @since 22.07.14 - */ -public class AuthConfig { - - public final static AuthConfig EMPTY_AUTH_CONFIG = new AuthConfig("", "", "", ""); - - private final String username; - private final String password; - private final String email; - private final String auth; - - private final String authEncoded; - - public AuthConfig(Map params) { - this(params.get("username"), - params.get("password"), - params.get("email"), - params.get("auth")); - } - - public AuthConfig(String username, String password, String email, String auth) { - this.username = username; - this.password = password; - this.email = email; - this.auth = auth; - authEncoded = createAuthEncoded(); - } - - /** - * Constructor which takes an base64 encoded credentials in the form 'user:password' - * - * @param credentialsEncoded the docker encoded user and password - * @param email the email to use for authentication - */ - public AuthConfig(String credentialsEncoded, String email) { - String credentials = new String(Base64.decodeBase64(credentialsEncoded)); - String[] parsedCreds = credentials.split(":",2); - username = parsedCreds[0]; - password = parsedCreds[1]; - this.email = email; - auth = null; - authEncoded = createAuthEncoded(); - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public String getAuth() { - return auth; - } - - public String toHeaderValue() { - return authEncoded; - } - - // ====================================================================================================== - - private String createAuthEncoded() { - JsonObject ret = new JsonObject(); - putNonNull(ret, "username", username); - putNonNull(ret, "password", password); - putNonNull(ret, "email", email); - putNonNull(ret, "auth", auth); - try { - return encodeBase64ChunkedURLSafeString(ret.toString().getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - return encodeBase64ChunkedURLSafeString(ret.toString().getBytes()); - } - } - - /** - * Encodes the given binaryData in a format that is compatible with the Docker Engine API. - * That is, base64 encoded, padded, and URL safe. - * - * @param binaryData data to encode - * @return encoded data - */ - private String encodeBase64ChunkedURLSafeString(final byte[] binaryData) { - return Base64.encodeBase64String(binaryData) - .replace('+', '-') - .replace('/', '_'); - } - - private void putNonNull(JsonObject ret, String key, String value) { - if (value != null) { - ret.addProperty(key,value); - } - } -} \ No newline at end of file diff --git a/src/main/java/io/fabric8/maven/docker/access/ContainerCreateConfig.java b/src/main/java/io/fabric8/maven/docker/access/ContainerCreateConfig.java index 1c58128aa..f93103db8 100644 --- a/src/main/java/io/fabric8/maven/docker/access/ContainerCreateConfig.java +++ b/src/main/java/io/fabric8/maven/docker/access/ContainerCreateConfig.java @@ -1,10 +1,5 @@ package io.fabric8.maven.docker.access; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; - -import org.apache.commons.text.StrSubstitutor; - import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; @@ -14,9 +9,12 @@ import java.util.Properties; import java.util.Set; -import io.fabric8.maven.docker.config.Arguments; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import io.fabric8.maven.docker.config.build.Arguments; import io.fabric8.maven.docker.util.EnvUtil; import io.fabric8.maven.docker.util.JsonFactory; +import org.apache.commons.text.StrSubstitutor; public class ContainerCreateConfig { diff --git a/src/main/java/io/fabric8/maven/docker/access/ContainerHostConfig.java b/src/main/java/io/fabric8/maven/docker/access/ContainerHostConfig.java index d1e4df612..b02bda1f1 100644 --- a/src/main/java/io/fabric8/maven/docker/access/ContainerHostConfig.java +++ b/src/main/java/io/fabric8/maven/docker/access/ContainerHostConfig.java @@ -1,16 +1,15 @@ package io.fabric8.maven.docker.access; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; - import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.Map; -import io.fabric8.maven.docker.config.LogConfiguration; -import io.fabric8.maven.docker.config.UlimitConfig; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import io.fabric8.maven.docker.config.run.LogConfiguration; +import io.fabric8.maven.docker.config.run.UlimitConfiguration; import io.fabric8.maven.docker.util.EnvUtil; import io.fabric8.maven.docker.util.JsonFactory; @@ -104,10 +103,10 @@ public ContainerHostConfig volumesFrom(List volumesFrom) { return addAsArray("VolumesFrom", volumesFrom); } - public ContainerHostConfig ulimits(List ulimitsConfig) { + public ContainerHostConfig ulimits(List ulimitsConfig) { if (ulimitsConfig != null && ulimitsConfig.size() > 0) { JsonArray ulimits = new JsonArray(); - for (UlimitConfig ulimit : ulimitsConfig) { + for (UlimitConfiguration ulimit : ulimitsConfig) { JsonObject ulimitConfigJson = new JsonObject(); ulimitConfigJson.addProperty("Name", ulimit.getName()); addIfNotNull(ulimitConfigJson, "Hard", ulimit.getHard()); diff --git a/src/main/java/io/fabric8/maven/docker/access/ContainerNetworkingConfig.java b/src/main/java/io/fabric8/maven/docker/access/ContainerNetworkingConfig.java index c5127bd75..63145eb82 100644 --- a/src/main/java/io/fabric8/maven/docker/access/ContainerNetworkingConfig.java +++ b/src/main/java/io/fabric8/maven/docker/access/ContainerNetworkingConfig.java @@ -1,8 +1,7 @@ package io.fabric8.maven.docker.access; import com.google.gson.JsonObject; - -import io.fabric8.maven.docker.config.NetworkConfig; +import io.fabric8.maven.docker.config.run.NetworkConfiguration; import io.fabric8.maven.docker.util.JsonFactory; public class ContainerNetworkingConfig { @@ -15,7 +14,7 @@ public class ContainerNetworkingConfig { * @param config network config as configured in the pom.xml * @return this configuration */ - public ContainerNetworkingConfig aliases(NetworkConfig config) { + public ContainerNetworkingConfig aliases(NetworkConfiguration config) { JsonObject endPoints = new JsonObject(); endPoints.add("Aliases", JsonFactory.newJsonArray(config.getAliases())); diff --git a/src/main/java/io/fabric8/maven/docker/access/DockerAccess.java b/src/main/java/io/fabric8/maven/docker/access/DockerAccess.java index c37eea437..846c4a2a4 100644 --- a/src/main/java/io/fabric8/maven/docker/access/DockerAccess.java +++ b/src/main/java/io/fabric8/maven/docker/access/DockerAccess.java @@ -5,8 +5,6 @@ import io.fabric8.maven.docker.access.log.LogCallback; import io.fabric8.maven.docker.access.log.LogGetHandle; -import io.fabric8.maven.docker.config.ArchiveCompression; -import io.fabric8.maven.docker.config.Arguments; import io.fabric8.maven.docker.log.LogOutputSpec; import io.fabric8.maven.docker.model.Container; import io.fabric8.maven.docker.model.ContainerDetails; @@ -76,7 +74,7 @@ public interface DockerAccess { List getContainersForImage(String image, boolean all) throws DockerAccessException; /** - * Starts a previously set up exec instance (via {@link #createExecContainer(String, Arguments)} container + * Starts a previously set up exec instance (via {@link #createExecContainer(String, List)} container * this API sets up a session with the exec command. Output is streamed to the log. This methods * returns only when the exec command has finished (i.e this method calls the command in a non-detached mode). * @@ -93,7 +91,7 @@ public interface DockerAccess { * @param arguments container exec commands to run * @throws DockerAccessException if the container could not be created. */ - String createExecContainer(String containerId, Arguments arguments) throws DockerAccessException; + String createExecContainer(String containerId, List arguments) throws DockerAccessException; /** * Create a container from the given image. @@ -175,11 +173,11 @@ void copyArchive(String containerId, File archive, String targetPath) * Pull an image from a remote registry and store it locally. * * @param image the image to pull. - * @param authConfig authentication configuration used when pulling an image + * @param authHeader authentication configuration used when pulling an image * @param registry an optional registry from where to pull the image. Can be null. * @throws DockerAccessException if the image couldn't be pulled. */ - void pullImage(String image, AuthConfig authConfig, String registry) throws DockerAccessException; + void pullImage(String image, String authHeader, String registry) throws DockerAccessException; /** * Push an image to a registry. An registry can be specified which is used as target @@ -189,12 +187,12 @@ void copyArchive(String containerId, File archive, String targetPath) * part (if not already existent) * * @param image image name to push - * @param authConfig authentication configuration + * @param authHeader authentication configuration * @param registry optional registry to which the image should be pushed. * @param retries optional number of times the push should be retried on a 500 error * @throws DockerAccessException in case pushing fails */ - void pushImage(String image, AuthConfig authConfig, String registry, int retries) throws DockerAccessException; + void pushImage(String image, String authHeader, String registry, int retries) throws DockerAccessException; /** * Create an docker image from a given archive @@ -232,10 +230,9 @@ void copyArchive(String containerId, File archive, String targetPath) * * @param image image to save * @param filename target filename - * @param compression compression to use for the archive * @throws DockerAccessException if an image cannot be removed */ - void saveImage(String image, String filename, ArchiveCompression compression) throws DockerAccessException; + void saveImage(String image, String filename) throws DockerAccessException; /** * List all networks diff --git a/src/main/java/io/fabric8/maven/docker/access/UrlBuilder.java b/src/main/java/io/fabric8/maven/docker/access/UrlBuilder.java index afe223d3f..a588b7e31 100644 --- a/src/main/java/io/fabric8/maven/docker/access/UrlBuilder.java +++ b/src/main/java/io/fabric8/maven/docker/access/UrlBuilder.java @@ -10,7 +10,7 @@ import java.util.Map; import java.util.TreeSet; -import io.fabric8.maven.docker.util.ImageName; +import io.fabric8.maven.docker.config.ImageName; public final class UrlBuilder { @@ -139,7 +139,7 @@ public String stopContainer(String containerId, int killWait) { return b.build(); } - public String tagContainer(ImageName source, ImageName target, boolean force) { + public String tagImage(ImageName source, ImageName target, boolean force) { return u("images/%s/tag", source.getFullName()) .p("repo",target.getNameWithoutTag()) .p("tag",target.getTag()) diff --git a/src/main/java/io/fabric8/maven/docker/access/hc/DockerAccessWithHcClient.java b/src/main/java/io/fabric8/maven/docker/access/hc/DockerAccessWithHcClient.java index f9d770917..18b7fa60f 100644 --- a/src/main/java/io/fabric8/maven/docker/access/hc/DockerAccessWithHcClient.java +++ b/src/main/java/io/fabric8/maven/docker/access/hc/DockerAccessWithHcClient.java @@ -23,8 +23,11 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.zip.GZIPOutputStream; -import io.fabric8.maven.docker.access.AuthConfig; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import io.fabric8.maven.docker.access.BuildOptions; import io.fabric8.maven.docker.access.ContainerCreateConfig; import io.fabric8.maven.docker.access.DockerAccess; @@ -44,8 +47,6 @@ import io.fabric8.maven.docker.access.log.LogCallback; import io.fabric8.maven.docker.access.log.LogGetHandle; import io.fabric8.maven.docker.access.log.LogRequestor; -import io.fabric8.maven.docker.config.ArchiveCompression; -import io.fabric8.maven.docker.config.Arguments; import io.fabric8.maven.docker.log.DefaultLogCallback; import io.fabric8.maven.docker.log.LogOutputSpec; import io.fabric8.maven.docker.model.Container; @@ -55,10 +56,15 @@ import io.fabric8.maven.docker.model.Network; import io.fabric8.maven.docker.model.NetworksListElement; import io.fabric8.maven.docker.util.EnvUtil; +import io.fabric8.maven.docker.config.ImageName; import io.fabric8.maven.docker.util.JsonFactory; -import io.fabric8.maven.docker.util.ImageName; import io.fabric8.maven.docker.util.Logger; import io.fabric8.maven.docker.util.Timestamp; +import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; @@ -186,14 +192,14 @@ public Object handleResponse(HttpResponse response) throws IOException { } @Override - public String createExecContainer(String containerId, Arguments arguments) throws DockerAccessException { + public String createExecContainer(String containerId, List arguments) throws DockerAccessException { String url = urlBuilder.createExecContainer(containerId); JsonObject request = new JsonObject(); request.addProperty("Tty", true); request.addProperty("AttachStdin", false); request.addProperty("AttachStdout", true); request.addProperty("AttachStderr", true); - request.add("Cmd", JsonFactory.newJsonArray(arguments.getExec())); + request.add("Cmd", JsonFactory.newJsonArray(arguments)); String execJsonRequest = request.toString(); try { @@ -406,28 +412,27 @@ public void loadImage(String image, File tarArchive) throws DockerAccessExceptio } @Override - public void pullImage(String image, AuthConfig authConfig, String registry) + public void pullImage(String image, String authHeader, String registry) throws DockerAccessException { ImageName name = new ImageName(image); String pullUrl = urlBuilder.pullImage(name, registry); try { - delegate.post(pullUrl, null, createAuthHeader(authConfig), - createPullOrPushResponseHandler(), HTTP_OK); + delegate.post(pullUrl, null, createAuthHeader(authHeader), createPullOrPushResponseHandler(), HTTP_OK); } catch (IOException e) { throw new DockerAccessException(e, "Unable to pull '%s'%s", image, (registry != null) ? " from registry '" + registry + "'" : ""); } } @Override - public void pushImage(String image, AuthConfig authConfig, String registry, int retries) + public void pushImage(String image, String authHeader, String registry, int retries) throws DockerAccessException { ImageName name = new ImageName(image); String pushUrl = urlBuilder.pushImage(name, registry); String temporaryImage = tagTemporaryImage(name, registry); DockerAccessException dae = null; try { - doPushImage(pushUrl, createAuthHeader(authConfig), createPullOrPushResponseHandler(), HTTP_OK, retries); + doPushImage(pushUrl, createAuthHeader(authHeader), createPullOrPushResponseHandler(), HTTP_OK, retries); } catch (IOException e) { dae = new DockerAccessException(e, "Unable to push '%s'%s", image, (registry != null) ? " to registry '" + registry + "'" : ""); throw dae; @@ -445,27 +450,37 @@ public void pushImage(String image, AuthConfig authConfig, String registry, int } @Override - public void saveImage(String image, String filename, ArchiveCompression compression) throws DockerAccessException { + public void saveImage(String image, String filename) throws DockerAccessException { ImageName name = new ImageName(image); String url = urlBuilder.getImage(name); try { - delegate.get(url, getImageResponseHandler(filename, compression), HTTP_OK); + delegate.get(url, getImageResponseHandler(filename), HTTP_OK); } catch (IOException e) { throw new DockerAccessException(e, "Unable to save '%s' to '%s'", image, filename); } } - private ResponseHandler getImageResponseHandler(final String filename, final ArchiveCompression compression) throws FileNotFoundException { - return new ResponseHandler() { - @Override - public Object handleResponse(HttpResponse response) throws IOException { - try (InputStream stream = response.getEntity().getContent(); - OutputStream out = compression.wrapOutputStream(new FileOutputStream(filename))) { + private ResponseHandler getImageResponseHandler(final String filename) throws FileNotFoundException { + return response -> { + OutputStream fout = new FileOutputStream(filename); + OutputStream out; + if (filename.endsWith(".tar.gz") || filename.endsWith(".tgz")) { + out = new GZIPOutputStream(fout); + } else if (filename.endsWith(".tar.bz") || filename.endsWith(".tar.bzip2") || filename.endsWith(".tar.bz2")) { + out = new BZip2CompressorOutputStream(fout); + } else { + out = fout; + } + + try { + try (InputStream stream = response.getEntity().getContent()) { IOUtils.copy(stream, out); } - return null; + } finally { + out.close(); } + return null; }; } @@ -475,7 +490,7 @@ public void tag(String sourceImage, String targetImage, boolean force) ImageName source = new ImageName(sourceImage); ImageName target = new ImageName(targetImage); try { - String url = urlBuilder.tagContainer(source, target, force); + String url = urlBuilder.tagImage(source, target, force); delegate.post(url, HTTP_CREATED); } catch (IOException e) { throw new DockerAccessException(e, "Unable to add tag [%s] to image [%s]", targetImage, @@ -624,11 +639,8 @@ private HcChunkedResponseHandlerWrapper createPullOrPushResponseHandler() { return new HcChunkedResponseHandlerWrapper(new PullOrPushResponseJsonHandler(log)); } - private Map createAuthHeader(AuthConfig authConfig) { - if (authConfig == null) { - authConfig = AuthConfig.EMPTY_AUTH_CONFIG; - } - return Collections.singletonMap("X-Registry-Auth", authConfig.toHeaderValue()); + private Map createAuthHeader(String authConfig) { + return Collections.singletonMap("X-Registry-Auth", authConfig); } private boolean isRetryableErrorCode(int errorCode) { diff --git a/src/main/java/io/fabric8/maven/docker/access/util/EnvCommand.java b/src/main/java/io/fabric8/maven/docker/access/util/EnvCommand.java index 89e2ec732..de2079cd7 100644 --- a/src/main/java/io/fabric8/maven/docker/access/util/EnvCommand.java +++ b/src/main/java/io/fabric8/maven/docker/access/util/EnvCommand.java @@ -30,7 +30,7 @@ * * @since 14/09/16 */ -abstract public class EnvCommand extends ExternalCommand { +public abstract class EnvCommand extends ExternalCommand { private final Map env = new HashMap<>(); @@ -51,11 +51,11 @@ protected void processLine(String line) { } } - private final Pattern ENV_VAR_PATTERN = Pattern.compile("^\\s*(?[^=]+)=\"?(?.*?)\"?\\s*$"); + private final Pattern envVarPattern = Pattern.compile("^\\s*(?[^=]+)=\"?(?.*?)\"?\\s*$"); // parse line like SET DOCKER_HOST=tcp://192.168.99.100:2376 private void setEnvironmentVariable(String line) { - Matcher matcher = ENV_VAR_PATTERN.matcher(line); + Matcher matcher = envVarPattern.matcher(line); if (matcher.matches()) { String key = matcher.group("key"); String value = matcher.group("value"); diff --git a/src/main/java/io/fabric8/maven/docker/access/util/ExternalCommand.java b/src/main/java/io/fabric8/maven/docker/access/util/ExternalCommand.java index 5f22a8425..ffc9aee6f 100644 --- a/src/main/java/io/fabric8/maven/docker/access/util/ExternalCommand.java +++ b/src/main/java/io/fabric8/maven/docker/access/util/ExternalCommand.java @@ -20,7 +20,7 @@ import java.util.concurrent.*; import io.fabric8.maven.docker.util.Logger; -import org.apache.maven.shared.utils.StringUtils; +import org.apache.commons.lang3.StringUtils; /** * @author roland diff --git a/src/main/java/io/fabric8/maven/docker/build/BuildContext.java b/src/main/java/io/fabric8/maven/docker/build/BuildContext.java new file mode 100644 index 000000000..70584c19c --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/BuildContext.java @@ -0,0 +1,30 @@ +package io.fabric8.maven.docker.build; + +import java.io.File; +import java.io.IOException; +import java.util.Properties; +import java.util.function.Function; + +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.util.Logger; + +/** + * @author roland + * @since 16.10.18 + */ +public interface BuildContext { + + String getSourceDirectory(); + + File getBasedir(); + + String getOutputDirectory(); + + Properties getProperties(); + + Function createInterpolator(String filter); + + File createImageContentArchive(String imageName, BuildConfiguration buildConfig, Logger log) throws IOException; + + RegistryContext getRegistryContext(); +} diff --git a/src/main/java/io/fabric8/maven/docker/build/BuildService.java b/src/main/java/io/fabric8/maven/docker/build/BuildService.java new file mode 100644 index 000000000..c04ad2f2d --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/BuildService.java @@ -0,0 +1,15 @@ +package io.fabric8.maven.docker.build; + +import java.io.IOException; +import java.util.Map; + +import io.fabric8.maven.docker.config.ImageConfiguration; + +/** + * @author roland + * @since 16.10.18 + */ +public interface BuildService { + void buildImage(ImageConfiguration imageConfig, BuildContext buildContext, Map buildArgs) + throws IOException; +} diff --git a/src/main/java/io/fabric8/maven/docker/build/RegistryContext.java b/src/main/java/io/fabric8/maven/docker/build/RegistryContext.java new file mode 100644 index 000000000..df9974db6 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/RegistryContext.java @@ -0,0 +1,21 @@ +package io.fabric8.maven.docker.build; + +import java.io.IOException; + +import io.fabric8.maven.docker.build.auth.RegistryAuth; +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig; +import io.fabric8.maven.docker.config.build.ImagePullPolicy; + +/** + * @author roland + * @since 17.10.18 + */ +public interface RegistryContext { + + ImagePullPolicy getDefaultImagePullPolicy(); + + String getRegistry(RegistryAuthConfig.Kind kind); + + RegistryAuth getAuthConfig(RegistryAuthConfig.Kind kind, String user, String registry) throws IOException; + +} diff --git a/src/main/java/io/fabric8/maven/docker/build/RegistryService.java b/src/main/java/io/fabric8/maven/docker/build/RegistryService.java new file mode 100644 index 000000000..2a0527234 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/RegistryService.java @@ -0,0 +1,16 @@ +package io.fabric8.maven.docker.build; + +import java.io.IOException; + +import io.fabric8.maven.docker.config.ImageConfiguration; +import io.fabric8.maven.docker.config.build.ImagePullPolicy; + +/** + * @author roland + * @since 17.10.18 + */ +public interface RegistryService { + void pushImage(ImageConfiguration imageConfig, int retries, boolean skipTag, RegistryContext registryContext) throws IOException; + + void pullImage(String image, ImagePullPolicy policy, RegistryContext registryContext) throws IOException; +} diff --git a/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuth.java b/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuth.java new file mode 100644 index 000000000..4dd7b9d2a --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuth.java @@ -0,0 +1,141 @@ +package io.fabric8.maven.docker.build.auth; + +import java.io.UnsupportedEncodingException; +import java.util.Optional; +import java.util.function.Function; + +import com.google.gson.JsonObject; +import java.util.Base64; + +/** + * Configuration object holding auth information for + * pushing to Docker + * + * @author roland + * @since 22.07.14 + */ +public class RegistryAuth { + + public final static RegistryAuth EMPTY_REGISTRY_AUTH = + new RegistryAuth.Builder().username("").password("").email("").auth("").build(); + + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; + public static final String EMAIL = "email"; + public static final String AUTH = "authToken"; + + private String username, password, email, auth, authEncoded; + + private RegistryAuth() { } + + public static RegistryAuth fromRegistryAuthConfig(RegistryAuthConfig registryAuthConfig, + RegistryAuthConfig.Kind kind, + Function decryptor) { + return new Builder() + .username(registryAuthConfig.getUsername(kind)) + .email(registryAuthConfig.getEmail(kind)) + .auth(registryAuthConfig.getAuth(kind)) + .password(registryAuthConfig.getPassword(kind), decryptor) + .build(); + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getAuth() { + return auth; + } + + public String toHeaderValue() { + return authEncoded; + } + + // ====================================================================================================== + + public static class Builder { + RegistryAuth registryAuth; + + public Builder() { + registryAuth = new RegistryAuth(); + } + + public Builder username(String username) { + registryAuth.username = username; + return this; + } + + public Builder password(String password) { + return password(password, null); + } + + public Builder password(String password, Function decryptor) { + registryAuth.password = + Optional.ofNullable(decryptor).map(d -> d.apply(password)).orElse(password); + return this; + } + + public Builder email(String email) { + registryAuth.email = email; + return this; + } + + public Builder auth(String auth) { + registryAuth.auth = auth; + return this; + } + + public Builder withCredentialsEncoded(String creds) { + String credentials = new String(Base64.getDecoder().decode(creds)); + String[] parsedCreds = credentials.split(":",2); + registryAuth.username = parsedCreds[0]; + registryAuth.password = parsedCreds[1]; + return this; + } + + + public RegistryAuth build() { + registryAuth.authEncoded = registryAuth.createAuthEncoded(); + return registryAuth; + } + } + + + // ====================================================================================================== + + private String createAuthEncoded() { + JsonObject ret = new JsonObject(); + putNonNull(ret, USERNAME, username); + putNonNull(ret, PASSWORD, password); + putNonNull(ret, EMAIL, email); + putNonNull(ret, AUTH, auth); + try { + return encodeBase64ChunkedURLSafeString(ret.toString().getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + return encodeBase64ChunkedURLSafeString(ret.toString().getBytes()); + } + } + + /** + * Encodes the given binaryData in a format that is compatible with the Docker Engine API. + * That is, base64 encoded, padded, and URL safe. + * + * @param binaryData data to encode + * @return encoded data + */ + private String encodeBase64ChunkedURLSafeString(final byte[] binaryData) { + return Base64.getEncoder().encodeToString(binaryData) + .replace('+', '-') + .replace('/', '_'); + } + + private void putNonNull(JsonObject ret, String key, String value) { + if (value != null) { + ret.addProperty(key,value); + } + } +} \ No newline at end of file diff --git a/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuthConfig.java b/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuthConfig.java new file mode 100644 index 000000000..6efcac42d --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuthConfig.java @@ -0,0 +1,110 @@ +package io.fabric8.maven.docker.build.auth; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + +/** + * @author roland + * @since 22.10.18 + */ +public class RegistryAuthConfig { + + private Map> handlerConfig = new HashMap<>(); + private Map> kindConfig = new HashMap<>(); + private Map defaultConfig = new HashMap<>(); + + private boolean skipExtendedAuthentication = false; + + private String propertyPrefix; + + private RegistryAuthConfig() { } + + public String getConfigForHandler(String handlerName, String key) { + return Optional.ofNullable(handlerConfig.get(handlerName)).map(m -> m.get(key)).orElse(null); + } + + public String getUsername(Kind kind) { + return getValueWithFallback(kind, RegistryAuth.USERNAME); + } + + public String getPassword(Kind kind) { + return getValueWithFallback(kind, RegistryAuth.PASSWORD); + } + + public String getEmail(Kind kind) { + return getValueWithFallback(kind, RegistryAuth.EMAIL); + } + + public String getAuth(Kind kind) { + return getValueWithFallback(kind, RegistryAuth.AUTH); + } + + private String getValueWithFallback(Kind kind, String key) { + return Optional.ofNullable(kindConfig.get(kind)).map(m -> m.get(key)).orElse(defaultConfig.get(key)); + } + + public boolean skipExtendedAuthentication() { + return skipExtendedAuthentication; + } + + public String extractFromProperties(Properties properties, Kind kind, String key) { + String value = properties.getProperty(propertyPrefix + "." + kind.name().toLowerCase() + "." + key); + if (value != null) { + return value; + } + // Default is without kind + return properties.getProperty(propertyPrefix + "." + key); + } + + + public static class Builder { + + private final RegistryAuthConfig config; + + public Builder() { + config = new RegistryAuthConfig(); + } + + public Builder addKindConfig(Kind kind, String key, String value) { + config.kindConfig.computeIfAbsent(kind, k -> new HashMap<>()).put(key, value); + return this; + } + + public Builder addDefaultConfig(String key, String value) { + if (value != null) { + config.defaultConfig.put(key, value); + } + return this; + } + + public Builder addHandlerConfig(String id, String key, String value) { + if (value != null) { + config.handlerConfig.computeIfAbsent(id, i -> new HashMap<>()).put(key, value); + } + return this; + } + + public Builder skipExtendedAuthentication(boolean skipExtendedAuthentication) { + config.skipExtendedAuthentication = skipExtendedAuthentication; + return this; + } + + public Builder propertyPrefix(String propertyPrefix) { + config.propertyPrefix = propertyPrefix; + return this; + } + + public RegistryAuthConfig build() { + return config; + } + } + + // ======================================================================================== + + public enum Kind { + PUSH, + PULL; + } +} diff --git a/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuthFactory.java b/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuthFactory.java new file mode 100644 index 000000000..b6a4142a5 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuthFactory.java @@ -0,0 +1,110 @@ +package io.fabric8.maven.docker.build.auth; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig.Kind; +import io.fabric8.maven.docker.util.Logger; + + +/** + * Factory for creating docker specific authentication configuration + * + * @author roland + * @since 29.07.14 + */ +public class RegistryAuthFactory { + + private RegistryAuthConfig registryAuthConfig; + private String defaultRegistry; + + private Logger log; + private final List registryAuthHandlers = new ArrayList<>(); + private final List extendedRegistryAuthHandlers = new ArrayList<>(); + + private Function decryptor; + + private RegistryAuthFactory() { } + + public RegistryAuth createAuthConfig(Kind kind, String user, String specificRegistry) throws IOException { + String registry = specificRegistry != null ? specificRegistry : defaultRegistry; + Optional ret = createRegistryAuthFromHandlers(kind, user, registry); + + if (ret.isPresent()) { + if (registry == null || registryAuthConfig.skipExtendedAuthentication()) { + return ret.get(); + } + return extendRegistryAuth(registry, ret.get()).orElse(ret.get()); + } + + log.debug("RegistryAuthFactoryg: no credentials found"); + return RegistryAuth.EMPTY_REGISTRY_AUTH; + } + + private Optional createRegistryAuthFromHandlers(Kind kind, String user, String registry) { + for (RegistryAuthHandler handler : registryAuthHandlers) { + RegistryAuth ret = handler.create(kind, user, registry, decryptor); + if (ret != null) { + return Optional.of(ret); + } + } + return Optional.empty(); + } + + private Optional extendRegistryAuth(String registry, RegistryAuth ret) throws IOException { + for (RegistryAuthHandler.Extender extended : extendedRegistryAuthHandlers) { + RegistryAuth extendedRet = extended.extend(ret, registry); + if (extendedRet != null) { + return Optional.of(extendedRet); + } + } + return Optional.empty(); + } + + // ================================================================================================== + + public static class Builder { + + private RegistryAuthFactory factory; + + public Builder() { + factory = new RegistryAuthFactory(); + } + + public Builder addRegistryAuthHandler(RegistryAuthHandler registryAuthHandler) { + factory.registryAuthHandlers.add(registryAuthHandler); + return this; + } + + public Builder addExtendedRegistryAuthHandler(RegistryAuthHandler.Extender extendedRegistryAuthHandler) { + factory.extendedRegistryAuthHandlers.add(extendedRegistryAuthHandler); + return this; + } + + public Builder registryAuthConfig(RegistryAuthConfig registryAuthConfig) { + factory.registryAuthConfig = registryAuthConfig; + return this; + } + + public Builder log(Logger log) { + factory.log = log; + return this; + } + + public Builder defaultRegistry(String defaultRegistry) { + factory.defaultRegistry = defaultRegistry; + return this; + } + + public Builder decryptor(Function decryptor) { + factory.decryptor = decryptor; + return this; + } + public RegistryAuthFactory build() { + return factory; + } + } +} diff --git a/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuthHandler.java b/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuthHandler.java new file mode 100644 index 000000000..52e8aa8c5 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/auth/RegistryAuthHandler.java @@ -0,0 +1,36 @@ +package io.fabric8.maven.docker.build.auth; + +import java.io.IOException; +import java.util.function.Function; + +/** + * @author roland + * @since 21.10.18 + */ +public interface RegistryAuthHandler { + + String getId(); + + RegistryAuth create(RegistryAuthConfig.Kind kind, String user, String registry, Function decryptor); + + interface Extender { + String getId(); + RegistryAuth extend(RegistryAuth given, String registry) throws IOException; + } +} + + + + + + + + + + + + + + + + diff --git a/src/main/java/io/fabric8/maven/docker/build/auth/extended/EcrExtendedRegistryAuthHandler.java b/src/main/java/io/fabric8/maven/docker/build/auth/extended/EcrExtendedRegistryAuthHandler.java new file mode 100644 index 000000000..b648551f7 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/auth/extended/EcrExtendedRegistryAuthHandler.java @@ -0,0 +1,34 @@ +package io.fabric8.maven.docker.build.auth.extended; + +import java.io.IOException; + +import io.fabric8.maven.docker.build.auth.RegistryAuth; +import io.fabric8.maven.docker.build.auth.RegistryAuthHandler; +import io.fabric8.maven.docker.build.auth.extended.ecr.EcrExtendedAuth; +import io.fabric8.maven.docker.util.Logger; + +/** + * @author roland + * @since 21.10.18 + */ +public class EcrExtendedRegistryAuthHandler implements RegistryAuthHandler.Extender { + + private final Logger log; + + public EcrExtendedRegistryAuthHandler(Logger log) { + this.log = log; + } + + @Override + public String getId() { + return "ecr"; + } + + public RegistryAuth extend(RegistryAuth given, String registry) throws IOException { + EcrExtendedAuth ecr = new EcrExtendedAuth(log, registry); + if (ecr.isAwsRegistry()) { + return ecr.extendedAuth(given); + } + return given; + } +} diff --git a/src/main/java/io/fabric8/maven/docker/access/ecr/AwsSigner4.java b/src/main/java/io/fabric8/maven/docker/build/auth/extended/ecr/AwsSigner4.java similarity index 93% rename from src/main/java/io/fabric8/maven/docker/access/ecr/AwsSigner4.java rename to src/main/java/io/fabric8/maven/docker/build/auth/extended/ecr/AwsSigner4.java index 4bc3a6b3d..414f867a7 100644 --- a/src/main/java/io/fabric8/maven/docker/access/ecr/AwsSigner4.java +++ b/src/main/java/io/fabric8/maven/docker/build/auth/extended/ecr/AwsSigner4.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.access.ecr; +package io.fabric8.maven.docker.build.auth.extended.ecr; import java.net.URI; import java.nio.charset.StandardCharsets; @@ -17,7 +17,7 @@ import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; -import io.fabric8.maven.docker.access.AuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuth; import org.codehaus.plexus.util.StringUtils; /** @@ -52,7 +52,7 @@ class AwsSigner4 { * @param credentials The credentials to use when signing. * @param signingTime The invocation time to use; */ - void sign(HttpRequest request, AuthConfig credentials, Date signingTime) { + void sign(HttpRequest request, RegistryAuth credentials, Date signingTime) { AwsSigner4Request sr = new AwsSigner4Request(region, service, request, signingTime); if(!request.containsHeader("X-Amz-Date")) { request.addHeader("X-Amz-Date", sr.getSigningDateTime()); @@ -95,11 +95,11 @@ String task2(AwsSigner4Request sr) { * Task 3. * Calculate the Signature for AWS Signature Version 4 */ - final byte[] task3(AwsSigner4Request sr, AuthConfig credentials) { + final byte[] task3(AwsSigner4Request sr, RegistryAuth credentials) { return hmacSha256(getSigningKey(sr, credentials), task2(sr)); } - private static byte[] getSigningKey(AwsSigner4Request sr, AuthConfig credentials) { + private static byte[] getSigningKey(AwsSigner4Request sr, RegistryAuth credentials) { byte[] kSecret = ("AWS4" + credentials.getPassword()).getBytes(StandardCharsets.UTF_8); byte[] kDate = hmacSha256(kSecret, sr.getSigningDate()); byte[] kRegion = hmacSha256(kDate, sr.getRegion()); @@ -111,7 +111,7 @@ private static byte[] getSigningKey(AwsSigner4Request sr, AuthConfig credentials * Task 4. * Add the Signing Information to the Request */ - String task4(AwsSigner4Request sr, AuthConfig credentials) { + String task4(AwsSigner4Request sr, RegistryAuth credentials) { StringBuilder sb = new StringBuilder("AWS4-HMAC-SHA256 Credential=") .append(credentials.getUsername() ).append( '/' ).append( sr.getScope() ) .append(", SignedHeaders=").append(sr.getSignedHeaders()) diff --git a/src/main/java/io/fabric8/maven/docker/access/ecr/AwsSigner4Request.java b/src/main/java/io/fabric8/maven/docker/build/auth/extended/ecr/AwsSigner4Request.java similarity index 99% rename from src/main/java/io/fabric8/maven/docker/access/ecr/AwsSigner4Request.java rename to src/main/java/io/fabric8/maven/docker/build/auth/extended/ecr/AwsSigner4Request.java index 4cceab45d..137d140a0 100644 --- a/src/main/java/io/fabric8/maven/docker/access/ecr/AwsSigner4Request.java +++ b/src/main/java/io/fabric8/maven/docker/build/auth/extended/ecr/AwsSigner4Request.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.access.ecr; +package io.fabric8.maven.docker.build.auth.extended.ecr; import java.io.IOException; import java.lang.reflect.UndeclaredThrowableException; diff --git a/src/main/java/io/fabric8/maven/docker/access/ecr/EcrExtendedAuth.java b/src/main/java/io/fabric8/maven/docker/build/auth/extended/ecr/EcrExtendedAuth.java similarity index 87% rename from src/main/java/io/fabric8/maven/docker/access/ecr/EcrExtendedAuth.java rename to src/main/java/io/fabric8/maven/docker/build/auth/extended/ecr/EcrExtendedAuth.java index 03791aa95..7188ea40c 100644 --- a/src/main/java/io/fabric8/maven/docker/access/ecr/EcrExtendedAuth.java +++ b/src/main/java/io/fabric8/maven/docker/build/auth/extended/ecr/EcrExtendedAuth.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.access.ecr; +package io.fabric8.maven.docker.build.auth.extended.ecr; import com.google.gson.Gson; import com.google.gson.JsonArray; @@ -21,7 +21,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import io.fabric8.maven.docker.access.AuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuth; import io.fabric8.maven.docker.util.Logger; /** @@ -76,17 +76,17 @@ public boolean isAwsRegistry() { * @throws IOException * @throws MojoExecutionException */ - public AuthConfig extendedAuth(AuthConfig localCredentials) throws IOException, MojoExecutionException { + public RegistryAuth extendedAuth(RegistryAuth localCredentials) throws IOException { JsonObject jo = getAuthorizationToken(localCredentials); JsonArray authorizationDatas = jo.getAsJsonArray("authorizationData"); JsonObject authorizationData = authorizationDatas.get(0).getAsJsonObject(); String authorizationToken = authorizationData.get("authorizationToken").getAsString(); - return new AuthConfig(authorizationToken, "none"); + return new RegistryAuth.Builder().withCredentialsEncoded(authorizationToken).email("none").build(); } - private JsonObject getAuthorizationToken(AuthConfig localCredentials) throws IOException, MojoExecutionException { + private JsonObject getAuthorizationToken(RegistryAuth localCredentials) throws IOException { HttpPost request = createSignedRequest(localCredentials, new Date()); return executeRequest(createClient(), request); } @@ -95,13 +95,13 @@ CloseableHttpClient createClient() { return HttpClients.custom().useSystemProperties().build(); } - private JsonObject executeRequest(CloseableHttpClient client, HttpPost request) throws IOException, MojoExecutionException { + private JsonObject executeRequest(CloseableHttpClient client, HttpPost request) throws IOException { try { CloseableHttpResponse response = client.execute(request); int statusCode = response.getStatusLine().getStatusCode(); logger.debug("Response status %d", statusCode); if (statusCode != HttpStatus.SC_OK) { - throw new MojoExecutionException("AWS authentication failure"); + throw new SecurityException("AWS authentication failure"); } HttpEntity entity = response.getEntity(); @@ -113,7 +113,7 @@ private JsonObject executeRequest(CloseableHttpClient client, HttpPost request) } } - HttpPost createSignedRequest(AuthConfig localCredentials, Date time) { + HttpPost createSignedRequest(RegistryAuth localCredentials, Date time) { String host = "ecr." + region + ".amazonaws.com"; logger.debug("Get ECR AuthorizationToken from %s", host); diff --git a/src/main/java/io/fabric8/maven/docker/build/auth/handler/FromConfigRegistryAuthHandler.java b/src/main/java/io/fabric8/maven/docker/build/auth/handler/FromConfigRegistryAuthHandler.java new file mode 100644 index 000000000..0b8a28ea0 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/auth/handler/FromConfigRegistryAuthHandler.java @@ -0,0 +1,42 @@ +package io.fabric8.maven.docker.build.auth.handler; + +import java.util.function.Function; + +import io.fabric8.maven.docker.build.auth.RegistryAuth; +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuthHandler; +import io.fabric8.maven.docker.util.Logger; + +/** + * @author roland + * @since 21.10.18 + */ +public class FromConfigRegistryAuthHandler implements RegistryAuthHandler { + private final RegistryAuthConfig registryAuthConfig; + private final Logger log; + + public FromConfigRegistryAuthHandler(RegistryAuthConfig registryAuthConfig, Logger log) { + this.registryAuthConfig = registryAuthConfig; + this.log = log; + } + + @Override + public String getId() { + return "config"; + } + + @Override + public RegistryAuth create(RegistryAuthConfig.Kind kind, String user, String registry, Function decryptor) { + // Get configuration from global plugin config + + if (registryAuthConfig.getUsername(kind) != null) { + if (registryAuthConfig.getPassword(kind) == null) { + throw new IllegalArgumentException("No 'password' given while using in configuration for mode " + kind); + } + log.debug("AuthConfig: credentials from plugin config"); + return RegistryAuth.fromRegistryAuthConfig(registryAuthConfig, kind, decryptor); + } + return null; + } + +} diff --git a/src/main/java/io/fabric8/maven/docker/build/auth/handler/OpenShiftRegistryAuthHandler.java b/src/main/java/io/fabric8/maven/docker/build/auth/handler/OpenShiftRegistryAuthHandler.java new file mode 100644 index 000000000..1ceb26cbc --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/auth/handler/OpenShiftRegistryAuthHandler.java @@ -0,0 +1,161 @@ +package io.fabric8.maven.docker.build.auth.handler; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.Reader; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.fabric8.maven.docker.build.auth.RegistryAuth; +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuthHandler; +import io.fabric8.maven.docker.util.Logger; +import org.yaml.snakeyaml.Yaml; + +/** + * @author roland + * @since 21.10.18 + */ +public class OpenShiftRegistryAuthHandler implements RegistryAuthHandler { + + public static final String AUTH_USE_OPENSHIFT_AUTH = "useOpenShiftAuth"; + + private final RegistryAuthConfig registryAuthConfig; + private final Logger log; + + public OpenShiftRegistryAuthHandler(RegistryAuthConfig registryAuthConfig, Logger log) { + this.registryAuthConfig = registryAuthConfig; + this.log = log; + } + + @Override + public String getId() { + return "openshift"; + } + + @Override + public RegistryAuth create(RegistryAuthConfig.Kind kind, String user, String registry, Function decryptor) { + // Check for openshift authentication either from the plugin config or from system props + Properties props = System.getProperties(); + String useOpenAuthMode = registryAuthConfig.extractFromProperties(props, kind, AUTH_USE_OPENSHIFT_AUTH); + // Check for system property + if (useOpenAuthMode != null) { + boolean useOpenShift = Boolean.valueOf(useOpenAuthMode); + if (!useOpenShift) { + return null; + } + log.debug("AuthConfig: OpenShift credentials"); + return validateMandatoryOpenShiftLogin(parseOpenShiftConfig()); + } + + boolean useOpenShiftAuth = + Optional.ofNullable(registryAuthConfig.getConfigForHandler(getId(),AUTH_USE_OPENSHIFT_AUTH)) + .map(Boolean::parseBoolean) + .orElse(false); + if (useOpenShiftAuth) { + log.debug("AuthConfig: OpenShift credentials"); + return validateMandatoryOpenShiftLogin(parseOpenShiftConfig()); + } + + return null; + } + + private RegistryAuth validateMandatoryOpenShiftLogin(RegistryAuth openShiftRegistryAuth) { + if (openShiftRegistryAuth != null) { + return openShiftRegistryAuth; + } + // No login found + String kubeConfigEnv = System.getenv("KUBECONFIG"); + throw new IllegalArgumentException( + String.format("OpenShift auth check enabled, but not active user and/or token found in %s. " + + "Please use 'oc login' for connecting to OpenShift.", kubeConfigEnv != null ? kubeConfigEnv : "~/.kube/config")); + + } + + // Parse OpenShift config to get credentials, but return null if not found + private RegistryAuth parseOpenShiftConfig() { + Map kubeConfig = readKubeConfig(); + if (kubeConfig == null) { + return null; + } + + String currentContextName = (String) kubeConfig.get("current-context"); + if (currentContextName == null) { + return null; + } + + for (Map contextMap : (List) kubeConfig.get("contexts")) { + if (currentContextName.equals(contextMap.get("name"))) { + return parseContext(kubeConfig, (Map) contextMap.get("context")); + } + } + + return null; + } + + private Map readKubeConfig() { + String kubeConfig = System.getenv("KUBECONFIG"); + Optional reader = + getFileReaderFromDir(kubeConfig == null ? new File(getHomeDir(), ".kube/config") : new File(kubeConfig)); + + return (Map) reader.map(r -> new Yaml().load(r)).orElse(null); + } + + private Optional getFileReaderFromDir(File file) { + try { + return Optional.of(new FileReader(file)); + } catch (FileNotFoundException e) { + return Optional.empty(); + } + } + + private File getHomeDir() { + String homeDir = System.getProperty("user.home") != null ? System.getProperty("user.home") : System.getenv("HOME"); + return new File(homeDir); + } + + private RegistryAuth parseContext(Map kubeConfig, Map context) { + if (context == null) { + return null; + } + String userName = (String) context.get("user"); + if (userName == null) { + return null; + } + + List users = (List) kubeConfig.get("users"); + if (users == null) { + return null; + } + + for (Map userMap : users) { + if (userName.equals(userMap.get("name"))) { + return parseUser(userName, (Map) userMap.get("user")); + } + } + return null; + } + + private RegistryAuth parseUser(String userName, Map user) { + if (user == null) { + return null; + } + String token = (String) user.get("token"); + if (token == null) { + return null; + } + + // Strip off stuff after username + Matcher matcher = Pattern.compile("^([^/]+).*$").matcher(userName); + return new RegistryAuth.Builder() + .username(matcher.matches() ? matcher.group(1) : userName) + .password(token) + .build(); + } +} diff --git a/src/main/java/io/fabric8/maven/docker/build/auth/handler/SystemPropertyRegistryAuthHandler.java b/src/main/java/io/fabric8/maven/docker/build/auth/handler/SystemPropertyRegistryAuthHandler.java new file mode 100644 index 000000000..fe741fdb6 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/auth/handler/SystemPropertyRegistryAuthHandler.java @@ -0,0 +1,51 @@ +package io.fabric8.maven.docker.build.auth.handler; + +import java.util.Properties; +import java.util.function.Function; + +import io.fabric8.maven.docker.build.auth.RegistryAuth; +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuthHandler; +import io.fabric8.maven.docker.util.Logger; + +/** + * @author roland + * @since 21.10.18 + */ +public class SystemPropertyRegistryAuthHandler implements RegistryAuthHandler { + + private final RegistryAuthConfig registryAuthConfig; + private final Logger log; + + public SystemPropertyRegistryAuthHandler(RegistryAuthConfig registryAuthConfig, Logger log) { + this.log = log; + this.registryAuthConfig = registryAuthConfig; + } + + @Override + public String getId() { + return "sysprops"; + } + + @Override + public RegistryAuth create(RegistryAuthConfig.Kind kind, String user, String registry, Function decryptor) { + Properties props = System.getProperties(); + String username = registryAuthConfig.extractFromProperties(props, kind, RegistryAuth.USERNAME); + String password = registryAuthConfig.extractFromProperties(props, kind, RegistryAuth.PASSWORD); + + if (username == null) { + return null; + } + if (password == null) { + throw new IllegalArgumentException("No password provided for username " + username); + } + + log.debug("AuthConfig: credentials from system properties"); + return new RegistryAuth.Builder() + .username(username) + .password(password, decryptor) + .email(registryAuthConfig.extractFromProperties(props, kind, RegistryAuth.EMAIL)) + .auth(registryAuthConfig.extractFromProperties(props, kind, RegistryAuth.AUTH)) + .build(); + } +} diff --git a/src/main/java/io/fabric8/maven/docker/util/CredentialHelperClient.java b/src/main/java/io/fabric8/maven/docker/build/docker/CredentialHelperClient.java similarity index 82% rename from src/main/java/io/fabric8/maven/docker/util/CredentialHelperClient.java rename to src/main/java/io/fabric8/maven/docker/build/docker/CredentialHelperClient.java index 40f1c22bf..682cafd34 100644 --- a/src/main/java/io/fabric8/maven/docker/util/CredentialHelperClient.java +++ b/src/main/java/io/fabric8/maven/docker/build/docker/CredentialHelperClient.java @@ -1,16 +1,17 @@ -package io.fabric8.maven.docker.util; +package io.fabric8.maven.docker.build.docker; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.gson.JsonObject; -import org.apache.maven.plugin.MojoExecutionException; - import java.io.IOException; import java.util.List; -import io.fabric8.maven.docker.access.AuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuth; import io.fabric8.maven.docker.access.util.ExternalCommand; +import io.fabric8.maven.docker.util.EnvUtil; +import io.fabric8.maven.docker.util.JsonFactory; +import io.fabric8.maven.docker.util.Logger; public class CredentialHelperClient { @@ -28,15 +29,15 @@ public String getName() { return credentialHelperName; } - public String getVersion() throws MojoExecutionException { + public String getVersion() { try { return new VersionCommand().getVersion(); } catch (IOException e) { - throw new MojoExecutionException("Error getting the version of the configured credential helper",e); + throw new RuntimeException("Error getting the version of the configured credential helper",e); } } - public AuthConfig getAuthConfig(String registryToLookup) throws MojoExecutionException { + public RegistryAuth getAuthConfig(String registryToLookup) { try { JsonObject creds = new GetCommand().getCredentialNode(registryToLookup); if (creds == null) { @@ -44,17 +45,17 @@ public AuthConfig getAuthConfig(String registryToLookup) throws MojoExecutionExc } return toAuthConfig(creds); } catch (IOException e) { - throw new MojoExecutionException("Error getting the credentials for " + registryToLookup + " from the configured credential helper",e); + throw new RuntimeException("Error getting the credentials for " + registryToLookup + " from the configured credential helper",e); } } - private AuthConfig toAuthConfig(JsonObject credential){ + private RegistryAuth toAuthConfig(JsonObject credential){ if (credential == null) { return null; } String password = credential.get(CredentialHelperClient.SECRET_KEY).getAsString(); String userKey = credential.get(CredentialHelperClient.USERNAME_KEY).getAsString(); - return new AuthConfig(userKey,password, null,null); + return new RegistryAuth.Builder().username(userKey).password(password).build(); } // docker-credential-XXX version diff --git a/src/main/java/io/fabric8/maven/docker/build/docker/DockerBuildService.java b/src/main/java/io/fabric8/maven/docker/build/docker/DockerBuildService.java new file mode 100644 index 000000000..431277d7e --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/docker/DockerBuildService.java @@ -0,0 +1,283 @@ +package io.fabric8.maven.docker.build.docker; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + +import com.google.common.collect.ImmutableMap; +import io.fabric8.maven.docker.access.BuildOptions; +import io.fabric8.maven.docker.access.DockerAccess; +import io.fabric8.maven.docker.access.DockerAccessException; +import io.fabric8.maven.docker.build.BuildContext; +import io.fabric8.maven.docker.build.BuildService; +import io.fabric8.maven.docker.build.RegistryService; +import io.fabric8.maven.docker.config.ImageConfiguration; +import io.fabric8.maven.docker.config.build.AssemblyConfiguration; +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.config.build.CleanupMode; +import io.fabric8.maven.docker.config.build.ImagePullPolicy; +import io.fabric8.maven.docker.util.DockerFileUtil; +import io.fabric8.maven.docker.util.EnvUtil; +import io.fabric8.maven.docker.config.ImageName; +import io.fabric8.maven.docker.util.Logger; + +public class DockerBuildService implements BuildService { + + public static final String DEFAULT_DATA_BASE_IMAGE = "busybox:latest"; + + private final DockerAccess docker; + private final RegistryService registryService; + private final Logger log; + + public DockerBuildService(DockerAccess docker, RegistryService registryService, Logger log) { + this.docker = docker; + this.registryService = registryService; + this.log = log; + } + + /** + * Pull the base image if needed and run the build. + * + * @param imageConfig the image configuration + * @param buildContext the build context + */ + @Override + public void buildImage(ImageConfiguration imageConfig, BuildContext buildContext, Map buildArgs) + throws IOException { + // Call a pre-hook to the build + autoPullBaseImageIfRequested(imageConfig, buildContext); + + String imageName = imageConfig.getName(); + ImageName.validate(imageName); + BuildConfiguration buildConfig = imageConfig.getBuildConfiguration(); + + // Load an archive if present + if (buildConfig.getDockerArchive() != null) { + loadImageFromArchive(imageName, buildContext, new File(buildConfig.getDockerArchive())); + return; + } + + // Get old image id (if requested + Optional oldImageId = getOldImageId(imageName, buildConfig); + + // Create an archive usable for sending to the Docker daemon + File dockerArchive = createDockerContextArchive(imageConfig, buildContext); + + // Prepare options for building against a Docker daemon and do the build + String newImageId = build(imageConfig, + getBuildArgsFromProperties(buildContext, buildArgs), + dockerArchive); + + // Remove the image if requested + if (oldImageId.isPresent() && !oldImageId.get().equals(newImageId)) { + removeOldImage(imageConfig, oldImageId.get()); + } + } + + public void tagImage(String imageName, ImageConfiguration imageConfig) throws DockerAccessException { + List tags = imageConfig.getBuildConfiguration().getTags(); + if (!tags.isEmpty()) { + log.info("%s: Tag with %s", imageConfig.getDescription(), EnvUtil.stringJoin(tags, ",")); + + for (String tag : tags) { + if (tag != null) { + docker.tag(imageName, new ImageName(imageName, tag).getFullName(), true); + } + } + + log.debug("Tagging image successful!"); + } + } + + + private void autoPullBaseImageIfRequested(ImageConfiguration imageConfig, BuildContext buildContext) throws IOException { + BuildConfiguration buildConfig = imageConfig.getBuildConfiguration(); + + if (buildConfig.getDockerArchive() != null) { + // No auto pull needed in archive mode + return; + } + + String fromImage; + if (buildConfig.isDockerFileMode()) { + fromImage = extractBaseFromDockerfile(buildConfig, buildContext); + } else { + fromImage = extractBaseFromConfiguration(buildConfig); + } + if (fromImage != null && !"scratch".equals(fromImage)) { + + ImagePullPolicy imagePullPolicy = + buildConfig.getImagePullPolicy() != null ? + createPullPolicy(buildConfig.getImagePullPolicy()) : + buildContext.getRegistryContext().getDefaultImagePullPolicy(); + + registryService.pullImage(fromImage, imagePullPolicy, buildContext.getRegistryContext()); + } + } + + private ImagePullPolicy createPullPolicy(String imagePullPolicy) { + if (imagePullPolicy != null) { + return ImagePullPolicy.fromString(imagePullPolicy); + } + return ImagePullPolicy.IfNotPresent; + } + + + private String extractBaseFromConfiguration(BuildConfiguration buildConfig) { + String fromImage; + fromImage = buildConfig.getFrom(); + if (fromImage == null) { + AssemblyConfiguration assemblyConfig = buildConfig.getAssemblyConfiguration(); + if (assemblyConfig == null) { + fromImage = DEFAULT_DATA_BASE_IMAGE; + } + } + return fromImage; + } + + private String extractBaseFromDockerfile(BuildConfiguration buildConfig, BuildContext ctx) { + String fromImage; + try { + final File fullDockerFilePath = + EnvUtil.prepareAbsoluteSourceDirPath(ctx, buildConfig.calculateDockerFilePath().getPath()); + fromImage = DockerFileUtil.extractBaseImage( + fullDockerFilePath, + ctx.createInterpolator(buildConfig.getFilter())); + + } catch (IOException e) { + // Cant extract base image, so we wont try an auto pull. An error will occur later anyway when + // building the image, so we are passive here. + fromImage = null; + } + return fromImage; + } + + + private void loadImageFromArchive(String imageName, BuildContext ctx, File dockerArchive) throws DockerAccessException { + long time = System.currentTimeMillis(); + File dockerArchiveAbsolute = EnvUtil.prepareAbsoluteSourceDirPath(ctx, dockerArchive.getPath()); + docker.loadImage(imageName, dockerArchiveAbsolute); + log.info("%s: Loaded tarball in %s", dockerArchive, EnvUtil.formatDurationTill(time)); + } + + private File createDockerContextArchive(ImageConfiguration imageConfig, BuildContext ctx) throws IOException { + long time = System.currentTimeMillis(); + String imageName = imageConfig.getName(); + BuildConfiguration buildConfig = imageConfig.getBuildConfiguration(); + File dockerContextArchive = ctx.createImageContentArchive(imageName, buildConfig, log); + log.info("%s: Created %s in %s", + imageConfig.getDescription(), + dockerContextArchive.getName(), + EnvUtil.formatDurationTill(time)); + return dockerContextArchive; + } + + private Optional getOldImageId(String imageName, BuildConfiguration buildConfig) throws DockerAccessException { + CleanupMode cleanupMode = CleanupMode.parse(buildConfig.getCleanupMode()); + return cleanupMode.isRemove() ? + Optional.ofNullable(docker.getImageId(imageName)) : + Optional.empty(); + } + + private String build(ImageConfiguration imageConfig, + Map buildArgs, + File dockerArchive) throws DockerAccessException { + String imageName = imageConfig.getName(); + BuildConfiguration buildConfig = imageConfig.getBuildConfiguration(); + boolean noCache = checkForNocache(imageConfig); + BuildOptions opts = + new BuildOptions(buildConfig.getBuildOptions()) + .dockerfile(getDockerfileName(buildConfig)) + .forceRemove(CleanupMode.parse(buildConfig.getCleanupMode()).isRemove()) + .noCache(noCache) + .buildArgs(prepareBuildArgs(buildArgs, buildConfig)); + docker.buildImage(imageName, dockerArchive, opts); + String newImageId = docker.getImageId(imageName); + log.info("%s: Built image %s", imageConfig.getDescription(), newImageId); + return newImageId; + } + + private void removeOldImage(ImageConfiguration imageConfig, String oldImageId) throws DockerAccessException { + try { + docker.removeImage(oldImageId, true); + log.info("%s: Removed old image %s", imageConfig.getDescription(), oldImageId); + } catch (DockerAccessException exp) { + String cleanup = imageConfig.getBuildConfiguration().getCleanupMode(); + if (CleanupMode.parse(cleanup) == CleanupMode.TRY_TO_REMOVE) { + log.warn("%s: %s (old image)%s", imageConfig.getDescription(), exp.getMessage(), + (exp.getCause() != null ? " [" + exp.getCause().getMessage() + "]" : "")); + } else { + throw exp; + } + } + } + + private Map prepareBuildArgs(Map buildArgs, BuildConfiguration buildConfig) { + ImmutableMap.Builder builder = ImmutableMap.builder(); + if (buildArgs != null) { + builder.putAll(buildArgs); + } + if (buildConfig.getArgs() != null) { + builder.putAll(buildConfig.getArgs()); + } + return builder.build(); + } + + private String getDockerfileName(BuildConfiguration buildConfig) { + if (buildConfig.isDockerFileMode()) { + return buildConfig.calculateDockerFilePath().getName(); + } else { + return null; + } + } + + private Map getBuildArgsFromProperties(BuildContext buildContext, Map buildArgs) { + Map buildArgsFromProject = getBuildArgsFromProperties(buildContext.getProperties()); + Map buildArgsFromSystem = getBuildArgsFromProperties(System.getProperties()); + return ImmutableMap.builder() + .putAll(Optional.ofNullable(buildArgs).orElse(Collections.emptyMap())) + .putAll(buildArgsFromProject) + .putAll(buildArgsFromSystem) + .build(); + } + + private Map getBuildArgsFromProperties(Properties properties) { + String argPrefix = "docker.buildArg."; + Map buildArgs = new HashMap<>(); + if (properties == null) { + return buildArgs; + } + for (Object keyObj : properties.keySet()) { + String key = (String) keyObj; + if (key.startsWith(argPrefix)) { + String argKey = key.replaceFirst(argPrefix, ""); + String value = properties.getProperty(key); + + if (!isEmpty(value)) { + buildArgs.put(argKey, value); + } + } + } + log.debug("Build args set %s", buildArgs); + return buildArgs; + } + + private boolean checkForNocache(ImageConfiguration imageConfig) { + String nocache = System.getProperty("docker.nocache"); + if (nocache != null) { + return nocache.length() == 0 || Boolean.valueOf(nocache); + } else { + BuildConfiguration buildConfig = imageConfig.getBuildConfiguration(); + return buildConfig.getNoCache() != null ? buildConfig.getNoCache() : false; + } + } + + private boolean isEmpty(String str) { + return str == null || str.isEmpty(); + } +} diff --git a/src/main/java/io/fabric8/maven/docker/assembly/DockerFileBuilder.java b/src/main/java/io/fabric8/maven/docker/build/docker/DockerFileBuilder.java similarity index 96% rename from src/main/java/io/fabric8/maven/docker/assembly/DockerFileBuilder.java rename to src/main/java/io/fabric8/maven/docker/build/docker/DockerFileBuilder.java index c14243923..d27234591 100644 --- a/src/main/java/io/fabric8/maven/docker/assembly/DockerFileBuilder.java +++ b/src/main/java/io/fabric8/maven/docker/build/docker/DockerFileBuilder.java @@ -1,17 +1,21 @@ -package io.fabric8.maven.docker.assembly; +package io.fabric8.maven.docker.build.docker; import java.io.File; import java.io.IOException; -import java.util.*; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.google.common.base.Joiner; -import io.fabric8.maven.docker.config.Arguments; -import io.fabric8.maven.docker.config.HealthCheckConfiguration; - -import org.codehaus.plexus.util.FileUtils; -import org.codehaus.plexus.util.StringUtils; +import io.fabric8.maven.docker.config.build.Arguments; +import io.fabric8.maven.docker.config.build.HealthCheckConfiguration; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; /** * Create a dockerfile @@ -79,7 +83,7 @@ public class DockerFileBuilder { */ public File write(File destDir) throws IOException { File target = new File(destDir,"Dockerfile"); - FileUtils.fileWrite(target, content()); + FileUtils.write(target, content(), Charset.defaultCharset()); return target; } @@ -94,7 +98,7 @@ public String content() throws IllegalArgumentException { StringBuilder b = new StringBuilder(); - DockerFileKeyword.FROM.addTo(b, baseImage != null ? baseImage : DockerAssemblyManager.DEFAULT_DATA_BASE_IMAGE); + DockerFileKeyword.FROM.addTo(b, baseImage != null ? baseImage : DockerBuildService.DEFAULT_DATA_BASE_IMAGE); if (maintainer != null) { DockerFileKeyword.MAINTAINER.addTo(b, maintainer); } diff --git a/src/main/java/io/fabric8/maven/docker/assembly/DockerFileKeyword.java b/src/main/java/io/fabric8/maven/docker/build/docker/DockerFileKeyword.java similarity index 96% rename from src/main/java/io/fabric8/maven/docker/assembly/DockerFileKeyword.java rename to src/main/java/io/fabric8/maven/docker/build/docker/DockerFileKeyword.java index 7a41a6812..2c029c8f4 100644 --- a/src/main/java/io/fabric8/maven/docker/assembly/DockerFileKeyword.java +++ b/src/main/java/io/fabric8/maven/docker/build/docker/DockerFileKeyword.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.assembly; +package io.fabric8.maven.docker.build.docker; /** * Fields for a dockerfile diff --git a/src/main/java/io/fabric8/maven/docker/assembly/DockerFileOption.java b/src/main/java/io/fabric8/maven/docker/build/docker/DockerFileOption.java similarity index 93% rename from src/main/java/io/fabric8/maven/docker/assembly/DockerFileOption.java rename to src/main/java/io/fabric8/maven/docker/build/docker/DockerFileOption.java index a1a6806f6..ec6debb70 100644 --- a/src/main/java/io/fabric8/maven/docker/assembly/DockerFileOption.java +++ b/src/main/java/io/fabric8/maven/docker/build/docker/DockerFileOption.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.assembly; +package io.fabric8.maven.docker.build.docker; /** * List of options for Docker keywords diff --git a/src/main/java/io/fabric8/maven/docker/build/docker/DockerRegistryAuthHandler.java b/src/main/java/io/fabric8/maven/docker/build/docker/DockerRegistryAuthHandler.java new file mode 100644 index 000000000..62c876479 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/docker/DockerRegistryAuthHandler.java @@ -0,0 +1,119 @@ +package io.fabric8.maven.docker.build.docker; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.Reader; +import java.util.Optional; +import java.util.function.Function; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import io.fabric8.maven.docker.build.auth.RegistryAuth; +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuthHandler; +import io.fabric8.maven.docker.util.EnvUtil; +import io.fabric8.maven.docker.util.Logger; + +/** + * @author roland + * @since 21.10.18 + */ +public class DockerRegistryAuthHandler implements RegistryAuthHandler { + + static final String DOCKER_LOGIN_DEFAULT_REGISTRY = "https://index.docker.io/v1/"; + + private final Logger log; + private final Gson gson; + + public DockerRegistryAuthHandler(Logger log) { + this.log = log; + this.gson = new Gson(); + + } + + @Override + public String getId() { + return "docker"; + } + + @Override + public RegistryAuth create(RegistryAuthConfig.Kind kind, String user, String registry, Function decryptor) { + return readDockerConfig().map(d -> extractAuthConfigFromDocker(d, registry)).orElse(null); + } + + private RegistryAuth extractAuthConfigFromDocker(JsonObject dockerConfig, String registry) { + String registryToLookup = registry != null ? registry : DOCKER_LOGIN_DEFAULT_REGISTRY; + + if (dockerConfig.has("credHelpers") || dockerConfig.has("credsStore")) { + if (dockerConfig.has("credHelpers")) { + final JsonObject credHelpers = dockerConfig.getAsJsonObject("credHelpers"); + if (credHelpers.has(registryToLookup)) { + return extractAuthConfigFromCredentialsHelper(registryToLookup, credHelpers.get(registryToLookup).getAsString()); + } + } + if (dockerConfig.has("credsStore")) { + return extractAuthConfigFromCredentialsHelper(registryToLookup, dockerConfig.get("credsStore").getAsString()); + } + } + + if (dockerConfig.has("auths")) { + return extractAuthConfigFromAuths(registryToLookup, dockerConfig.getAsJsonObject("auths")); + } + + return null; + } + + private Optional readDockerConfig() { + String dockerConfig = System.getenv("DOCKER_CONFIG"); + + Optional reader = dockerConfig == null + ? getFileReaderFromDir(new File(getHomeDir(), ".docker/config.json")) + : getFileReaderFromDir(new File(dockerConfig, "config.json")); + return reader.map(r -> gson.fromJson(r, JsonObject.class)); + } + + private RegistryAuth extractAuthConfigFromAuths(String registryToLookup, JsonObject auths) { + JsonObject credentials = getCredentialsNode(auths, registryToLookup); + if (credentials == null || !credentials.has("auth")) { + return null; + } + String auth = credentials.get("auth").getAsString(); + String email = credentials.has("email") ? credentials.get("email").getAsString() : null; + return new RegistryAuth.Builder().withCredentialsEncoded(auth).email(email).build(); + } + + private RegistryAuth extractAuthConfigFromCredentialsHelper(String registryToLookup, String credConfig) { + CredentialHelperClient credentialHelper = new CredentialHelperClient(log, credConfig); + log.debug("AuthConfig: credentials from credential helper/store %s version %s", + credentialHelper.getName(), + credentialHelper.getVersion()); + return credentialHelper.getAuthConfig(registryToLookup); + } + + private JsonObject getCredentialsNode(JsonObject auths, String registryToLookup) { + if (auths.has(registryToLookup)) { + return auths.getAsJsonObject(registryToLookup); + } + String registryWithScheme = EnvUtil.ensureRegistryHttpUrl(registryToLookup); + if (auths.has(registryWithScheme)) { + return auths.getAsJsonObject(registryWithScheme); + } + return null; + } + + private Optional getFileReaderFromDir(File file) { + try { + return Optional.of(new FileReader(file)); + } catch (FileNotFoundException e) { + return Optional.empty(); + } + } + + private File getHomeDir() { + String homeDir = Optional.ofNullable(System.getProperty("user.home")).orElse(System.getenv("HOME")); + return new File(homeDir); + } + + +} diff --git a/src/main/java/io/fabric8/maven/docker/build/docker/DockerRegistryService.java b/src/main/java/io/fabric8/maven/docker/build/docker/DockerRegistryService.java new file mode 100644 index 000000000..481ecebfb --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/docker/DockerRegistryService.java @@ -0,0 +1,134 @@ +package io.fabric8.maven.docker.build.docker; + +import java.io.IOException; + +import io.fabric8.maven.docker.build.auth.RegistryAuth; +import io.fabric8.maven.docker.access.DockerAccess; +import io.fabric8.maven.docker.access.DockerAccessException; +import io.fabric8.maven.docker.build.RegistryContext; +import io.fabric8.maven.docker.build.RegistryService; +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig; +import io.fabric8.maven.docker.config.ImageConfiguration; +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.config.build.ImagePullPolicy; +import io.fabric8.maven.docker.util.EnvUtil; +import io.fabric8.maven.docker.config.ImageName; +import io.fabric8.maven.docker.util.Logger; + +/** + * Allows to interact with registries, eg. to push/pull images. + */ +public class DockerRegistryService implements RegistryService { + + private final DockerAccess docker; + private final Logger log; + private final ImagePullCache imagePullCache; + + public DockerRegistryService(DockerAccess docker, Logger log, ImagePullCache.Backend backend) { + this.docker = docker; + this.log = log; + this.imagePullCache = new ImagePullCache(backend); + } + + /** + * Push a set of images to a registry + * + * @param imageConfig image to push but only if it has a build configuration + * @param retries how often to retry + * @param skipTag flag to skip pushing tagged images + * @throws DockerAccessException + */ + @Override + public void pushImage(ImageConfiguration imageConfig, + int retries, boolean skipTag, RegistryContext context) throws IOException { + BuildConfiguration buildConfig = imageConfig.getBuildConfiguration(); + String name = imageConfig.getName(); + if (buildConfig != null) { + String registry = EnvUtil.firstRegistryOf( + new ImageName(imageConfig.getName()).getRegistry(), + imageConfig.getRegistry(), + context.getRegistry(RegistryAuthConfig.Kind.PUSH)); + + + RegistryAuth registryAuth = context.getAuthConfig(RegistryAuthConfig.Kind.PUSH, new ImageName(name).getUser(), registry); + + long start = System.currentTimeMillis(); + docker.pushImage(name, registryAuth.toHeaderValue(), registry, retries); + log.info("Pushed %s in %s", name, EnvUtil.formatDurationTill(start)); + + if (!skipTag) { + for (String tag : imageConfig.getBuildConfiguration().getTags()) { + if (tag != null) { + docker.pushImage(new ImageName(name, tag).getFullName(), registryAuth.toHeaderValue(), registry, retries); + } + } + } + } + } + + + /** + * Check an image, and, if autoPull is set to true, fetch it. Otherwise if the image + * is not existent, throw an error + * + * @throws DockerAccessException + */ + public void pullImage(String image, ImagePullPolicy policy, RegistryContext registryContext) + throws IOException { + + // Already pulled, so we don't need to take care + if (imagePullCache.hasAlreadyPulled(image)) { + return; + } + + // Check if a pull is required + if (!imageRequiresPull(docker.hasImage(image), policy, image)) { + return; + } + + ImageName imageName = new ImageName(image); + long time = System.currentTimeMillis(); + String registry = EnvUtil.firstRegistryOf( + imageName.getRegistry(), + registryContext.getRegistry(RegistryAuthConfig.Kind.PULL)); + + docker.pullImage(imageName.getFullName(), + registryContext.getAuthConfig(RegistryAuthConfig.Kind.PULL, null, registry).toHeaderValue(), + registry); + log.info("Pulled %s in %s", imageName.getFullName(), EnvUtil.formatDurationTill(time)); + imagePullCache.pulled(image); + + if (registry != null && !imageName.hasRegistry()) { + // If coming from a registry which was not contained in the original name, add a tag from the + // full name with the registry to the short name with no-registry. + docker.tag(imageName.getFullName(registry), image, false); + } + } + + + // ============================================================================================================ + + + private boolean imageRequiresPull(boolean hasImage, ImagePullPolicy pullPolicy, String imageName) { + + // The logic here is like this (see also #96): + // otherwise: don't pull + + if (pullPolicy == ImagePullPolicy.Never) { + if (!hasImage) { + throw new IllegalArgumentException( + String.format("No image '%s' found and pull policy 'Never' is set. Please chose another pull policy or pull the image yourself)", imageName)); + } + return false; + } + + // If the image is not available and mode is not ImagePullPolicy.Never --> pull + if (!hasImage) { + return true; + } + + // If pullPolicy == Always --> pull, otherwise not (we have it already) + return pullPolicy == ImagePullPolicy.Always; + } + +} diff --git a/src/main/java/io/fabric8/maven/docker/build/docker/ImagePullCache.java b/src/main/java/io/fabric8/maven/docker/build/docker/ImagePullCache.java new file mode 100644 index 000000000..7c3ad9625 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/docker/ImagePullCache.java @@ -0,0 +1,81 @@ +package io.fabric8.maven.docker.build.docker; + +import com.google.gson.JsonObject; +import io.fabric8.maven.docker.util.JsonFactory; + +/** + * Simple interface for a ImagePullCache manager, to load and persist the cache. + */ +public class ImagePullCache { + + // Key for the previously used image cache + private static final String CONTEXT_KEY_PREVIOUSLY_PULLED = "CONTEXT_KEY_PREVIOUSLY_PULLED"; + + private Backend backend; + + public ImagePullCache(Backend backend) { + this.backend = backend; + } + + public boolean hasAlreadyPulled(String image) { + return load().has(image); + } + + public void pulled(String image) { + save(load().add(image)); + } + + // Store to use for the cached + public interface Backend { + String get(String key); + void put(String key, String value); + } + + // ====================================================================================== + + private ImagePullCacheStore load() { + + String pullCacheJson = backend.get(CONTEXT_KEY_PREVIOUSLY_PULLED); + + ImagePullCacheStore cache = new ImagePullCacheStore(pullCacheJson); + + if (pullCacheJson == null) { + save(cache); + } + return cache; + } + + private void save(ImagePullCacheStore cache) { + backend.put(CONTEXT_KEY_PREVIOUSLY_PULLED, cache.toString()); + } + + /** + * Simple serializable cache for holding image names + * + * @author roland + * @since 20/07/16 + */ + class ImagePullCacheStore { + + private JsonObject cache; + + + ImagePullCacheStore(String json) { + cache = json != null ? JsonFactory.newJsonObject(json) : new JsonObject(); + } + + public boolean has(String imageName) { + return cache.has(imageName); + } + + public ImagePullCacheStore add(String image) { + cache.addProperty(image, Boolean.TRUE); + return this; + } + + @Override + public String toString() { + return cache.toString(); + } + } +} diff --git a/src/main/java/io/fabric8/maven/docker/service/ArchiveService.java b/src/main/java/io/fabric8/maven/docker/build/maven/MavenArchiveService.java similarity index 66% rename from src/main/java/io/fabric8/maven/docker/service/ArchiveService.java rename to src/main/java/io/fabric8/maven/docker/build/maven/MavenArchiveService.java index 48ffa8514..3ac5b5bf2 100644 --- a/src/main/java/io/fabric8/maven/docker/service/ArchiveService.java +++ b/src/main/java/io/fabric8/maven/docker/build/maven/MavenArchiveService.java @@ -1,5 +1,5 @@ -package io.fabric8.maven.docker.service;/* - * +package io.fabric8.maven.docker.build.maven;/* + * * Copyright 2015 Roland Huss * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,33 +15,32 @@ * limitations under the License. */ -import io.fabric8.maven.docker.assembly.ArchiverCustomizer; -import io.fabric8.maven.docker.assembly.AssemblyFiles; -import io.fabric8.maven.docker.assembly.DockerAssemblyManager; -import io.fabric8.maven.docker.config.BuildImageConfiguration; +import java.io.File; +import java.io.IOException; +import java.util.List; + +import io.fabric8.maven.docker.build.maven.assembly.ArchiverCustomizer; +import io.fabric8.maven.docker.build.maven.assembly.AssemblyFiles; +import io.fabric8.maven.docker.build.maven.assembly.DockerAssemblyManager; import io.fabric8.maven.docker.config.ImageConfiguration; +import io.fabric8.maven.docker.config.build.BuildConfiguration; import io.fabric8.maven.docker.util.Logger; -import io.fabric8.maven.docker.util.MojoParameters; -import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.assembly.InvalidAssemblerConfigurationException; import org.apache.maven.plugins.assembly.archive.ArchiveCreationException; import org.apache.maven.plugins.assembly.format.AssemblyFormattingException; -import java.io.File; -import java.util.List; - /** * @author roland * @since 30/11/15 */ -public class ArchiveService { +public class MavenArchiveService { private final Logger log; private DockerAssemblyManager dockerAssemblyManager; - public ArchiveService(DockerAssemblyManager dockerAssemblyManager,Logger log) { + public MavenArchiveService(DockerAssemblyManager dockerAssemblyManager, Logger log) { this.log = log; this.dockerAssemblyManager = dockerAssemblyManager; } @@ -53,10 +52,10 @@ public ArchiveService(DockerAssemblyManager dockerAssemblyManager,Logger log) { * @param imageConfig the image configuration * @param params mojo params for the project * @return file for holding the sources - * @throws MojoExecutionException if during creation of the tar an error occurs. + * @throws IOException if during creation of the tar an error occurs. */ - public File createDockerBuildArchive(ImageConfiguration imageConfig, MojoParameters params) - throws MojoExecutionException { + public File createDockerBuildArchive(ImageConfiguration imageConfig, MavenBuildContext params) + throws IOException { return createDockerBuildArchive(imageConfig, params, null); } @@ -65,14 +64,14 @@ public File createDockerBuildArchive(ImageConfiguration imageConfig, MojoParamet * uploading to a Docker daemon for creating the image * * @param imageConfig the image configuration - * @param params mojo params for the project + * @param context mojo params for the project * @param customizer final customizer to be applied to the tar before being generated * @return file for holding the sources - * @throws MojoExecutionException if during creation of the tar an error occurs. + * @throws IOException if during creation of the tar an error occurs. */ - public File createDockerBuildArchive(ImageConfiguration imageConfig, MojoParameters params, ArchiverCustomizer customizer) - throws MojoExecutionException { - File ret = createArchive(imageConfig.getName(), imageConfig.getBuildConfiguration(), params, log, customizer); + public File createDockerBuildArchive(ImageConfiguration imageConfig, MavenBuildContext context, ArchiverCustomizer customizer) + throws IOException { + File ret = createArchive(imageConfig.getName(), imageConfig.getBuildConfiguration(), context, log, customizer); log.info("%s: Created docker source tar %s",imageConfig.getDescription(), ret); return ret; } @@ -84,18 +83,18 @@ public File createDockerBuildArchive(ImageConfiguration imageConfig, MojoParamet * * @param imageConfig image config for which to get files. The build- and assembly configuration in this image * config must not be null. - * @param mojoParameters needed for tracking the assembly + * @param context needed for tracking the assembly * @return mapping of assembly files - * @throws MojoExecutionException + * @throws IOException */ - public AssemblyFiles getAssemblyFiles(ImageConfiguration imageConfig, MojoParameters mojoParameters) - throws MojoExecutionException { + public AssemblyFiles getAssemblyFiles(ImageConfiguration imageConfig, MavenBuildContext context) + throws IOException { String name = imageConfig.getName(); try { - return dockerAssemblyManager.getAssemblyFiles(name, imageConfig.getBuildConfiguration(), mojoParameters, log); + return dockerAssemblyManager.getAssemblyFiles(name, imageConfig.getBuildConfiguration(), context, log); } catch (InvalidAssemblerConfigurationException | ArchiveCreationException | AssemblyFormattingException e) { - throw new MojoExecutionException("Cannot extract assembly files for image " + name + ": " + e, e); + throw new IOException("Cannot extract assembly files for image " + name + ": " + e, e); } } @@ -107,19 +106,19 @@ public AssemblyFiles getAssemblyFiles(ImageConfiguration imageConfig, MojoParame * @return created archive */ public File createChangedFilesArchive(List entries, File assemblyDir, - String imageName, MojoParameters mojoParameters) throws MojoExecutionException { + String imageName, MavenBuildContext mojoParameters) throws IOException { return dockerAssemblyManager.createChangedFilesArchive(entries, assemblyDir, imageName, mojoParameters); } // ============================================= - File createArchive(String imageName, BuildImageConfiguration buildConfig, MojoParameters params, Logger log) - throws MojoExecutionException { - return createArchive(imageName, buildConfig, params, log, null); + public File createArchive(String imageName, BuildConfiguration buildConfig, MavenBuildContext ctx, Logger log) + throws IOException { + return createArchive(imageName, buildConfig, ctx, log, null); } - File createArchive(String imageName, BuildImageConfiguration buildConfig, MojoParameters params, Logger log, ArchiverCustomizer customizer) - throws MojoExecutionException { - return dockerAssemblyManager.createDockerTarArchive(imageName, params, buildConfig, log, customizer); + File createArchive(String imageName, BuildConfiguration buildConfig, MavenBuildContext ctx, Logger log, ArchiverCustomizer customizer) + throws IOException { + return dockerAssemblyManager.createDockerTarArchive(imageName, ctx, buildConfig, customizer, log); } } diff --git a/src/main/java/io/fabric8/maven/docker/build/maven/MavenBuildContext.java b/src/main/java/io/fabric8/maven/docker/build/maven/MavenBuildContext.java new file mode 100644 index 000000000..7b4702abf --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/maven/MavenBuildContext.java @@ -0,0 +1,186 @@ +package io.fabric8.maven.docker.build.maven; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import java.util.function.Function; + +import io.fabric8.maven.docker.build.BuildContext; +import io.fabric8.maven.docker.build.RegistryContext; +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.util.DockerFileUtil; +import io.fabric8.maven.docker.util.Logger; +import org.apache.maven.archiver.MavenArchiveConfiguration; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; +import org.apache.maven.settings.Settings; +import org.apache.maven.shared.filtering.MavenFileFilter; +import org.apache.maven.shared.filtering.MavenReaderFilter; +import org.codehaus.plexus.interpolation.fixed.FixedStringSearchInterpolator; + +/** + * @author roland + * @since 16.10.18 + */ +public class MavenBuildContext implements BuildContext { + + private String sourceDirectory; + private String outputDirectory; + private MavenProject project; + private MavenSession session; + private MavenFileFilter mavenFileFilter; + private MavenReaderFilter mavenReaderFilter; + private Settings settings; + private List reactorProjects; + private MavenArchiveConfiguration archiveConfiguration; + private MavenArchiveService archiveService; + private RegistryContext registryContext; + + private MavenBuildContext() { } + + + public String getSourceDirectory() { + return sourceDirectory; + } + + public String getOutputDirectory() { + return outputDirectory; + } + + + public File getBasedir() { + return project.getBasedir(); + } + + @Override + public Properties getProperties() { + return project.getProperties(); + } + + @Override + public Function createInterpolator(String filter) { + FixedStringSearchInterpolator interpolator = + DockerFileUtil.createInterpolator(this, filter); + return interpolator::interpolate; + } + + @Override + public File createImageContentArchive(String imageName, BuildConfiguration buildConfig, Logger log) throws IOException { + return archiveService.createArchive(imageName, buildConfig, this, log); + } + + @Override + public RegistryContext getRegistryContext() { + return registryContext; + } + + // ======================================================================================= + // Maven specific method not available via interface + + public MavenProject getProject() { + return project; + } + + public MavenSession getSession() { + return session; + } + + public MavenFileFilter getMavenFileFilter() { + return mavenFileFilter; + } + + public MavenReaderFilter getMavenReaderFilter() { + return mavenReaderFilter; + } + + public Settings getSettings() { + return settings; + } + + public List getReactorProjects() { + return reactorProjects; + } + + public MavenArchiveConfiguration getArchiveConfiguration() { + return archiveConfiguration; + } + + // ======================================================================================= + public static class Builder { + + private MavenBuildContext context; + + public Builder() { + this.context = new MavenBuildContext(); + } + + public Builder(MavenBuildContext context) { + this.context = context; + } + + public Builder sourceDirectory(String sourceDirectory) { + context.sourceDirectory = sourceDirectory; + return this; + } + + public Builder outputDirectory(String outputDirectory) { + context.outputDirectory = outputDirectory; + return this; + } + + public Builder registryContext(RegistryContext registryContext) { + context.registryContext = registryContext; + return this; + } + + // =============================================================================== + // Maven specific calls + + public Builder project(MavenProject project) { + context.project = project; + return this; + } + + public Builder session(MavenSession session) { + context.session = session; + return this; + } + + public Builder settings(Settings settings) { + context.settings = settings; + return this; + } + + public Builder mavenReaderFilter(MavenReaderFilter mavenReaderFilter) { + context.mavenReaderFilter = mavenReaderFilter; + return this; + } + + public Builder mavenFileFilter(MavenFileFilter mavenFileFilter) { + context.mavenFileFilter = mavenFileFilter; + return this; + } + + public Builder reactorProjects(List reactorProjects) { + context.reactorProjects = reactorProjects; + return this; + } + + public Builder archiveConfiguration(MavenArchiveConfiguration archiveConfiguration) { + context.archiveConfiguration = archiveConfiguration; + return this; + } + + public Builder archiveService(MavenArchiveService archiveService) { + context.archiveService = archiveService; + return this; + } + + // ================================================================================ + public MavenBuildContext build() { + return context; + } + + } +} diff --git a/src/main/java/io/fabric8/maven/docker/build/maven/MavenCacheBackend.java b/src/main/java/io/fabric8/maven/docker/build/maven/MavenCacheBackend.java new file mode 100644 index 000000000..04f8cc3e7 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/maven/MavenCacheBackend.java @@ -0,0 +1,31 @@ +package io.fabric8.maven.docker.build.maven; + +import java.util.Properties; + +import io.fabric8.maven.docker.build.docker.ImagePullCache; +import org.apache.maven.execution.MavenSession; + +/** + * @author roland + * @since 17.10.18 + */ +public class MavenCacheBackend implements ImagePullCache.Backend { + + private MavenSession session; + + public MavenCacheBackend(MavenSession session) { + this.session = session; + } + + @Override + public String get(String key) { + Properties userProperties = session.getUserProperties(); + return userProperties.getProperty(key); + } + + @Override + public void put(String key, String value) { + Properties userProperties = session.getUserProperties(); + userProperties.setProperty(key, value); + } +} diff --git a/src/main/java/io/fabric8/maven/docker/build/maven/MavenRegistryContext.java b/src/main/java/io/fabric8/maven/docker/build/maven/MavenRegistryContext.java new file mode 100644 index 000000000..c65cd431c --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/maven/MavenRegistryContext.java @@ -0,0 +1,69 @@ +package io.fabric8.maven.docker.build.maven; + +import java.io.IOException; + +import io.fabric8.maven.docker.build.auth.RegistryAuth; +import io.fabric8.maven.docker.build.RegistryContext; +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuthFactory; +import io.fabric8.maven.docker.config.build.ImagePullPolicy; + +/** + * @author roland + * @since 17.10.18 + */ +public class MavenRegistryContext implements RegistryContext { + + private ImagePullPolicy defaultImagePullPolicy; + private RegistryAuthFactory registryAuthFactory; + private String pushRegistry; + private String pullRegistry; + + @Override + public ImagePullPolicy getDefaultImagePullPolicy() { + return defaultImagePullPolicy; + } + + @Override + public RegistryAuth getAuthConfig(RegistryAuthConfig.Kind kind, String user, String registry) throws IOException { + return registryAuthFactory.createAuthConfig(kind, user, registry); + } + + @Override + public String getRegistry(RegistryAuthConfig.Kind kind) { + return kind == RegistryAuthConfig.Kind.PULL ? pullRegistry : pushRegistry; + } + + // =============================================================================================== + + public static class Builder { + + private MavenRegistryContext context = new MavenRegistryContext(); + + public Builder defaultImagePullPolicy(ImagePullPolicy defaultImagePullPolicy) { + context.defaultImagePullPolicy = defaultImagePullPolicy; + return this; + } + + public Builder pushRegistry(String pushRegistry) { + context.pushRegistry = pushRegistry; + return this; + } + + public Builder pullRegistry(String pullRegistry) { + context.pullRegistry = pullRegistry; + return this; + } + + public Builder authRegistryAuthFactory(RegistryAuthFactory registryAuthFactory) { + context.registryAuthFactory = registryAuthFactory; + return this; + } + + // ================================================================================ + public MavenRegistryContext build() { + return context; + } + + } +} diff --git a/src/main/java/io/fabric8/maven/docker/build/maven/SettingsRegistrysAuthHandler.java b/src/main/java/io/fabric8/maven/docker/build/maven/SettingsRegistrysAuthHandler.java new file mode 100644 index 000000000..8d790e7c6 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/build/maven/SettingsRegistrysAuthHandler.java @@ -0,0 +1,95 @@ +package io.fabric8.maven.docker.build.maven; + +import java.util.Optional; +import java.util.function.Function; + +import io.fabric8.maven.docker.build.auth.RegistryAuth; +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuthHandler; +import io.fabric8.maven.docker.util.Logger; +import org.apache.maven.settings.Server; +import org.apache.maven.settings.Settings; +import org.codehaus.plexus.util.xml.Xpp3Dom; + +/** + * @author roland + * @since 21.10.18 + */ +public class SettingsRegistrysAuthHandler implements RegistryAuthHandler { + + private static final String[] DEFAULT_REGISTRIES = new String[]{ + "docker.io", "index.docker.io", "registry.hub.docker.com" + }; + + private final Settings settings; + private final Logger log; + + public SettingsRegistrysAuthHandler(Settings settings, Logger log) { + this.settings = settings; + this.log = log; + } + + @Override + public String getId() { + return "settings"; + } + + @Override + public RegistryAuth create(RegistryAuthConfig.Kind kind, String user, String registry, Function decryptor) { + // Now lets lookup the registry & user from ~/.m2/setting.xml + Server defaultServer = null; + Server found; + for (Server server : settings.getServers()) { + String id = server.getId(); + + // Remember a default server without user as fallback for later + if (defaultServer == null) { + defaultServer = checkForServer(server, id, registry, null); + } + // Check for specific server with user part + found = checkForServer(server, id, registry, user); + if (found != null) { + log.debug("AuthConfig: credentials from ~/.m2/setting.xml (%s)", found); + return createAuthConfigFromServer(found, decryptor); + } + } + + if (defaultServer != null) { + log.debug("AuthConfig: credentials from ~/.m2/setting.xml (%s)", defaultServer); + return createAuthConfigFromServer(defaultServer, decryptor); + } + + return null; + } + + private Server checkForServer(Server server, String id, String registry, String user) { + + String[] registries = registry != null ? new String[]{registry} : DEFAULT_REGISTRIES; + for (String reg : registries) { + if (id.equals(user == null ? reg : reg + "/" + user)) { + return server; + } + } + return null; + } + + private RegistryAuth createAuthConfigFromServer(Server server, Function decryptor) { + return new RegistryAuth.Builder() + .username(server.getUsername()) + .password(server.getPassword(), decryptor) + .email(extractFromServerConfiguration(server.getConfiguration(), RegistryAuth.EMAIL)) + .auth(extractFromServerConfiguration(server.getConfiguration(), RegistryAuth.AUTH)) + .build(); + } + + private String extractFromServerConfiguration(Object configuration, String prop) { + if (configuration != null) { + Xpp3Dom dom = (Xpp3Dom) configuration; + Xpp3Dom element = dom.getChild(prop); + if (element != null) { + return element.getValue(); + } + } + return null; + } +} diff --git a/src/main/java/io/fabric8/maven/docker/assembly/AllFilesExecCustomizer.java b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/AllFilesExecCustomizer.java similarity index 98% rename from src/main/java/io/fabric8/maven/docker/assembly/AllFilesExecCustomizer.java rename to src/main/java/io/fabric8/maven/docker/build/maven/assembly/AllFilesExecCustomizer.java index 80df6319d..6a40bc1c1 100644 --- a/src/main/java/io/fabric8/maven/docker/assembly/AllFilesExecCustomizer.java +++ b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/AllFilesExecCustomizer.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.assembly; +package io.fabric8.maven.docker.build.maven.assembly; /* * * Copyright 2016 Roland Huss diff --git a/src/main/java/io/fabric8/maven/docker/assembly/ArchiverCustomizer.java b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/ArchiverCustomizer.java similarity index 94% rename from src/main/java/io/fabric8/maven/docker/assembly/ArchiverCustomizer.java rename to src/main/java/io/fabric8/maven/docker/build/maven/assembly/ArchiverCustomizer.java index 316d71828..3ed88706f 100644 --- a/src/main/java/io/fabric8/maven/docker/assembly/ArchiverCustomizer.java +++ b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/ArchiverCustomizer.java @@ -13,7 +13,7 @@ * implied. See the License for the specific language governing * permissions and limitations under the License. */ -package io.fabric8.maven.docker.assembly; +package io.fabric8.maven.docker.build.maven.assembly; import java.io.IOException; diff --git a/src/main/java/io/fabric8/maven/docker/assembly/AssemblyFiles.java b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/AssemblyFiles.java similarity index 98% rename from src/main/java/io/fabric8/maven/docker/assembly/AssemblyFiles.java rename to src/main/java/io/fabric8/maven/docker/build/maven/assembly/AssemblyFiles.java index f756fc5dc..9906288cd 100644 --- a/src/main/java/io/fabric8/maven/docker/assembly/AssemblyFiles.java +++ b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/AssemblyFiles.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.assembly;/* +package io.fabric8.maven.docker.build.maven.assembly;/* * * Copyright 2014 Roland Huss * diff --git a/src/main/java/io/fabric8/maven/docker/assembly/BuildDirs.java b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/BuildDirs.java similarity index 81% rename from src/main/java/io/fabric8/maven/docker/assembly/BuildDirs.java rename to src/main/java/io/fabric8/maven/docker/build/maven/assembly/BuildDirs.java index f81d3a5c4..a8693ce2b 100644 --- a/src/main/java/io/fabric8/maven/docker/assembly/BuildDirs.java +++ b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/BuildDirs.java @@ -1,5 +1,5 @@ -package io.fabric8.maven.docker.assembly;/* - * +package io.fabric8.maven.docker.build.maven.assembly;/* + * * Copyright 2014 Roland Huss * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,7 @@ import java.io.File; -import io.fabric8.maven.docker.util.MojoParameters; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; import io.fabric8.maven.docker.util.EnvUtil; /** @@ -30,16 +30,16 @@ class BuildDirs { private final String buildTopDir; - private final MojoParameters params; + private final MavenBuildContext context; /** * Constructor building up the the output directories * * @param imageName image name for the image to build - * @param params mojo params holding base and global outptput dir + * @param context mojo params holding base and global outptput dir */ - BuildDirs(String imageName, MojoParameters params) { - this.params = params; + BuildDirs(String imageName, MavenBuildContext context) { + this.context = context; // Replace tag separator with a slash to avoid problems // with OSs which gets confused by colons. this.buildTopDir = imageName != null ? imageName.replace(':', '/') : null; @@ -69,6 +69,6 @@ void createDirs() { } private File getDir(String dir) { - return EnvUtil.prepareAbsoluteOutputDirPath(params, buildTopDir, dir); + return EnvUtil.prepareAbsoluteOutputDirPath(context, buildTopDir, dir); } } diff --git a/src/main/java/io/fabric8/maven/docker/assembly/DockerAssemblyConfigurationSource.java b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyConfigurationSource.java similarity index 88% rename from src/main/java/io/fabric8/maven/docker/assembly/DockerAssemblyConfigurationSource.java rename to src/main/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyConfigurationSource.java index f5accd095..a05ed1090 100644 --- a/src/main/java/io/fabric8/maven/docker/assembly/DockerAssemblyConfigurationSource.java +++ b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyConfigurationSource.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.assembly; +package io.fabric8.maven.docker.build.maven.assembly; import java.io.File; import java.util.Collections; @@ -7,8 +7,8 @@ import javax.annotation.Nonnull; -import io.fabric8.maven.docker.config.AssemblyConfiguration; -import io.fabric8.maven.docker.util.MojoParameters; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; +import io.fabric8.maven.docker.config.build.AssemblyConfiguration; import io.fabric8.maven.docker.util.EnvUtil; import org.apache.maven.archiver.MavenArchiveConfiguration; import org.apache.maven.artifact.repository.ArtifactRepository; @@ -30,18 +30,18 @@ public class DockerAssemblyConfigurationSource implements AssemblerConfigurationSource { private final AssemblyConfiguration assemblyConfig; - private final MojoParameters params; + private final MavenBuildContext context; private final BuildDirs buildDirs; // Required by configuration source and duplicated from AbstractAssemblyMojo (which is unfortunately - // not extracted to be usab;e + // not extracted to be usable private FixedStringSearchInterpolator commandLinePropertiesInterpolator; private FixedStringSearchInterpolator envInterpolator; private FixedStringSearchInterpolator rootInterpolator; private FixedStringSearchInterpolator mainProjectInterpolator; - public DockerAssemblyConfigurationSource(MojoParameters params, BuildDirs buildDirs, AssemblyConfiguration assemblyConfig) { - this.params = params; + public DockerAssemblyConfigurationSource(MavenBuildContext context, BuildDirs buildDirs, AssemblyConfiguration assemblyConfig) { + this.context = context; this.assemblyConfig = assemblyConfig; this.buildDirs = buildDirs; } @@ -52,7 +52,7 @@ public String[] getDescriptors() { String descriptor = assemblyConfig.getDescriptor(); if (descriptor != null) { - return new String[] {EnvUtil.prepareAbsoluteSourceDirPath(params, descriptor).getAbsolutePath() }; + return new String[] {EnvUtil.prepareAbsoluteSourceDirPath(context, descriptor).getAbsolutePath() }; } } return new String[0]; @@ -95,39 +95,39 @@ public String getFinalName() { @Override public ArtifactRepository getLocalRepository() { - return params.getSession().getLocalRepository(); + return context.getSession().getLocalRepository(); } - + public MavenFileFilter getMavenFileFilter() { - return params.getMavenFileFilter(); + return context.getMavenFileFilter(); } // Maybe use injection @Override public List getReactorProjects() { - return params.getReactorProjects(); + return context.getReactorProjects(); } // Maybe use injection @Override public List getRemoteRepositories() { - return params.getProject().getRemoteArtifactRepositories(); + return context.getProject().getRemoteArtifactRepositories(); } @Override public MavenSession getMavenSession() { - return params.getSession(); + return context.getSession(); } @Override public MavenArchiveConfiguration getJarArchiveConfiguration() { - return params.getArchiveConfiguration(); + return context.getArchiveConfiguration(); } // X @Override public String getEncoding() { - return params.getProject().getProperties().getProperty("project.build.sourceEncoding"); + return context.getProject().getProperties().getProperty("project.build.sourceEncoding"); } // X @@ -180,13 +180,13 @@ public FixedStringSearchInterpolator getMainProjectInterpolator() // X @Override public MavenProject getProject() { - return params.getProject(); + return context.getProject(); } // X @Override public File getBasedir() { - return params.getProject().getBasedir(); + return context.getProject().getBasedir(); } // X @@ -256,7 +256,7 @@ public String getArchiverConfig() { @Override public MavenReaderFilter getMavenReaderFilter() { - return params.getMavenFilterReader(); + return context.getMavenReaderFilter(); } @Override @@ -271,7 +271,10 @@ public boolean isUseJvmChmod() { @Override public boolean isIgnorePermissions() { - return assemblyConfig != null ? assemblyConfig.isIgnorePermissions() : false; + return + assemblyConfig != null && + assemblyConfig.getPermissions() != null && + assemblyConfig.getPermissions() == AssemblyConfiguration.PermissionMode.ignore; } // ======================================================================= diff --git a/src/main/java/io/fabric8/maven/docker/assembly/DockerAssemblyManager.java b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyManager.java similarity index 72% rename from src/main/java/io/fabric8/maven/docker/assembly/DockerAssemblyManager.java rename to src/main/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyManager.java index 8760c2ced..cd9c3ed2e 100644 --- a/src/main/java/io/fabric8/maven/docker/assembly/DockerAssemblyManager.java +++ b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyManager.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.assembly; +package io.fabric8.maven.docker.build.maven.assembly; import java.io.File; import java.io.FileWriter; @@ -7,16 +7,18 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; - -import io.fabric8.maven.docker.config.ArchiveCompression; -import io.fabric8.maven.docker.config.Arguments; -import io.fabric8.maven.docker.config.AssemblyConfiguration; -import io.fabric8.maven.docker.config.AssemblyMode; -import io.fabric8.maven.docker.config.BuildImageConfiguration; +import java.util.function.Function; + +import io.fabric8.maven.docker.build.docker.DockerFileBuilder; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; +import io.fabric8.maven.docker.config.build.ArchiveCompression; +import io.fabric8.maven.docker.config.build.AssemblyConfiguration; +import io.fabric8.maven.docker.config.build.AssemblyMode; +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.config.maven.MavenAssemblyConfiguration; import io.fabric8.maven.docker.util.DockerFileUtil; import io.fabric8.maven.docker.util.EnvUtil; import io.fabric8.maven.docker.util.Logger; -import io.fabric8.maven.docker.util.MojoParameters; import org.apache.commons.io.IOUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Build; @@ -53,9 +55,6 @@ @Component(role = DockerAssemblyManager.class, instantiationStrategy = "per-lookup") public class DockerAssemblyManager { - public static final String DEFAULT_DATA_BASE_IMAGE = "busybox:latest"; - public static final String SCRATCH_IMAGE = "scratch"; - // Assembly name used also as build directory within outputBuildDir public static final String DOCKER_IGNORE = ".maven-dockerignore"; public static final String DOCKER_EXCLUDE = ".maven-dockerexclude"; @@ -79,74 +78,59 @@ public class DockerAssemblyManager { * creating the image. * * @param imageName Name of the image to create (used for creating build directories) - * @param params Mojos parameters (used for finding the directories) + * @param context Mojos parameters (used for finding the directories) * @param buildConfig configuration for how to build the image - * @param log Logger used to display warning if permissions are to be normalized - * @return file holding the path to the created assembly tar file - * @throws MojoExecutionException - */ - public File createDockerTarArchive(String imageName, MojoParameters params, BuildImageConfiguration buildConfig, Logger log) - throws MojoExecutionException { - return createDockerTarArchive(imageName, params, buildConfig, log, null); - } - - /** - * Create an docker tar archive from the given configuration which can be send to the Docker host for - * creating the image. - * - * @param imageName Name of the image to create (used for creating build directories) - * @param params Mojos parameters (used for finding the directories) - * @param buildConfig configuration for how to build the image - * @param log Logger used to display warning if permissions are to be normalized * @param finalCustomizer finalCustomizer to be applied to the tar archive * @return file holding the path to the created assembly tar file * @throws MojoExecutionException */ - public File createDockerTarArchive(String imageName, final MojoParameters params, final BuildImageConfiguration buildConfig, Logger log, ArchiverCustomizer finalCustomizer) - throws MojoExecutionException { + public File createDockerTarArchive(String imageName, final MavenBuildContext context, final BuildConfiguration buildConfig, ArchiverCustomizer finalCustomizer, Logger log) + throws IOException { - final BuildDirs buildDirs = createBuildDirs(imageName, params); + final BuildDirs buildDirs = createBuildDirs(imageName, context); final AssemblyConfiguration assemblyConfig = buildConfig.getAssemblyConfiguration(); final List archiveCustomizers = new ArrayList<>(); // Build up assembly. In dockerfile mode this must be added explicitly in the Dockerfile with an ADD if (hasAssemblyConfiguration(assemblyConfig)) { - createAssemblyArchive(assemblyConfig, params, buildDirs); + createAssemblyArchive(assemblyConfig, context, buildDirs); } try { if (buildConfig.isDockerFileMode()) { // Use specified docker directory which must include a Dockerfile. - final File dockerFile = buildConfig.getAbsoluteDockerFilePath(params); + final File dockerFile = + EnvUtil.prepareAbsoluteSourceDirPath(context, buildConfig.calculateDockerFilePath().getPath()); if (!dockerFile.exists()) { - throw new MojoExecutionException("Configured Dockerfile \"" + - buildConfig.getDockerFile() + "\" (resolved to \"" + dockerFile + "\") doesn't exist"); + throw new IOException("Configured Dockerfile \"" + + buildConfig.getDockerFile() + "\" (resolved to \"" + dockerFile + "\") doesn't exist"); } - FixedStringSearchInterpolator interpolator = DockerFileUtil.createInterpolator(params, buildConfig.getFilter()); - verifyGivenDockerfile(dockerFile, buildConfig, interpolator, log); + FixedStringSearchInterpolator interpolator = DockerFileUtil.createInterpolator(context, buildConfig.getFilter()); + verifyGivenDockerfile(dockerFile, buildConfig, interpolator::interpolate, log); interpolateDockerfile(dockerFile, buildDirs, interpolator); // User dedicated Dockerfile from extra directory - archiveCustomizers.add(new ArchiverCustomizer() { - @Override - public TarArchiver customize(TarArchiver archiver) throws IOException { - DefaultFileSet fileSet = DefaultFileSet.fileSet(dockerFile.getParentFile()); - addDockerIncludesExcludesIfPresent(fileSet, params); - // Exclude non-interpolated dockerfile from source tree - // Interpolated Dockerfile is already added as it was created into the output directory when - // using dir dir mode - excludeDockerfile(fileSet, dockerFile); - - // If the content is added as archive, then we need to add the Dockerfile from the builddir - // directly to docker.tar (as the output builddir is not picked up in archive mode) - if (isArchive(assemblyConfig)) { - String name = dockerFile.getName(); - archiver.addFile(new File(buildDirs.getOutputDirectory(), name), name); - } - - archiver.addFileSet(fileSet); - return archiver; + archiveCustomizers.add(archiver -> { + File contextDir = buildConfig.getContextDir() != null ? new File(buildConfig.getContextDir()) : dockerFile.getParentFile(); + if (!contextDir.exists()) { + throw new IOException(String.format("Docker context directory %s doesn't exist", contextDir.getAbsolutePath())); } + DefaultFileSet fileSet = DefaultFileSet.fileSet(contextDir); + addDockerIncludesExcludesIfPresent(fileSet, context); + // Exclude non-interpolated dockerfile from source tree + // Interpolated Dockerfile is already added as it was created into the output directory when + // using dir dir mode + excludeDockerfile(fileSet, dockerFile); + + // If the content is added as archive, then we need to add the Dockerfile from the builddir + // directly to docker.tar (as the output builddir is not picked up in archive mode) + if (isArchive(assemblyConfig)) { + String name = dockerFile.getName(); + archiver.addFile(new File(buildDirs.getOutputDirectory(), name), name); + } + + archiver.addFileSet(fileSet); + return archiver; }); } else { // Create custom docker file in output dir @@ -154,12 +138,9 @@ public TarArchiver customize(TarArchiver archiver) throws IOException { builder.write(buildDirs.getOutputDirectory()); // Add own Dockerfile final File dockerFile = new File(buildDirs.getOutputDirectory(), DOCKERFILE_NAME); - archiveCustomizers.add(new ArchiverCustomizer() { - @Override - public TarArchiver customize(TarArchiver archiver) throws IOException { - archiver.addFile(dockerFile, DOCKERFILE_NAME); - return archiver; - } + archiveCustomizers.add(archiver -> { + archiver.addFile(dockerFile, DOCKERFILE_NAME); + return archiver; }); } @@ -179,7 +160,7 @@ public TarArchiver customize(TarArchiver archiver) throws IOException { return createBuildTarBall(buildDirs, archiveCustomizers, assemblyConfig, buildConfig.getCompression()); } catch (IOException e) { - throw new MojoExecutionException(String.format("Cannot create %s in %s", DOCKERFILE_NAME, buildDirs.getOutputDirectory()), e); + throw new IOException(String.format("Cannot create %s in %s", DOCKERFILE_NAME, buildDirs.getOutputDirectory()), e); } } @@ -202,7 +183,7 @@ private void interpolateDockerfile(File dockerFile, BuildDirs params, FixedStrin } // visible for testing - void verifyGivenDockerfile(File dockerFile, BuildImageConfiguration buildConfig, FixedStringSearchInterpolator interpolator, Logger log) throws IOException { + void verifyGivenDockerfile(File dockerFile, BuildConfiguration buildConfig, Function interpolator, Logger log) throws IOException { AssemblyConfiguration assemblyConfig = buildConfig.getAssemblyConfiguration(); if (assemblyConfig == null) { return; @@ -237,15 +218,15 @@ void verifyGivenDockerfile(File dockerFile, BuildImageConfiguration buildConfig, * Extract all files with a tracking archiver. These can be used to track changes in the filesystem and triggering * a rebuild of the image if needed ('docker:watch') */ - public AssemblyFiles getAssemblyFiles(String name, BuildImageConfiguration buildConfig, MojoParameters mojoParams, Logger log) - throws InvalidAssemblerConfigurationException, ArchiveCreationException, AssemblyFormattingException, MojoExecutionException { + public AssemblyFiles getAssemblyFiles(String name, BuildConfiguration buildConfig, MavenBuildContext context, Logger log) + throws InvalidAssemblerConfigurationException, ArchiveCreationException, AssemblyFormattingException, IOException { - BuildDirs buildDirs = createBuildDirs(name, mojoParams); + BuildDirs buildDirs = createBuildDirs(name, context); AssemblyConfiguration assemblyConfig = buildConfig.getAssemblyConfiguration(); String assemblyName = assemblyConfig.getName(); DockerAssemblyConfigurationSource source = - new DockerAssemblyConfigurationSource(mojoParams, buildDirs, assemblyConfig); + new DockerAssemblyConfigurationSource(context, buildDirs, assemblyConfig); Assembly assembly = getAssemblyConfig(assemblyConfig, source); @@ -254,19 +235,21 @@ public AssemblyFiles getAssemblyFiles(String name, BuildImageConfiguration build ta.init(log, assemblyName); assembly.setId("tracker"); assemblyArchiver.createArchive(assembly, assemblyName, "track", source, false, null); - return ta.getAssemblyFiles(mojoParams.getSession()); + return ta.getAssemblyFiles(context.getSession()); } } - private BuildDirs createBuildDirs(String imageName, MojoParameters params) { - BuildDirs buildDirs = new BuildDirs(imageName, params); + private BuildDirs createBuildDirs(String imageName, MavenBuildContext context) { + BuildDirs buildDirs = new BuildDirs(imageName, context); buildDirs.createDirs(); return buildDirs; } private boolean hasAssemblyConfiguration(AssemblyConfiguration assemblyConfig) { + boolean hasInlineAssembly = (assemblyConfig instanceof MavenAssemblyConfiguration) && + ((MavenAssemblyConfiguration) assemblyConfig).getInline() != null; return assemblyConfig != null && - (assemblyConfig.getInline() != null || + (hasInlineAssembly || assemblyConfig.getDescriptor() != null || assemblyConfig.getDescriptorRef() != null); } @@ -278,9 +261,9 @@ private boolean isArchive(AssemblyConfiguration assemblyConfig) { } public File createChangedFilesArchive(List entries, File assemblyDirectory, - String imageName, MojoParameters mojoParameters) - throws MojoExecutionException { - BuildDirs dirs = createBuildDirs(imageName, mojoParameters); + String imageName, MavenBuildContext context) + throws IOException { + BuildDirs dirs = createBuildDirs(imageName, context); try { File archive = new File(dirs.getTemporaryRootDirectory(), "changed-files.tar"); File archiveDir = createArchiveDir(dirs); @@ -290,8 +273,8 @@ public File createChangedFilesArchive(List entries, File as } return createChangedFilesTarBall(archive, archiveDir); } catch (IOException exp) { - throw new MojoExecutionException("Error while creating " + dirs.getTemporaryRootDirectory() + - "/changed-files.tar: " + exp); + throw new IOException("Error while creating " + dirs.getTemporaryRootDirectory() + + "/changed-files.tar: " + exp); } } @@ -303,7 +286,7 @@ private File prepareChangedFilesArchivePath(File archiveDir, File destFile, File // Create final tar-ball to be used for building the archive to send to the Docker daemon private File createBuildTarBall(BuildDirs buildDirs, List archiverCustomizers, - AssemblyConfiguration assemblyConfig, ArchiveCompression compression) throws MojoExecutionException { + AssemblyConfiguration assemblyConfig, ArchiveCompression compression) throws IOException { File archive = new File(buildDirs.getTemporaryRootDirectory(), "docker-build." + compression.getFileSuffix()); try { TarArchiver archiver = createBuildArchiver(buildDirs.getOutputDirectory(), archive, assemblyConfig); @@ -312,22 +295,37 @@ private File createBuildTarBall(BuildDirs buildDirs, List ar archiver = customizer.customize(archiver); } } - archiver.setCompression(compression.getTarCompressionMethod()); + archiver.setCompression(getTarCompressionMethod(compression)); archiver.createArchive(); return archive; } catch (NoSuchArchiverException e) { - throw new MojoExecutionException("No archiver for type 'tar' found", e); + throw new IOException("No archiver for type 'tar' found", e); } catch (IOException e) { - throw new MojoExecutionException("Cannot create archive " + archive, e); + throw new IOException("Cannot create archive " + archive, e); } } - private void addDockerIncludesExcludesIfPresent(DefaultFileSet fileSet, MojoParameters params) throws IOException { + private TarArchiver.TarCompressionMethod getTarCompressionMethod(ArchiveCompression compression) { + if (compression == null) { + return TarArchiver.TarCompressionMethod.none; + } + switch (compression) { + case gzip: + return TarArchiver.TarCompressionMethod.gzip; + case bzip2: + return TarArchiver.TarCompressionMethod.bzip2; + case none: + default: + return TarArchiver.TarCompressionMethod.none; + } + } + + private void addDockerIncludesExcludesIfPresent(DefaultFileSet fileSet, MavenBuildContext params) throws IOException { addDockerExcludes(fileSet, params); addDockerIncludes(fileSet); } - private void addDockerExcludes(DefaultFileSet fileSet, MojoParameters params) throws IOException { + private void addDockerExcludes(DefaultFileSet fileSet, MavenBuildContext params) throws IOException { File directory = fileSet.getDirectory(); List excludes = new ArrayList<>(); // Output directory will be always excluded @@ -351,7 +349,7 @@ private void addDockerIncludes(DefaultFileSet fileSet) throws IOException { } } - private File createChangedFilesTarBall(File archive, File archiveDir) throws MojoExecutionException { + private File createChangedFilesTarBall(File archive, File archiveDir) throws IOException { try { TarArchiver archiver = (TarArchiver) archiverManager.getArchiver("tar"); archiver.setLongfile(TarLongFileMode.posix); @@ -360,23 +358,23 @@ private File createChangedFilesTarBall(File archive, File archiveDir) throws Moj archiver.createArchive(); return archive; } catch (NoSuchArchiverException e) { - throw new MojoExecutionException("No archiver for type 'tar' found", e); + throw new IOException("No archiver for type 'tar' found", e); } catch (IOException e) { - throw new MojoExecutionException("Cannot create archive " + archive, e); + throw new IOException("Cannot create archive " + archive, e); } catch (RuntimeException e) { e.printStackTrace(); throw e; } } - private File createArchiveDir(BuildDirs dirs) throws IOException, MojoExecutionException { + private File createArchiveDir(BuildDirs dirs) throws IOException { File archiveDir = new File(dirs.getTemporaryRootDirectory(), "changed-files"); if (archiveDir.exists()) { // Remove old stuff to FileUtils.cleanDirectory(archiveDir); } else { if (!archiveDir.mkdir()) { - throw new MojoExecutionException("Cannot create " + archiveDir); + throw new IOException("Cannot create " + archiveDir); } } return archiveDir; @@ -405,7 +403,7 @@ private TarArchiver createBuildArchiver(File outputDir, File archive, AssemblyCo // visible for testing @SuppressWarnings("deprecation") - DockerFileBuilder createDockerFileBuilder(BuildImageConfiguration buildConfig, AssemblyConfiguration assemblyConfig) { + DockerFileBuilder createDockerFileBuilder(BuildConfiguration buildConfig, AssemblyConfiguration assemblyConfig) { DockerFileBuilder builder = new DockerFileBuilder() .env(buildConfig.getEnv()) @@ -424,7 +422,7 @@ DockerFileBuilder createDockerFileBuilder(BuildImageConfiguration buildConfig, A builder.add(assemblyConfig.getName(), "") .basedir(assemblyConfig.getTargetDir()) .assemblyUser(assemblyConfig.getUser()) - .exportTargetDir(assemblyConfig.exportTargetDir()); + .exportTargetDir(assemblyConfig.getExportTargetDir()); } else { builder.exportTargetDir(false); } @@ -437,28 +435,25 @@ DockerFileBuilder createDockerFileBuilder(BuildImageConfiguration buildConfig, A if (buildConfig.getCmd() != null){ builder.cmd(buildConfig.getCmd()); - } else if (buildConfig.getCommand() != null) { - Arguments args = Arguments.Builder.get().withShell(buildConfig.getCommand()).build(); - builder.cmd(args); } if (buildConfig.getEntryPoint() != null){ builder.entryPoint(buildConfig.getEntryPoint()); } - if (buildConfig.optimise()) { + if (buildConfig.getOptimise() != null && buildConfig.getOptimise()) { builder.optimise(); } return builder; } - private void createAssemblyArchive(AssemblyConfiguration assemblyConfig, MojoParameters params, BuildDirs buildDirs) - throws MojoExecutionException { + private void createAssemblyArchive(AssemblyConfiguration assemblyConfig, MavenBuildContext params, BuildDirs buildDirs) + throws IOException { DockerAssemblyConfigurationSource source = new DockerAssemblyConfigurationSource(params, buildDirs, assemblyConfig); Assembly assembly = getAssemblyConfig(assemblyConfig, source); - AssemblyMode buildMode = assemblyConfig.getMode(); + AssemblyMode buildMode = assemblyConfig.getMode() != null ? assemblyConfig.getMode() : AssemblyMode.dir; File originalArtifactFile = null; try { originalArtifactFile = ensureThatArtifactFileIsSet(params.getProject()); @@ -472,11 +467,9 @@ private void createAssemblyArchive(AssemblyConfiguration assemblyConfig, MojoPar "built the artifact before with 'mvn package' (should be available in the target/ dir). " + "Please see the documentation (section \"Assembly\") for more information."; } - throw new MojoExecutionException(error, e); + throw new IOException(error, e); } catch (InvalidAssemblerConfigurationException e) { - throw new MojoExecutionException(assembly, "Assembly is incorrectly configured: " + assembly.getId(), - "Assembly: " + assembly.getId() + " is not configured correctly: " - + e.getMessage()); + throw new IOException("Assembly: " + assembly.getId() + " is not configured correctly: " + e.getMessage(), e); } finally { setArtifactFile(params.getProject(), originalArtifactFile); } @@ -524,28 +517,31 @@ private void setArtifactFile(MavenProject project, File artifactFile) { } private Assembly getAssemblyConfig(AssemblyConfiguration assemblyConfig, DockerAssemblyConfigurationSource source) - throws MojoExecutionException { - Assembly assembly = assemblyConfig.getInline(); + throws IOException { + Assembly assembly = null; + if (assemblyConfig instanceof MavenAssemblyConfiguration) { + assembly = ((MavenAssemblyConfiguration) assemblyConfig).getInline(); + } if (assembly == null) { assembly = extractAssembly(source); } return assembly; } - private Assembly extractAssembly(AssemblerConfigurationSource config) throws MojoExecutionException { + private Assembly extractAssembly(AssemblerConfigurationSource config) throws IOException { try { List assemblies = assemblyReader.readAssemblies(config); if (assemblies.size() != 1) { - throw new MojoExecutionException("Only one assembly can be used for creating a Docker base image (and not " + throw new IllegalArgumentException("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); + throw new IOException("Error reading assembly: " + e.getMessage(), e); } catch (InvalidAssemblerConfigurationException e) { - throw new MojoExecutionException(assemblyReader, e.getMessage(), "Docker assembly configuration is invalid: " + e.getMessage()); + throw new IOException("Docker assembly configuration is invalid: " + e.getMessage(), e); } } diff --git a/src/main/java/io/fabric8/maven/docker/assembly/MappingTrackArchiver.java b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/MappingTrackArchiver.java similarity index 99% rename from src/main/java/io/fabric8/maven/docker/assembly/MappingTrackArchiver.java rename to src/main/java/io/fabric8/maven/docker/build/maven/assembly/MappingTrackArchiver.java index 1e939d72a..bc6261352 100644 --- a/src/main/java/io/fabric8/maven/docker/assembly/MappingTrackArchiver.java +++ b/src/main/java/io/fabric8/maven/docker/build/maven/assembly/MappingTrackArchiver.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.assembly;/* +package io.fabric8.maven.docker.build.maven.assembly;/* * * Copyright 2014 Roland Huss * diff --git a/src/main/java/io/fabric8/maven/docker/config/DockerMachineConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/DockerMachineConfiguration.java index 0c3c55394..1faff9dcb 100644 --- a/src/main/java/io/fabric8/maven/docker/config/DockerMachineConfiguration.java +++ b/src/main/java/io/fabric8/maven/docker/config/DockerMachineConfiguration.java @@ -3,8 +3,6 @@ import java.io.Serializable; import java.util.Map; -import org.apache.maven.plugins.annotations.Parameter; - public class DockerMachineConfiguration implements Serializable { public static final String DOCKER_MACHINE_NAME_PROP = "docker.machine.name"; @@ -14,19 +12,16 @@ public class DockerMachineConfiguration implements Serializable { /** * Name of the docker-machine */ - @Parameter private String name = "default"; /** * Should the docker-machine be created if it does not exist? */ - @Parameter private Boolean autoCreate = Boolean.FALSE; /** * Should the docker-machine's certificates be regenerated after starting? */ - @Parameter private Boolean regenerateCertsAfterStart = Boolean.FALSE; /** @@ -37,7 +32,6 @@ public class DockerMachineConfiguration implements Serializable { * <virtualbox-no-share/> * */ - @Parameter private Map createOptions; public DockerMachineConfiguration() {} diff --git a/src/main/java/io/fabric8/maven/docker/config/ImageConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/ImageConfiguration.java index 1ea2e1839..eefe8cabb 100644 --- a/src/main/java/io/fabric8/maven/docker/config/ImageConfiguration.java +++ b/src/main/java/io/fabric8/maven/docker/config/ImageConfiguration.java @@ -4,59 +4,40 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; -import io.fabric8.maven.docker.util.DeepCopy; -import io.fabric8.maven.docker.util.EnvUtil; -import io.fabric8.maven.docker.util.ImageName; -import io.fabric8.maven.docker.util.Logger; -import io.fabric8.maven.docker.util.StartOrderResolver; -import org.apache.maven.plugins.annotations.Parameter; +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import org.apache.commons.lang3.SerializationUtils; /** * @author roland * @since 02.09.14 */ -public class ImageConfiguration implements StartOrderResolver.Resolvable, Serializable { +public class ImageConfiguration implements Serializable { - @Parameter(required = true) private String name; - @Parameter private String alias; - @Parameter - private RunImageConfiguration run; + private String registry; + + private RunConfiguration run; - @Parameter - private BuildImageConfiguration build; + private BuildConfiguration build; - @Parameter - private WatchImageConfiguration watch; + private WatchConfiguration watch; - @Parameter private Map external; - @Parameter - private String registry; // Used for injection public ImageConfiguration() {} - @Override public String getName() { return name; } - /** - * Change the name which can be useful in long running runs e.g. for updating - * images when doing updates. Use with caution and only for those circumstances. - * - * @param name image name to set. - */ - public void setName(String name) { - this.name = name; - } - /** * Override externalConfiguration when defined via special property. * @@ -66,20 +47,19 @@ public void setExternalConfiguration(Map externalConfiguration) this.external = externalConfiguration; } - @Override - public String getAlias() { + public String getAlias() { return alias; } - public RunImageConfiguration getRunConfiguration() { - return (run == null) ? RunImageConfiguration.DEFAULT : run; + public RunConfiguration getRunConfiguration() { + return (run == null) ? RunConfiguration.DEFAULT : run; } - public BuildImageConfiguration getBuildConfiguration() { + public BuildConfiguration getBuildConfiguration() { return build; } - public WatchImageConfiguration getWatchConfiguration() { + public WatchConfiguration getWatchConfiguration() { return watch; } @@ -87,53 +67,6 @@ public Map getExternalConfig() { return external; } - @Override - public List getDependencies() { - RunImageConfiguration runConfig = getRunConfiguration(); - List ret = new ArrayList<>(); - if (runConfig != null) { - addVolumes(runConfig, ret); - addLinks(runConfig, ret); - addContainerNetwork(runConfig, ret); - addDependsOn(runConfig, ret); - } - return ret; - } - - private void addVolumes(RunImageConfiguration runConfig, List ret) { - RunVolumeConfiguration volConfig = runConfig.getVolumeConfiguration(); - if (volConfig != null) { - List volumeImages = volConfig.getFrom(); - if (volumeImages != null) { - ret.addAll(volumeImages); - } - } - } - - private void addLinks(RunImageConfiguration runConfig, List ret) { - // Custom networks can have circular links, no need to be considered for the starting order. - if (!runConfig.getNetworkingConfig().isCustomNetwork()) { - for (String[] link : EnvUtil.splitOnLastColon(runConfig.getLinks())) { - ret.add(link[0]); - } - } - } - - private void addContainerNetwork(RunImageConfiguration runConfig, List ret) { - NetworkConfig config = runConfig.getNetworkingConfig(); - String alias = config.getContainerAlias(); - if (alias != null) { - ret.add(alias); - } - } - - private void addDependsOn(RunImageConfiguration runConfig, List ret) { - // Only used in custom networks. - if (runConfig.getNetworkingConfig().isCustomNetwork()) { - ret.addAll(runConfig.getDependsOn()); - } - } - public boolean isDataImage() { // If there is no explicit run configuration, its a data image // TODO: Probably add an explicit property so that a user can indicated whether it @@ -154,23 +87,23 @@ public String toString() { return String.format("ImageConfiguration {name='%s', alias='%s'}", name, alias); } - public String initAndValidate(ConfigHelper.NameFormatter nameFormatter, Logger log) { + public String[] validate(NameFormatter nameFormatter) { name = nameFormatter.format(name); - String minimalApiVersion = null; + List apiVersions = new ArrayList<>(); if (build != null) { - minimalApiVersion = build.initAndValidate(log); + apiVersions.add(build.validate()); } if (run != null) { - minimalApiVersion = EnvUtil.extractLargerVersion(minimalApiVersion, run.initAndValidate()); + apiVersions.add(run.validate()); } - return minimalApiVersion; + return apiVersions.stream().filter(Objects::nonNull).toArray(String[]::new); } // ========================================================================= // Builder for image configurations public static class Builder { - private final ImageConfiguration config; + protected ImageConfiguration config; public Builder() { this(null); @@ -181,7 +114,7 @@ public Builder(ImageConfiguration that) { if (that == null) { this.config = new ImageConfiguration(); } else { - this.config = DeepCopy.copy(that); + this.config = SerializationUtils.clone(that); } } @@ -195,12 +128,12 @@ public Builder alias(String alias) { return this; } - public Builder runConfig(RunImageConfiguration runConfig) { + public Builder runConfig(RunConfiguration runConfig) { config.run = runConfig; return this; } - public Builder buildConfig(BuildImageConfiguration buildConfig) { + public Builder buildConfig(BuildConfiguration buildConfig) { config.build = buildConfig; return this; } @@ -219,9 +152,21 @@ public ImageConfiguration build() { return config; } - public Builder watchConfig(WatchImageConfiguration watchConfig) { + public Builder watchConfig(WatchConfiguration watchConfig) { config.watch = watchConfig; return this; } } + + // ===================================================================== + /** + * Format an image name by replacing certain placeholders + */ + public interface NameFormatter { + String format(String name); + + NameFormatter IDENTITY = name -> name; + } + + } diff --git a/src/main/java/io/fabric8/maven/docker/util/ImageName.java b/src/main/java/io/fabric8/maven/docker/config/ImageName.java similarity index 99% rename from src/main/java/io/fabric8/maven/docker/util/ImageName.java rename to src/main/java/io/fabric8/maven/docker/config/ImageName.java index 601f4eca9..e64d33ebc 100644 --- a/src/main/java/io/fabric8/maven/docker/util/ImageName.java +++ b/src/main/java/io/fabric8/maven/docker/config/ImageName.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.util; +package io.fabric8.maven.docker.config; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/io/fabric8/maven/docker/config/RegistryAuthConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/RegistryAuthConfiguration.java deleted file mode 100644 index 68364e1e4..000000000 --- a/src/main/java/io/fabric8/maven/docker/config/RegistryAuthConfiguration.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.fabric8.maven.docker.config; - -import java.io.Serializable; -import java.util.Map; -import java.util.TreeMap; - -import io.fabric8.maven.docker.util.AuthConfigFactory; -import org.apache.commons.lang3.StringUtils; -import org.apache.maven.plugins.annotations.Parameter; - -public class RegistryAuthConfiguration implements Serializable { - - @Parameter - private Map push; - - @Parameter - private Map pull; - - @Parameter - private String username; - - @Parameter - private String password; - - @Parameter - private String email; - - @Parameter - private String authToken; - - public Map toMap() { - final Map authMap = new TreeMap<>(); - - if (push != null) { - authMap.put("push", push); - } - if (pull != null) { - authMap.put("pull", pull); - } - if (StringUtils.isNotBlank(username)) { - authMap.put(AuthConfigFactory.AUTH_USERNAME, username); - } - if (StringUtils.isNotBlank(password)) { - authMap.put(AuthConfigFactory.AUTH_PASSWORD, password); - } - if (StringUtils.isNotBlank(authToken)) { - authMap.put(AuthConfigFactory.AUTH_AUTHTOKEN, authToken); - } - if (StringUtils.isNotBlank(email)) { - authMap.put(AuthConfigFactory.AUTH_EMAIL,email); - } - return authMap; - } -} diff --git a/src/main/java/io/fabric8/maven/docker/config/WatchImageConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/WatchConfiguration.java similarity index 72% rename from src/main/java/io/fabric8/maven/docker/config/WatchImageConfiguration.java rename to src/main/java/io/fabric8/maven/docker/config/WatchConfiguration.java index 76d970634..a9cf3ddf2 100644 --- a/src/main/java/io/fabric8/maven/docker/config/WatchImageConfiguration.java +++ b/src/main/java/io/fabric8/maven/docker/config/WatchConfiguration.java @@ -2,27 +2,22 @@ import java.io.Serializable; -import io.fabric8.maven.docker.util.DeepCopy; -import org.apache.maven.plugins.annotations.Parameter; +import org.apache.commons.lang3.SerializationUtils; /** * Configuration for watching on image changes */ -public class WatchImageConfiguration implements Serializable { +public class WatchConfiguration implements Serializable { - @Parameter private Integer interval; - @Parameter private WatchMode mode; - @Parameter private String postGoal; - @Parameter private String postExec; - public WatchImageConfiguration() {}; + public WatchConfiguration() {}; public int getInterval() { return interval != null ? interval : 5000; @@ -46,17 +41,17 @@ public String getPostExec() { public static class Builder { - private final WatchImageConfiguration c; + private final WatchConfiguration c; public Builder() { this(null); } - public Builder(WatchImageConfiguration that) { + public Builder(WatchConfiguration that) { if (that == null) { - this.c = new WatchImageConfiguration(); + this.c = new WatchConfiguration(); } else { - this.c = DeepCopy.copy(that); + this.c = SerializationUtils.clone(that); } } @@ -82,7 +77,7 @@ public Builder postExec(String exec) { return this; } - public WatchImageConfiguration build() { + public WatchConfiguration build() { return c; } } diff --git a/src/main/java/io/fabric8/maven/docker/config/ArchiveCompression.java b/src/main/java/io/fabric8/maven/docker/config/build/ArchiveCompression.java similarity index 52% rename from src/main/java/io/fabric8/maven/docker/config/ArchiveCompression.java rename to src/main/java/io/fabric8/maven/docker/config/build/ArchiveCompression.java index da98af3bb..ec58dc63b 100644 --- a/src/main/java/io/fabric8/maven/docker/config/ArchiveCompression.java +++ b/src/main/java/io/fabric8/maven/docker/config/build/ArchiveCompression.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.build; /* * * Copyright 2015 Roland Huss @@ -16,13 +16,6 @@ * limitations under the License. */ -import java.io.IOException; -import java.io.OutputStream; -import java.util.zip.GZIPOutputStream; - -import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream; -import org.codehaus.plexus.archiver.tar.TarArchiver; - /** * Enumeration for determine the compression mode when creating docker * build archives. @@ -32,44 +25,22 @@ */ public enum ArchiveCompression { - none(TarArchiver.TarCompressionMethod.none, "tar"), - - gzip(TarArchiver.TarCompressionMethod.gzip,"tar.gz") { - @Override - public OutputStream wrapOutputStream(OutputStream out) throws IOException { - return new GZIPOutputStream(out); - } - }, - - bzip2(TarArchiver.TarCompressionMethod.bzip2,"tar.bz") { - @Override - public OutputStream wrapOutputStream(OutputStream out) throws IOException { - return new BZip2CompressorOutputStream(out); - } - }; + none("tar"), + gzip("tar.gz"), + bzip2("tar.bz"); // ==================================================================== - private final TarArchiver.TarCompressionMethod tarCompressionMethod; private final String fileSuffix; - ArchiveCompression(TarArchiver.TarCompressionMethod tarCompressionMethod, String fileSuffix) { - this.tarCompressionMethod = tarCompressionMethod; + ArchiveCompression(String fileSuffix) { this.fileSuffix = fileSuffix; } - public TarArchiver.TarCompressionMethod getTarCompressionMethod() { - return tarCompressionMethod; - } - public String getFileSuffix() { return fileSuffix; } - public OutputStream wrapOutputStream(OutputStream outputStream) throws IOException { - return outputStream; - } - public static ArchiveCompression fromFileName(String filename) { if (filename.endsWith(".tar.gz") || filename.endsWith(".tgz")) { return ArchiveCompression.gzip; diff --git a/src/main/java/io/fabric8/maven/docker/config/Arguments.java b/src/main/java/io/fabric8/maven/docker/config/build/Arguments.java similarity index 86% rename from src/main/java/io/fabric8/maven/docker/config/Arguments.java rename to src/main/java/io/fabric8/maven/docker/config/build/Arguments.java index ffc462e84..41c6d2d76 100644 --- a/src/main/java/io/fabric8/maven/docker/config/Arguments.java +++ b/src/main/java/io/fabric8/maven/docker/config/build/Arguments.java @@ -1,17 +1,16 @@ -package io.fabric8.maven.docker.config; - -import io.fabric8.maven.docker.util.EnvUtil; -import org.apache.maven.plugins.annotations.Parameter; +package io.fabric8.maven.docker.config.build; import java.io.Serializable; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; public class Arguments implements Serializable { - @Parameter private String shell; - @Parameter private List exec; /** @@ -105,7 +104,12 @@ public void validate() throws IllegalArgumentException { public List asStrings() { if (shell != null) { - return Arrays.asList(EnvUtil.splitOnSpaceWithEscape(shell)); + String[] split = shell.split("(? T set(T prop) { + protected T set(T prop) { if (prop != null) { isEmpty = false; } diff --git a/src/main/java/io/fabric8/maven/docker/config/AssemblyMode.java b/src/main/java/io/fabric8/maven/docker/config/build/AssemblyMode.java similarity index 96% rename from src/main/java/io/fabric8/maven/docker/config/AssemblyMode.java rename to src/main/java/io/fabric8/maven/docker/config/build/AssemblyMode.java index a1d0117aa..17bd72944 100644 --- a/src/main/java/io/fabric8/maven/docker/config/AssemblyMode.java +++ b/src/main/java/io/fabric8/maven/docker/config/build/AssemblyMode.java @@ -1,5 +1,7 @@ -package io.fabric8.maven.docker.config;/* - * +package io.fabric8.maven.docker.config.build; + +/* + * * Copyright 2014 Roland Huss * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/main/java/io/fabric8/maven/docker/config/BuildImageConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/build/BuildConfiguration.java similarity index 58% rename from src/main/java/io/fabric8/maven/docker/config/BuildImageConfiguration.java rename to src/main/java/io/fabric8/maven/docker/config/build/BuildConfiguration.java index 9527dfa5c..58b8bdff8 100644 --- a/src/main/java/io/fabric8/maven/docker/config/BuildImageConfiguration.java +++ b/src/main/java/io/fabric8/maven/docker/config/build/BuildConfiguration.java @@ -1,36 +1,33 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.build; import java.io.File; import java.io.Serializable; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; -import io.fabric8.maven.docker.util.*; -import org.apache.maven.plugins.annotations.Parameter; - -import javax.annotation.Nonnull; +import org.apache.commons.lang3.SerializationUtils; /** * @author roland * @since 02.09.14 */ -public class BuildImageConfiguration implements Serializable { - - public static final String DEFAULT_FILTER = "${*}"; - public static final String DEFAULT_CLEANUP = "try"; +public class BuildConfiguration implements Serializable { /** - * Directory holding an external Dockerfile which is used to build the - * image. This Dockerfile will be enriched by the addition build configuration + * Directory used as the contexst directory, e.g. for a docker build. */ - @Parameter - private String dockerFileDir; + private String contextDir; /** * Path to a dockerfile to use. Its parent directory is used as build context (i.e. as dockerFileDir). - * Multiple different Dockerfiles can be specified that way. If set overwrites a possibly givem - * dockerFileDir + * Multiple different Dockerfiles can be specified that way. If set overwrites a possibly given + * contextDir */ - @Parameter private String dockerFile; /** @@ -38,137 +35,92 @@ public class BuildImageConfiguration implements Serializable { * Note only either dockerFile/dockerFileDir or * dockerArchive can be used. */ - @Parameter private String dockerArchive; /** * How interpolation of a dockerfile should be performed */ - @Parameter private String filter; /** * Base Image */ - @Parameter private String from; /** * Extended version for */ - @Parameter private Map fromExt; - @Parameter private String registry; - @Parameter private String maintainer; - @Parameter private List ports; /** * Policy for pulling the base images */ - @Parameter private String imagePullPolicy; /** * RUN Commands within Build/Image */ - @Parameter private List runCmds; - @Parameter private String cleanup; - @Parameter private Boolean nocache; - @Parameter private Boolean optimise; - @Parameter private List volumes; - @Parameter private List tags; - @Parameter private Map env; - @Parameter private Map labels; - @Parameter private Map args; - @Parameter private Arguments entryPoint; - @Parameter - @Deprecated - private String command; - - @Parameter private String workdir; - @Parameter private Arguments cmd; - @Parameter private String user; - @Parameter private HealthCheckConfiguration healthCheck; - @Parameter private AssemblyConfiguration assembly; - @Parameter private Boolean skip; - @Parameter private ArchiveCompression compression = ArchiveCompression.none; - @Parameter private Map buildOptions; - // Path to Dockerfile to use, initialized lazily .... - private File dockerFileFile, dockerArchiveFile; - - public BuildImageConfiguration() {} + public BuildConfiguration() {} public boolean isDockerFileMode() { - return dockerFileFile != null; + return dockerFile != null || contextDir != null; } - public File getDockerFile() { - return dockerFileFile; - } - - public File getDockerArchive() { - return dockerArchiveFile; - } - - public String getDockerFileRaw() { + public String getDockerFile() { return dockerFile; } - public String getDockerArchiveRaw() { + public String getDockerArchive() { return dockerArchive; } - public String getDockerFileDirRaw() { - return dockerFileDir; + public String getContextDir() { + return contextDir; } public String getFilter() { - return filter != null ? filter : DEFAULT_FILTER; - } - - public String getFilterRaw() { return filter; } @@ -199,23 +151,20 @@ public AssemblyConfiguration getAssemblyConfiguration() { return assembly; } - @Nonnull public List getPorts() { - return EnvUtil.removeEmptyEntries(ports); + return removeEmptyEntries(ports); } public String getImagePullPolicy() { return imagePullPolicy; } - @Nonnull public List getVolumes() { - return EnvUtil.removeEmptyEntries(volumes); + return removeEmptyEntries(volumes); } - @Nonnull public List getTags() { - return EnvUtil.removeEmptyEntries(tags); + return removeEmptyEntries(tags); } public Map getEnv() { @@ -230,31 +179,10 @@ public Arguments getCmd() { return cmd; } - @Deprecated - public String getCommand() { - return command; - } - - public String getCleanup() { + public String getCleanupMode() { return cleanup; } - public CleanupMode cleanupMode() { - return CleanupMode.parse(cleanup != null ? cleanup : DEFAULT_CLEANUP); - } - - public boolean nocache() { - return nocache != null ? nocache : false; - } - - public boolean optimise() { - return optimise != null ? optimise : false; - } - - public boolean skip() { - return skip != null ? skip : false; - } - public Boolean getNoCache() { return nocache; } @@ -279,9 +207,8 @@ public Arguments getEntryPoint() { return entryPoint; } - @Nonnull public List getRunCmds() { - return EnvUtil.removeEmptyEntries(runCmds); + return removeEmptyEntries(runCmds); } public String getUser() { @@ -296,31 +223,26 @@ public Map getArgs() { return args; } - public File getAbsoluteDockerFilePath(MojoParameters mojoParams) { - return EnvUtil.prepareAbsoluteSourceDirPath(mojoParams, getDockerFile().getPath()); - } + // =========================================================================================== + public static class Builder { - public File getAbsoluteDockerTarPath(MojoParameters mojoParams) { - return EnvUtil.prepareAbsoluteSourceDirPath(mojoParams, getDockerArchive().getPath()); - } - public static class Builder { - private final BuildImageConfiguration config; + protected BuildConfiguration config; public Builder() { this(null); } - public Builder(BuildImageConfiguration that) { + public Builder(BuildConfiguration that) { if (that == null) { - this.config = new BuildImageConfiguration(); + this.config = new BuildConfiguration(); } else { - this.config = DeepCopy.copy(that); + this.config = SerializationUtils.clone(that); } } - public Builder dockerFileDir(String dir) { - config.dockerFileDir = dir; + public Builder contextDir(String dir) { + config.contextDir = dir; return this; } @@ -380,11 +302,7 @@ public Builder imagePullPolicy(String imagePullPolicy) { } public Builder runCmds(List theCmds) { - if (theCmds == null) { - config.runCmds = new ArrayList<>(); - } else { - config.runCmds = theCmds; - } + config.runCmds = theCmds; return this; } @@ -427,7 +345,7 @@ public Builder cleanup(String cleanup) { public Builder compression(String compression) { if (compression == null) { - config.compression = ArchiveCompression.none; + config.compression = null; } else { config.compression = ArchiveCompression.valueOf(compression); } @@ -471,12 +389,12 @@ public Builder buildOptions(Map buildOptions) { return this; } - public BuildImageConfiguration build() { + public BuildConfiguration build() { return config; } } - public String initAndValidate(Logger log) throws IllegalArgumentException { + public String validate() throws IllegalArgumentException { if (entryPoint != null) { entryPoint.validate(); } @@ -487,22 +405,12 @@ public String initAndValidate(Logger log) throws IllegalArgumentException { healthCheck.validate(); } - if (command != null) { - log.warn(" in the configuration is deprecated and will be be removed soon"); - log.warn("Please use with nested or sections instead."); - log.warn(""); - log.warn("More on this is explained in the user manual: "); - log.warn("https://github.com/fabric8io/docker-maven-plugin/blob/master/doc/manual.md#start-up-arguments"); - log.warn(""); - log.warn("Migration is trivial, see changelog to version 0.12.0 -->"); - log.warn("https://github.com/fabric8io/docker-maven-plugin/blob/master/doc/changelog.md"); - log.warn(""); - log.warn("For now, the command is automatically translated for you to the shell form:"); - log.warn(" %s", command); + // can't have dockerFile/dockerFileDir and dockerArchive + if ((dockerFile != null || contextDir != null) && dockerArchive != null) { + throw new IllegalArgumentException("Both () and are set. " + + "Only one of them can be specified."); } - initDockerFileFile(log); - if (healthCheck != null) { // HEALTHCHECK support added later return "1.24"; @@ -514,54 +422,70 @@ public String initAndValidate(Logger log) throws IllegalArgumentException { } } - // Initialize the dockerfile location and the build mode - private void initDockerFileFile(Logger log) { - // can't have dockerFile/dockerFileDir and dockerArchive - if ((dockerFile != null || dockerFileDir != null) && dockerArchive != null) { - throw new IllegalArgumentException("Both () and are set. " + - "Only one of them can be specified."); - } - dockerFileFile = findDockerFileFile(log); - - if (dockerArchive != null) { - dockerArchiveFile = new File(dockerArchive); - } - } - - private File findDockerFileFile(Logger log) { + public File calculateDockerFilePath() { if (dockerFile != null) { File dFile = new File(dockerFile); - if (dockerFileDir == null) { + if (contextDir == null) { return dFile; - } else { - if (dFile.isAbsolute()) { - throw new IllegalArgumentException(" can not be absolute path if also set."); - } - if (EnvUtil.isWindows() && !EnvUtil.isValidWindowsFileName(dockerFile)) { - throw new IllegalArgumentException(String.format("Invalid Windows file name %s for ", dockerFile)); - } - return new File(dockerFileDir, dockerFile); } + if (dFile.isAbsolute()) { + return dFile; + } + if (System.getProperty("os.name").toLowerCase().contains("windows") && + !isValidWindowsFileName(dockerFile)) { + throw new IllegalArgumentException(String.format("Invalid Windows file name %s for ", dockerFile)); + } + return new File(contextDir, dFile.getPath()); } - if (dockerFileDir != null) { - return new File(dockerFileDir, "Dockerfile"); + if (contextDir != null) { + return new File(contextDir, "Dockerfile"); } - // TODO: Remove the following deprecated handling section - if (dockerArchive == null) { - String deprecatedDockerFileDir = - getAssemblyConfiguration() != null ? - getAssemblyConfiguration().getDockerFileDir() : - null; - if (deprecatedDockerFileDir != null) { - log.warn(" in the section of a configuration is deprecated"); - log.warn("Please use or directly within the configuration instead"); - return new File(deprecatedDockerFileDir,"Dockerfile"); - } + // No dockerfile mode + throw new IllegalArgumentException("Can't calculate a docker file path if neither dockerFile nor contextDir is specified"); + } + + // =============================================================================================================== + + private List removeEmptyEntries(List list) { + if (list == null) { + return Collections.emptyList(); } + return list.stream() + .filter(Objects::nonNull) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toList()); + } - // No dockerfile mode - return null; + + /** + * Validate that the provided filename is a valid Windows filename. + * + * The validation of the Windows filename is copied from stackoverflow: https://stackoverflow.com/a/6804755 + * + * @param filename the filename + * @return filename is a valid Windows filename + */ + boolean isValidWindowsFileName(String filename) { + Pattern pattern = Pattern.compile( + "# Match a valid Windows filename (unspecified file system). \n" + + "^ # Anchor to start of string. \n" + + "(?! # Assert filename is not: CON, PRN, \n" + + " (?: # AUX, NUL, COM1, COM2, COM3, COM4, \n" + + " CON|PRN|AUX|NUL| # COM5, COM6, COM7, COM8, COM9, \n" + + " COM[1-9]|LPT[1-9] # LPT1, LPT2, LPT3, LPT4, LPT5, \n" + + " ) # LPT6, LPT7, LPT8, and LPT9... \n" + + " (?:\\.[^.]*)? # followed by optional extension \n" + + " $ # and end of string \n" + + ") # End negative lookahead assertion. \n" + + "[^<>:\"/\\\\|?*\\x00-\\x1F]* # Zero or more valid filename chars.\n" + + "[^<>:\"/\\\\|?*\\x00-\\x1F .] # Last char is not a space or dot. \n" + + "$ # Anchor to end of string. ", + Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS); + Matcher matcher = pattern.matcher(filename); + return matcher.matches(); } + } diff --git a/src/main/java/io/fabric8/maven/docker/config/BuildImageSelectMode.java b/src/main/java/io/fabric8/maven/docker/config/build/BuildImageSelectMode.java similarity index 94% rename from src/main/java/io/fabric8/maven/docker/config/BuildImageSelectMode.java rename to src/main/java/io/fabric8/maven/docker/config/build/BuildImageSelectMode.java index 2af1bb67c..6abed90db 100644 --- a/src/main/java/io/fabric8/maven/docker/config/BuildImageSelectMode.java +++ b/src/main/java/io/fabric8/maven/docker/config/build/BuildImageSelectMode.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.build; /* * * Copyright 2016 Roland Huss diff --git a/src/main/java/io/fabric8/maven/docker/config/CleanupMode.java b/src/main/java/io/fabric8/maven/docker/config/build/CleanupMode.java similarity index 97% rename from src/main/java/io/fabric8/maven/docker/config/CleanupMode.java rename to src/main/java/io/fabric8/maven/docker/config/build/CleanupMode.java index e2684f1c8..70a1f6dd2 100644 --- a/src/main/java/io/fabric8/maven/docker/config/CleanupMode.java +++ b/src/main/java/io/fabric8/maven/docker/config/build/CleanupMode.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.build; /* * * Copyright 2016 Roland Huss diff --git a/src/main/java/io/fabric8/maven/docker/config/HealthCheckConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/build/HealthCheckConfiguration.java similarity index 98% rename from src/main/java/io/fabric8/maven/docker/config/HealthCheckConfiguration.java rename to src/main/java/io/fabric8/maven/docker/config/build/HealthCheckConfiguration.java index 7cd8154d1..67dedf9b7 100644 --- a/src/main/java/io/fabric8/maven/docker/config/HealthCheckConfiguration.java +++ b/src/main/java/io/fabric8/maven/docker/config/build/HealthCheckConfiguration.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.build; import java.io.Serializable; diff --git a/src/main/java/io/fabric8/maven/docker/config/HealthCheckMode.java b/src/main/java/io/fabric8/maven/docker/config/build/HealthCheckMode.java similarity index 81% rename from src/main/java/io/fabric8/maven/docker/config/HealthCheckMode.java rename to src/main/java/io/fabric8/maven/docker/config/build/HealthCheckMode.java index cce8a4b17..c3502e664 100644 --- a/src/main/java/io/fabric8/maven/docker/config/HealthCheckMode.java +++ b/src/main/java/io/fabric8/maven/docker/config/build/HealthCheckMode.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.build; public enum HealthCheckMode { diff --git a/src/main/java/io/fabric8/maven/docker/config/ImagePullPolicy.java b/src/main/java/io/fabric8/maven/docker/config/build/ImagePullPolicy.java similarity index 58% rename from src/main/java/io/fabric8/maven/docker/config/ImagePullPolicy.java rename to src/main/java/io/fabric8/maven/docker/config/build/ImagePullPolicy.java index aa5e979a7..c0a5ec323 100644 --- a/src/main/java/io/fabric8/maven/docker/config/ImagePullPolicy.java +++ b/src/main/java/io/fabric8/maven/docker/config/build/ImagePullPolicy.java @@ -1,6 +1,7 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.build; -import org.apache.commons.lang3.StringUtils; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * @author roland @@ -29,7 +30,9 @@ public static ImagePullPolicy fromString(String imagePullPolicy) { return policy; } } - throw new IllegalArgumentException(String.format("No policy %s known. Valid values are: %s", - imagePullPolicy, StringUtils.join(values(), ", "))); + throw new IllegalArgumentException( + String.format("No policy %s known. Valid values are: %s", + imagePullPolicy, + Stream.of(values()).map(Enum::name).collect(Collectors.joining(", ")))); } } diff --git a/src/main/java/io/fabric8/maven/docker/config/handler/ImageConfigResolver.java b/src/main/java/io/fabric8/maven/docker/config/handler/ImageConfigResolver.java index 6b5e4a806..473db2382 100644 --- a/src/main/java/io/fabric8/maven/docker/config/handler/ImageConfigResolver.java +++ b/src/main/java/io/fabric8/maven/docker/config/handler/ImageConfigResolver.java @@ -17,7 +17,7 @@ import java.util.*; -import io.fabric8.maven.docker.config.ConfigHelper; +import io.fabric8.maven.docker.util.ConfigHelper; import io.fabric8.maven.docker.config.ImageConfiguration; import io.fabric8.maven.docker.config.handler.compose.DockerComposeConfigHandler; import io.fabric8.maven.docker.config.handler.property.PropertyConfigHandler; diff --git a/src/main/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeConfigHandler.java b/src/main/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeConfigHandler.java index 5422d0daf..fa078d6cd 100644 --- a/src/main/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeConfigHandler.java +++ b/src/main/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeConfigHandler.java @@ -1,12 +1,20 @@ package io.fabric8.maven.docker.config.handler.compose; -import java.io.*; -import java.util.*; - -import io.fabric8.maven.docker.config.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import io.fabric8.maven.docker.config.ImageConfiguration; +import io.fabric8.maven.docker.config.build.BuildConfiguration; import io.fabric8.maven.docker.config.handler.ExternalConfigHandler; import io.fabric8.maven.docker.config.handler.ExternalConfigHandlerException; -import io.fabric8.maven.docker.util.DeepCopy; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import org.apache.commons.lang3.SerializationUtils; import org.apache.maven.execution.MavenSession; import org.apache.maven.project.MavenProject; import org.apache.maven.shared.filtering.MavenFilteringException; @@ -95,7 +103,7 @@ private ImageConfiguration buildImageConfiguration(DockerComposeServiceWrapper m .buildConfig(createBuildImageConfiguration(mapper, composeParent, unresolvedConfig, handlerConfig)) .runConfig(createRunConfiguration(mapper, unresolvedConfig)); if (serviceMatchesAlias(mapper, unresolvedConfig)) { - builder.watchConfig(DeepCopy.copy(unresolvedConfig.getWatchConfiguration())); + builder.watchConfig(SerializationUtils.clone(unresolvedConfig.getWatchConfiguration())); } return builder.build(); } @@ -135,11 +143,11 @@ private Reader getFilteredReader(File path, MavenProject project, MavenSession s return readerFilter.filter(request); } - private BuildImageConfiguration createBuildImageConfiguration(DockerComposeServiceWrapper mapper, - File composeParent, - ImageConfiguration imageConfig, - DockerComposeConfiguration handlerConfig) { - BuildImageConfiguration buildConfig = imageConfig.getBuildConfiguration(); + private BuildConfiguration createBuildImageConfiguration(DockerComposeServiceWrapper mapper, + File composeParent, + ImageConfiguration imageConfig, + DockerComposeConfiguration handlerConfig) { + BuildConfiguration buildConfig = imageConfig.getBuildConfiguration(); if (handlerConfig.isIgnoreBuild() || !mapper.requiresBuild()) { if (serviceMatchesAlias(mapper, imageConfig)) { // Only when the specified image name maps to the current docker-compose service @@ -150,7 +158,7 @@ private BuildImageConfiguration createBuildImageConfiguration(DockerComposeServi } // Build from the specification as given in the docker-compose file - BuildImageConfiguration.Builder builder = new BuildImageConfiguration.Builder(buildConfig) + BuildConfiguration.Builder builder = new BuildConfiguration.Builder(buildConfig) .dockerFile(extractDockerFilePath(mapper, composeParent)) .args(mapper.getBuildArgs()); return builder.build(); @@ -160,11 +168,11 @@ private boolean serviceMatchesAlias(DockerComposeServiceWrapper mapper, ImageCon return mapper.getAlias() != null && mapper.getAlias().equals(imageConfig.getAlias()); } - private RunImageConfiguration createRunConfiguration(DockerComposeServiceWrapper wrapper, ImageConfiguration imageConfig) { - RunImageConfiguration.Builder builder = + private RunConfiguration createRunConfiguration(DockerComposeServiceWrapper wrapper, ImageConfiguration imageConfig) { + RunConfiguration.Builder builder = serviceMatchesAlias(wrapper, imageConfig) ? - new RunImageConfiguration.Builder(imageConfig.getRunConfiguration()) : - new RunImageConfiguration.Builder(); + new RunConfiguration.Builder(imageConfig.getRunConfiguration()) : + new RunConfiguration.Builder(); return builder .capAdd(wrapper.getCapAdd()) .capDrop(wrapper.getCapDrop()) diff --git a/src/main/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeServiceWrapper.java b/src/main/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeServiceWrapper.java index 0c356030b..95a3af1f8 100644 --- a/src/main/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeServiceWrapper.java +++ b/src/main/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeServiceWrapper.java @@ -8,13 +8,13 @@ import java.util.List; import java.util.Map; -import io.fabric8.maven.docker.config.Arguments; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.LogConfiguration; -import io.fabric8.maven.docker.config.NetworkConfig; -import io.fabric8.maven.docker.config.RestartPolicy; -import io.fabric8.maven.docker.config.RunVolumeConfiguration; -import io.fabric8.maven.docker.config.UlimitConfig; +import io.fabric8.maven.docker.config.build.Arguments; +import io.fabric8.maven.docker.config.run.LogConfiguration; +import io.fabric8.maven.docker.config.run.NetworkConfiguration; +import io.fabric8.maven.docker.config.run.RestartPolicy; +import io.fabric8.maven.docker.config.run.RunVolumeConfiguration; +import io.fabric8.maven.docker.config.run.UlimitConfiguration; import io.fabric8.maven.docker.util.VolumeBindingUtil; @@ -169,10 +169,10 @@ LogConfiguration getLogConfiguration() { .build(); } - NetworkConfig getNetworkConfig() { + NetworkConfiguration getNetworkConfig() { String net = asString("network_mode"); if (net != null) { - return new NetworkConfig(net); + return new NetworkConfiguration(net); } Object networks = asObject("networks"); if (networks == null) { @@ -183,14 +183,14 @@ NetworkConfig getNetworkConfig() { if (toJoin.size() > 1) { throwIllegalArgumentException("'networks:' Only one custom network to join is supported currently"); } - return new NetworkConfig(NetworkConfig.Mode.custom, toJoin.get(0)); + return new NetworkConfiguration(NetworkConfiguration.Mode.custom, toJoin.get(0)); } else if (networks instanceof Map) { Map toJoin = (Map) networks; if (toJoin.size() > 1) { throwIllegalArgumentException("'networks:' Only one custom network to join is supported currently"); } String custom = toJoin.keySet().iterator().next(); - NetworkConfig ret = new NetworkConfig(NetworkConfig.Mode.custom, custom); + NetworkConfiguration ret = new NetworkConfiguration(NetworkConfiguration.Mode.custom, custom); Object aliases = toJoin.get(custom); if (aliases != null) { if (aliases instanceof List) { @@ -240,7 +240,7 @@ List getPortMapping() { return ports; } - List getUlimits() { + List getUlimits() { Object ulimits = asObject("ulimits"); if (ulimits == null) { return null; @@ -249,16 +249,16 @@ List getUlimits() { throwIllegalArgumentException("'ulimits:' must be a map"); } Map ulimitMap = (Map) ulimits; - List ret = new ArrayList<>(); + List ret = new ArrayList<>(); for (String ulimit : ulimitMap.keySet()) { Object val = ulimitMap.get(ulimit); if (val instanceof Map) { Map valMap = (Map) val; Integer soft = valMap.get("soft"); Integer hard = valMap.get("hard"); - ret.add(new UlimitConfig(ulimit, hard, soft)); + ret.add(new UlimitConfiguration(ulimit, hard, soft)); } else if (val instanceof Integer) { - ret.add(new UlimitConfig(ulimit, (Integer) val, null)); + ret.add(new UlimitConfiguration(ulimit, (Integer) val, null)); } else { throwIllegalArgumentException("'ulimits:' invalid limit value " + val + " (class : " + val.getClass() + ")"); } diff --git a/src/main/java/io/fabric8/maven/docker/config/handler/property/ConfigKey.java b/src/main/java/io/fabric8/maven/docker/config/handler/property/ConfigKey.java index e22d52b3a..e6cce9e93 100644 --- a/src/main/java/io/fabric8/maven/docker/config/handler/property/ConfigKey.java +++ b/src/main/java/io/fabric8/maven/docker/config/handler/property/ConfigKey.java @@ -28,10 +28,7 @@ public enum ConfigKey { ASSEMBLY_BASEDIR("assembly.baseDir"), ASSEMBLY_DESCRIPTOR("assembly.descriptor"), ASSEMBLY_DESCRIPTOR_REF("assembly.descriptorRef"), - ASSEMBLY_EXPORT_BASEDIR("assembly.exportBaseDir"), - ASSEMBLY_IGNORE_PERMISSIONS("assembly.ignorePermissions"), ASSEMBLY_PERMISSIONS("assembly.permissions"), - ASSEMBLY_DOCKER_FILE_DIR("assembly.dockerFileDir"), ASSEMBLY_USER("assembly.user"), ASSEMBLY_MODE("assembly.mode"), ASSEMBLY_TARLONGFILEMODE("assembly.tarLongFileMode"), @@ -87,7 +84,6 @@ public enum ConfigKey { MEMORY_SWAP, NAME, NAMING_STRATEGY, - NET, NETWORK_MODE("network.mode"), NETWORK_NAME("network.name"), NETWORK_ALIAS("network.alias"), diff --git a/src/main/java/io/fabric8/maven/docker/config/handler/property/PropertyConfigHandler.java b/src/main/java/io/fabric8/maven/docker/config/handler/property/PropertyConfigHandler.java index 5da7758d9..cb1ef0600 100644 --- a/src/main/java/io/fabric8/maven/docker/config/handler/property/PropertyConfigHandler.java +++ b/src/main/java/io/fabric8/maven/docker/config/handler/property/PropertyConfigHandler.java @@ -23,20 +23,20 @@ import java.util.Properties; import java.util.function.Supplier; -import io.fabric8.maven.docker.config.Arguments; -import io.fabric8.maven.docker.config.AssemblyConfiguration; -import io.fabric8.maven.docker.config.BuildImageConfiguration; -import io.fabric8.maven.docker.config.HealthCheckConfiguration; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.LogConfiguration; -import io.fabric8.maven.docker.config.NetworkConfig; -import io.fabric8.maven.docker.config.RestartPolicy; -import io.fabric8.maven.docker.config.RunImageConfiguration; -import io.fabric8.maven.docker.config.RunVolumeConfiguration; -import io.fabric8.maven.docker.config.UlimitConfig; -import io.fabric8.maven.docker.config.WaitConfiguration; -import io.fabric8.maven.docker.config.WatchImageConfiguration; +import io.fabric8.maven.docker.config.WatchConfiguration; +import io.fabric8.maven.docker.config.build.Arguments; +import io.fabric8.maven.docker.config.build.AssemblyConfiguration; +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.config.build.HealthCheckConfiguration; import io.fabric8.maven.docker.config.handler.ExternalConfigHandler; +import io.fabric8.maven.docker.config.run.LogConfiguration; +import io.fabric8.maven.docker.config.run.NetworkConfiguration; +import io.fabric8.maven.docker.config.run.RestartPolicy; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import io.fabric8.maven.docker.config.run.RunVolumeConfiguration; +import io.fabric8.maven.docker.config.run.UlimitConfiguration; +import io.fabric8.maven.docker.config.run.WaitConfiguration; import io.fabric8.maven.docker.util.EnvUtil; import org.apache.maven.execution.MavenSession; import org.apache.maven.project.MavenProject; @@ -69,9 +69,9 @@ public List resolve(ImageConfiguration fromConfig, MavenProj PropertyMode propertyMode = getMode(externalConfig); ValueProvider valueProvider = new ValueProvider(prefix, properties, propertyMode); - RunImageConfiguration run = extractRunConfiguration(fromConfig, valueProvider); - BuildImageConfiguration build = extractBuildConfiguration(fromConfig, valueProvider, project); - WatchImageConfiguration watch = extractWatchConfig(fromConfig, valueProvider); + RunConfiguration run = extractRunConfiguration(fromConfig, valueProvider); + BuildConfiguration build = extractBuildConfiguration(fromConfig, valueProvider, project); + WatchConfiguration watch = extractWatchConfig(fromConfig, valueProvider); String name = valueProvider.getString(NAME, fromConfig.getName()); String alias = valueProvider.getString(ALIAS, fromConfig.getAlias()); @@ -89,11 +89,11 @@ public List resolve(ImageConfiguration fromConfig, MavenProj .build()); } - private boolean isStringValueNull(ValueProvider valueProvider, BuildImageConfiguration config, ConfigKey key, Supplier supplier) { + private boolean isStringValueNull(ValueProvider valueProvider, BuildConfiguration config, ConfigKey key, Supplier supplier) { return valueProvider.getString(key, config == null ? null : supplier.get()) != null; } // Enable build config only when a `.from.`, `.dockerFile.`, or `.dockerFileDir.` is configured - private boolean buildConfigured(BuildImageConfiguration config, ValueProvider valueProvider, MavenProject project) { + private boolean buildConfigured(BuildConfiguration config, ValueProvider valueProvider, MavenProject project) { if (isStringValueNull(valueProvider, config, FROM, () -> config.getFrom())) { @@ -103,14 +103,14 @@ private boolean buildConfigured(BuildImageConfiguration config, ValueProvider va if (valueProvider.getMap(FROM_EXT, config == null ? null : config.getFromExt()) != null) { return true; } - if (isStringValueNull(valueProvider, config, DOCKER_FILE, () -> config.getDockerFileRaw() )) { + if (isStringValueNull(valueProvider, config, DOCKER_FILE, () -> config.getDockerFile() )) { return true; } - if (isStringValueNull(valueProvider, config, DOCKER_ARCHIVE, () -> config.getDockerArchiveRaw())) { + if (isStringValueNull(valueProvider, config, DOCKER_ARCHIVE, () -> config.getDockerArchive())) { return true; } - if (isStringValueNull(valueProvider, config, DOCKER_FILE_DIR, () -> config.getDockerFileDirRaw())) { + if (isStringValueNull(valueProvider, config, DOCKER_FILE_DIR, () -> config.getContextDir())) { return true; } @@ -119,15 +119,15 @@ private boolean buildConfigured(BuildImageConfiguration config, ValueProvider va } - private BuildImageConfiguration extractBuildConfiguration(ImageConfiguration fromConfig, ValueProvider valueProvider, MavenProject project) { - BuildImageConfiguration config = fromConfig.getBuildConfiguration(); + private BuildConfiguration extractBuildConfiguration(ImageConfiguration fromConfig, ValueProvider valueProvider, MavenProject project) { + BuildConfiguration config = fromConfig.getBuildConfiguration(); if (!buildConfigured(config, valueProvider, project)) { return null; } - return new BuildImageConfiguration.Builder() + return new BuildConfiguration.Builder() .cmd(extractArguments(valueProvider, CMD, config == null ? null : config.getCmd())) - .cleanup(valueProvider.getString(CLEANUP, config == null ? null : config.getCleanup())) + .cleanup(valueProvider.getString(CLEANUP, config == null ? null : config.getCleanupMode())) .nocache(valueProvider.getBoolean(NOCACHE, config == null ? null : config.getNoCache())) .optimise(valueProvider.getBoolean(OPTIMISE, config == null ? null : config.getOptimise())) .entryPoint(extractArguments(valueProvider, ENTRYPOINT, config == null ? null : config.getEntryPoint())) @@ -149,30 +149,29 @@ private BuildImageConfiguration extractBuildConfiguration(ImageConfiguration fro .workdir(valueProvider.getString(WORKDIR, config == null ? null : config.getWorkdir())) .skip(valueProvider.getBoolean(SKIP_BUILD, config == null ? null : config.getSkip())) .imagePullPolicy(valueProvider.getString(IMAGE_PULL_POLICY_BUILD, config == null ? null : config.getImagePullPolicy())) - .dockerArchive(valueProvider.getString(DOCKER_ARCHIVE, config == null ? null : config.getDockerArchiveRaw())) - .dockerFile(valueProvider.getString(DOCKER_FILE, config == null ? null : config.getDockerFileRaw())) - .dockerFileDir(valueProvider.getString(DOCKER_FILE_DIR, config == null ? null : config.getDockerFileDirRaw())) + .dockerArchive(valueProvider.getString(DOCKER_ARCHIVE, config == null ? null : config.getDockerArchive())) + .dockerFile(valueProvider.getString(DOCKER_FILE, config == null ? null : config.getDockerFile())) + .contextDir(valueProvider.getString(DOCKER_FILE_DIR, config == null ? null : config.getContextDir())) .buildOptions(valueProvider.getMap(BUILD_OPTIONS, config == null ? null : config.getBuildOptions())) - .filter(valueProvider.getString(FILTER, config == null ? null : config.getFilterRaw())) + .filter(valueProvider.getString(FILTER, config == null ? null : config.getFilter())) .user(valueProvider.getString(USER, config == null ? null : config.getUser())) .healthCheck(extractHealthCheck(config == null ? null : config.getHealthCheck(), valueProvider)) .build(); } - private RunImageConfiguration extractRunConfiguration(ImageConfiguration fromConfig, ValueProvider valueProvider) { - RunImageConfiguration config = fromConfig.getRunConfiguration(); + private RunConfiguration extractRunConfiguration(ImageConfiguration fromConfig, ValueProvider valueProvider) { + RunConfiguration config = fromConfig.getRunConfiguration(); if (config.isDefault()) { config = null; } - return new RunImageConfiguration.Builder() + return new RunConfiguration.Builder() .capAdd(valueProvider.getList(CAP_ADD, config == null ? null : config.getCapAdd())) .capDrop(valueProvider.getList(CAP_DROP, config == null ? null : config.getCapDrop())) .securityOpts(valueProvider.getList(SECURITY_OPTS, config == null ? null : config.getSecurityOpts())) .cmd(extractArguments(valueProvider, CMD, config == null ? null : config.getCmd())) .dns(valueProvider.getList(DNS, config == null ? null : config.getDns())) .dependsOn(valueProvider.getList(DEPENDS_ON, config == null ? null : config.getDependsOn())) - .net(valueProvider.getString(NET, config == null ? null : config.getNetRaw())) .network(extractNetworkConfig(config == null ? null : config.getNetworkingConfig(), valueProvider)) .dnsSearch(valueProvider.getList(DNS_SEARCH, config == null ? null : config.getDnsSearch())) .domainname(valueProvider.getString(DOMAINNAME, config == null ? null : config.getDomainname())) @@ -211,8 +210,8 @@ private RunImageConfiguration extractRunConfiguration(ImageConfiguration fromCon .build(); } - private NetworkConfig extractNetworkConfig(NetworkConfig config, ValueProvider valueProvider) { - return new NetworkConfig.Builder() + private NetworkConfiguration extractNetworkConfig(NetworkConfiguration config, ValueProvider valueProvider) { + return new NetworkConfiguration.Builder() .mode(valueProvider.getString(NETWORK_MODE, config == null || config.getMode() == null ? null : config.getMode().name())) .name(valueProvider.getString(NETWORK_NAME, config == null ? null : config.getName())) .aliases(valueProvider.getList(NETWORK_ALIAS, config == null ? null : config.getAliases())) @@ -225,12 +224,9 @@ private AssemblyConfiguration extractAssembly(AssemblyConfiguration config, Valu .targetDir(valueProvider.getString(ASSEMBLY_BASEDIR, config == null ? null : config.getTargetDir())) .descriptor(valueProvider.getString(ASSEMBLY_DESCRIPTOR, config == null ? null : config.getDescriptor())) .descriptorRef(valueProvider.getString(ASSEMBLY_DESCRIPTOR_REF, config == null ? null : config.getDescriptorRef())) - .dockerFileDir(valueProvider.getString(ASSEMBLY_DOCKER_FILE_DIR, config == null ? null : config.getDockerFileDir())) - .exportBasedir(valueProvider.getBoolean(ASSEMBLY_EXPORT_BASEDIR, config == null ? null : config.getExportTargetDir())) - .ignorePermissions(valueProvider.getBoolean(ASSEMBLY_IGNORE_PERMISSIONS, config == null ? null : config.getIgnorePermissions())) - .permissions(valueProvider.getString(ASSEMBLY_PERMISSIONS, config == null ? null : config.getPermissionsRaw())) + .permissions(valueProvider.getString(ASSEMBLY_PERMISSIONS, config == null ? null : config.getPermissions() != null ? config.getPermissions().name() : null)) .user(valueProvider.getString(ASSEMBLY_USER, config == null ? null : config.getUser())) - .mode(valueProvider.getString(ASSEMBLY_MODE, config == null ? null : config.getModeRaw())) + .mode(valueProvider.getString(ASSEMBLY_MODE, config == null ? null : config.getMode() != null ? config.getMode().name() : null)) .tarLongFileMode(valueProvider.getString(ASSEMBLY_TARLONGFILEMODE, config == null ? null : config.getTarLongFileMode())) .build(); } @@ -321,10 +317,10 @@ private WaitConfiguration extractWaitConfig(WaitConfiguration config, ValueProvi .build(); } - private WatchImageConfiguration extractWatchConfig(ImageConfiguration fromConfig, ValueProvider valueProvider) { - WatchImageConfiguration config = fromConfig.getWatchConfiguration(); + private WatchConfiguration extractWatchConfig(ImageConfiguration fromConfig, ValueProvider valueProvider) { + WatchConfiguration config = fromConfig.getWatchConfiguration(); - return new WatchImageConfiguration.Builder() + return new WatchConfiguration.Builder() .interval(valueProvider.getInteger(WATCH_INTERVAL, config == null ? null : config.getIntervalRaw())) .postGoal(valueProvider.getString(WATCH_POSTGOAL, config == null ? null : config.getPostGoal())) .postExec(valueProvider.getString(WATCH_POSTEXEC, config == null ? null : config.getPostExec())) @@ -332,12 +328,12 @@ private WatchImageConfiguration extractWatchConfig(ImageConfiguration fromConfig .build(); } - private List extractUlimits(List config, ValueProvider valueProvider) { + private List extractUlimits(List config, ValueProvider valueProvider) { List other = null; if (config != null) { other = new ArrayList<>(); // Convert back to string for potential merge - for (UlimitConfig ulimitConfig : config) { + for (UlimitConfiguration ulimitConfig : config) { other.add(ulimitConfig.serialize()); } } @@ -346,9 +342,9 @@ private List extractUlimits(List config, ValueProvid if (ulimits == null) { return null; } - List ret = new ArrayList<>(); + List ret = new ArrayList<>(); for (String ulimit : ulimits) { - ret.add(new UlimitConfig(ulimit)); + ret.add(new UlimitConfiguration(ulimit)); } return ret; } diff --git a/src/main/java/io/fabric8/maven/docker/config/handler/property/ValueProvider.java b/src/main/java/io/fabric8/maven/docker/config/handler/property/ValueProvider.java index 51ec1d158..6a1ceeca0 100644 --- a/src/main/java/io/fabric8/maven/docker/config/handler/property/ValueProvider.java +++ b/src/main/java/io/fabric8/maven/docker/config/handler/property/ValueProvider.java @@ -43,7 +43,7 @@ public class ValueProvider { private LongValueExtractor longValueExtractor; private BooleanValueExtractor booleanValueExtractor; private DoubleValueExtractor doubleValueExtractor; - + /** * Initiates ValueProvider which is to work with data from the given properties. * @@ -200,9 +200,6 @@ protected T merge(ConfigKey key, List values) { } } - - - private class StringValueExtractor extends ValueExtractor { @Override protected String withPrefix(String prefix, ConfigKey key, Properties properties) { diff --git a/src/main/java/io/fabric8/maven/docker/config/maven/MavenAssemblyConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/maven/MavenAssemblyConfiguration.java new file mode 100644 index 000000000..43cbf3147 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/config/maven/MavenAssemblyConfiguration.java @@ -0,0 +1,40 @@ +package io.fabric8.maven.docker.config.maven; + +import io.fabric8.maven.docker.config.build.AssemblyConfiguration; +import org.apache.maven.plugins.assembly.model.Assembly; + +/** + * @author roland + * @since 19.10.18 + */ +public class MavenAssemblyConfiguration extends AssemblyConfiguration { + + /** + * Assembly defined inline in the pom.xml + */ + private Assembly inline; + + public Assembly getInline() { + return inline; + } + + public static class Builder extends AssemblyConfiguration.Builder { + + private final MavenAssemblyConfiguration mavenConfig; + + public Builder() { + mavenConfig = new MavenAssemblyConfiguration(); + config = mavenConfig; + } + + public Builder assemblyDef(Assembly descriptor) { + mavenConfig.inline = set(descriptor); + return this; + } + + @Override + public MavenAssemblyConfiguration build() { + return mavenConfig; + } + } +} diff --git a/src/main/java/io/fabric8/maven/docker/config/maven/MavenBuildConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/maven/MavenBuildConfiguration.java new file mode 100644 index 000000000..a360f8ca3 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/config/maven/MavenBuildConfiguration.java @@ -0,0 +1,47 @@ +package io.fabric8.maven.docker.config.maven; + +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import org.apache.commons.lang3.SerializationUtils; + +/** + * @author roland + * @since 19.10.18 + */ +public class MavenBuildConfiguration extends BuildConfiguration { + + private MavenAssemblyConfiguration assembly; + + @Override + public MavenAssemblyConfiguration getAssemblyConfiguration() { + return assembly; + } + + public static class Builder extends BuildConfiguration.Builder { + + private MavenBuildConfiguration mavenConfig; + + public Builder() { + this(null); + } + + public Builder(MavenBuildConfiguration that) { + if (that == null) { + this.mavenConfig = new MavenBuildConfiguration(); + this.config = mavenConfig; + } else { + this.config = SerializationUtils.clone(that); + } + } + + public Builder assembly(MavenAssemblyConfiguration assembly) { + this.mavenConfig.assembly = assembly; + return this; + } + + @Override + public MavenBuildConfiguration build() { + return mavenConfig; + } + } + +} diff --git a/src/main/java/io/fabric8/maven/docker/config/maven/MavenImageConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/maven/MavenImageConfiguration.java new file mode 100644 index 000000000..4c52c74b7 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/config/maven/MavenImageConfiguration.java @@ -0,0 +1,46 @@ +package io.fabric8.maven.docker.config.maven; + +import io.fabric8.maven.docker.config.ImageConfiguration; +import org.apache.commons.lang3.SerializationUtils; + +/** + * @author roland + * @since 19.10.18 + */ +public class MavenImageConfiguration extends ImageConfiguration { + + private MavenBuildConfiguration build; + + @Override + public MavenBuildConfiguration getBuildConfiguration() { + return build; + } + + public static class Builder extends ImageConfiguration.Builder { + + private MavenImageConfiguration mavenConfig; + + public Builder() { + this(null); + } + + public Builder buildConfig(MavenBuildConfiguration build) { + mavenConfig.build = build; + return this; + } + + public Builder(MavenImageConfiguration that) { + if (that == null) { + this.mavenConfig = new MavenImageConfiguration(); + this.config = mavenConfig; + } else { + this.config = SerializationUtils.clone(that); + } + } + + @Override + public MavenImageConfiguration build() { + return mavenConfig; + } + } +} diff --git a/src/main/java/io/fabric8/maven/docker/config/maven/RegistryAuthConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/maven/RegistryAuthConfiguration.java new file mode 100644 index 000000000..7322a1663 --- /dev/null +++ b/src/main/java/io/fabric8/maven/docker/config/maven/RegistryAuthConfiguration.java @@ -0,0 +1,49 @@ +package io.fabric8.maven.docker.config.maven; + +import java.io.Serializable; +import java.util.Map; +import java.util.TreeMap; + + +/** + * Class holding configuration for accessing a registry + */ +public class RegistryAuthConfiguration implements Serializable { + + private Map push; + + private Map pull; + + private String username; + + private String password; + + private String email; + + private String authToken; + + public Map getPush() { + return push; + } + + public Map getPull() { + return pull; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getEmail() { + return email; + } + + public String getAuthToken() { + return authToken; + } + +} diff --git a/src/main/java/io/fabric8/maven/docker/config/LogConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/run/LogConfiguration.java similarity index 73% rename from src/main/java/io/fabric8/maven/docker/config/LogConfiguration.java rename to src/main/java/io/fabric8/maven/docker/config/run/LogConfiguration.java index fa12d2dc1..0fab95eed 100644 --- a/src/main/java/io/fabric8/maven/docker/config/LogConfiguration.java +++ b/src/main/java/io/fabric8/maven/docker/config/run/LogConfiguration.java @@ -1,9 +1,10 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.run; import java.io.Serializable; import java.util.Map; -import org.apache.maven.plugins.annotations.Parameter; +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import org.apache.commons.lang3.SerializationUtils; /** * @author roland @@ -11,37 +12,22 @@ */ public class LogConfiguration implements Serializable { - public static final LogConfiguration DEFAULT = new LogConfiguration(null, null, null, null, null, null); + public static final LogConfiguration DEFAULT = new LogConfiguration(); - @Parameter(defaultValue = "true") private Boolean enabled; - @Parameter private String prefix; - @Parameter private String date; - @Parameter private String color; - @Parameter private String file; - @Parameter private LogDriver driver; public LogConfiguration() {} - private LogConfiguration(Boolean enabled, String prefix, String color, String date, String file, LogDriver driver) { - this.enabled = enabled; - this.prefix = prefix; - this.date = date; - this.color = color; - this.file = file; - this.driver = driver; - } - public String getPrefix() { return prefix; } @@ -89,10 +75,8 @@ public LogDriver getDriver() { public static class LogDriver implements Serializable { - /** @parameter */ private String name; - /** @parameter */ private Map opts; public LogDriver() {}; @@ -114,32 +98,46 @@ public Map getOpts() { // ============================================================================= public static class Builder { - private Boolean enabled; - private String prefix, date, color, file; - private Map driverOpts; + + private final LogConfiguration config; + private String driverName; + private Map driverOpts; + + public Builder() { + this(null); + } + + public Builder(LogConfiguration that) { + if (that == null) { + this.config = new LogConfiguration(); + } else { + this.config = SerializationUtils.clone(that); + } + } + public Builder enabled(Boolean enabled) { - this.enabled = enabled; + config.enabled = enabled; return this; } public Builder prefix(String prefix) { - this.prefix = prefix; + config.prefix = prefix; return this; } public Builder date(String date) { - this.date = date; + config.date = date; return this; } public Builder color(String color) { - this.color = color; + config.color = color; return this; } public Builder file(String file) { - this.file = file; + config.file = file; return this; } @@ -154,8 +152,10 @@ public Builder logDriverOpts(Map logOpts) { } public LogConfiguration build() { - return new LogConfiguration(enabled, prefix, color, date, file, - driverName != null ? new LogDriver(driverName,driverOpts) : null); + if (driverName != null) { + config.driver = new LogDriver(driverName, driverOpts); + } + return config; } } } diff --git a/src/main/java/io/fabric8/maven/docker/config/NetworkConfig.java b/src/main/java/io/fabric8/maven/docker/config/run/NetworkConfiguration.java similarity index 91% rename from src/main/java/io/fabric8/maven/docker/config/NetworkConfig.java rename to src/main/java/io/fabric8/maven/docker/config/run/NetworkConfiguration.java index 98142e6a7..43caeb9eb 100644 --- a/src/main/java/io/fabric8/maven/docker/config/NetworkConfig.java +++ b/src/main/java/io/fabric8/maven/docker/config/run/NetworkConfiguration.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.run; /* * * Copyright 2016 Roland Huss @@ -20,20 +20,16 @@ import java.util.ArrayList; import java.util.List; -import org.apache.maven.plugins.annotations.Parameter; - /** * Network config encapsulating network specific configuration * @author roland * @since 29/07/16 */ -public class NetworkConfig implements Serializable { +public class NetworkConfiguration implements Serializable { - @Parameter private String name; - @Parameter private Mode mode; private List aliases = new ArrayList<>(); @@ -48,17 +44,17 @@ public void addAlias(String alias) { * Legacy constructor using the <net> config * @param net net, encapsulating mode & name. */ - public NetworkConfig(String net) { + public NetworkConfiguration(String net) { initLegacyNetSpec(net); } - public NetworkConfig(Mode mode, String name) { + public NetworkConfiguration(Mode mode, String name) { this.name = name; this.mode = mode; } - public NetworkConfig() { + public NetworkConfiguration() { name = null; mode = null; } @@ -149,10 +145,10 @@ public enum Mode { public static class Builder { - private final NetworkConfig config = new NetworkConfig(); + private final NetworkConfiguration config = new NetworkConfiguration(); private boolean isEmpty = true; - public NetworkConfig build() { + public NetworkConfiguration build() { return isEmpty ? null : config; } diff --git a/src/main/java/io/fabric8/maven/docker/config/RestartPolicy.java b/src/main/java/io/fabric8/maven/docker/config/run/RestartPolicy.java similarity index 91% rename from src/main/java/io/fabric8/maven/docker/config/RestartPolicy.java rename to src/main/java/io/fabric8/maven/docker/config/run/RestartPolicy.java index 1da15edc8..54654c25a 100644 --- a/src/main/java/io/fabric8/maven/docker/config/RestartPolicy.java +++ b/src/main/java/io/fabric8/maven/docker/config/run/RestartPolicy.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config;/* +package io.fabric8.maven.docker.config.run;/* * * Copyright 2014 Roland Huss * @@ -17,8 +17,6 @@ import java.io.Serializable; -import org.apache.maven.plugins.annotations.Parameter; - /** * @author roland * @since 08/12/14 @@ -27,10 +25,8 @@ public class RestartPolicy implements Serializable { public static final RestartPolicy DEFAULT = new RestartPolicy(); - @Parameter private String name; - @Parameter private int retry; public RestartPolicy() {}; diff --git a/src/main/java/io/fabric8/maven/docker/config/RunImageConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/run/RunConfiguration.java similarity index 83% rename from src/main/java/io/fabric8/maven/docker/config/RunImageConfiguration.java rename to src/main/java/io/fabric8/maven/docker/config/run/RunConfiguration.java index 4a94975cb..f2b798000 100644 --- a/src/main/java/io/fabric8/maven/docker/config/RunImageConfiguration.java +++ b/src/main/java/io/fabric8/maven/docker/config/run/RunConfiguration.java @@ -1,130 +1,102 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.run; import java.io.Serializable; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; -import javax.annotation.Nonnull; - -import io.fabric8.maven.docker.util.DeepCopy; -import io.fabric8.maven.docker.util.EnvUtil; -import org.apache.maven.plugins.annotations.Parameter; +import io.fabric8.maven.docker.config.build.Arguments; +import org.apache.commons.lang3.SerializationUtils; /** * @author roland * @since 02.09.14 */ -public class RunImageConfiguration implements Serializable { +public class RunConfiguration implements Serializable { - static final RunImageConfiguration DEFAULT = new RunImageConfiguration(); + public static final RunConfiguration DEFAULT = new RunConfiguration(); public boolean isDefault() { - return this == RunImageConfiguration.DEFAULT; + return this == RunConfiguration.DEFAULT; } /** * Environment variables to set when starting the container. key: variable name, value: env value */ - @Parameter private Map env; - @Parameter private Map labels; // Path to a property file holding environment variables - @Parameter private String envPropertyFile; // Command to execute in container - @Parameter private Arguments cmd; // container domain name - @Parameter private String domainname; // container domain name - @Parameter private List dependsOn; // container entry point - @Parameter private Arguments entrypoint; // container hostname - @Parameter private String hostname; // container user - @Parameter private String user; // working directory - @Parameter private String workingDir; // Size of /dev/shm in bytes - /** @parameter */ + /** */ private Long shmSize; // memory in bytes - @Parameter private Long memory; // total memory (swap + ram) in bytes, -1 to disable - @Parameter private Long memorySwap; // Path to a file where the dynamically mapped properties are written to - @Parameter private String portPropertyFile; - // For simple network setups. For complex stuff use "network" - @Parameter - private String net; - - @Parameter - private NetworkConfig network; + private NetworkConfiguration network; - @Parameter private List dns; - @Parameter private List dnsSearch; - @Parameter private List capAdd; - @Parameter private List capDrop; - @Parameter private List securityOpts; - @Parameter private Boolean privileged; - @Parameter private List extraHosts; - @Parameter private Long cpuShares; - @Parameter private Long cpus; - @Parameter private String cpuSet; // Port mapping. Can contain symbolic names in which case dynamic // ports are used - @Parameter private List ports; /** * @deprecated */ - @Parameter @Deprecated private NamingStrategy namingStrategy; @@ -137,56 +109,44 @@ public boolean isDefault() { * - %i for an increasing index of container names * */ - @Parameter private String containerNamePattern; /** * Property key part used to expose the container ip when running. */ - @Parameter private String exposedPropertyKey; // Mount volumes from the given image's started containers - @Parameter private RunVolumeConfiguration volumes; // Links to other container started - @Parameter private List links; // Configuration for how to wait during startup of the container - @Parameter private WaitConfiguration wait; // Mountpath for tmps - @Parameter private List tmpfs; - @Parameter private LogConfiguration log; - @Parameter private RestartPolicy restartPolicy; - @Parameter - private List ulimits; + private List ulimits; - @Parameter private Boolean skip; - + /** * Policy for pulling the image to start */ - @Parameter private String imagePullPolicy; // Mount the container's root filesystem as read only - @Parameter private Boolean readOnly; - public RunImageConfiguration() { } + public RunConfiguration() { } - public String initAndValidate() { + public String validate() { if (entrypoint != null) { entrypoint.validate(); } @@ -195,7 +155,7 @@ public String initAndValidate() { } // Custom networks are available since API 1.21 (Docker 1.9) - NetworkConfig config = getNetworkingConfig(); + NetworkConfiguration config = getNetworkingConfig(); if (config != null && config.isCustomNetwork()) { return "1.21"; } @@ -227,9 +187,8 @@ public String getDomainname() { return domainname; } - @Nonnull public List getDependsOn() { - return EnvUtil.splitAtCommasAndTrim(dependsOn); + return splitAtCommasAndTrim(dependsOn); } public String getUser() { @@ -260,9 +219,15 @@ public String getCpuSet() { return cpuSet; } - @Nonnull public List getPorts() { - return EnvUtil.removeEmptyEntries(ports); + if (ports == null) { + return Collections.emptyList(); + } + return ports.stream() + .filter(Objects::nonNull) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toList()); } public Arguments getCmd() { @@ -301,18 +266,11 @@ public List getDns() { return dns; } - @Deprecated - public String getNetRaw() { - return net; - } - - public NetworkConfig getNetworkingConfig() { + public NetworkConfiguration getNetworkingConfig() { if (network != null) { return network; - } else if (net != null) { - return new NetworkConfig(net); } else { - return new NetworkConfig(); + return new NetworkConfiguration(); } } @@ -328,12 +286,11 @@ public RunVolumeConfiguration getVolumeConfiguration() { return volumes; } - @Nonnull public List getLinks() { - return EnvUtil.splitAtCommasAndTrim(links); + return splitAtCommasAndTrim(links); } - public List getUlimits() { + public List getUlimits() { return ulimits; } @@ -366,10 +323,6 @@ public Boolean getPrivileged() { } public RestartPolicy getRestartPolicy() { - return (restartPolicy == null) ? RestartPolicy.DEFAULT : restartPolicy; - } - - public RestartPolicy getRestartPolicyRaw() { return restartPolicy; } @@ -405,11 +358,11 @@ public NamingStrategy getNamingStrategy() { public static class Builder { - public Builder(RunImageConfiguration config) { + public Builder(RunConfiguration config) { if (config == null) { - this.config = new RunImageConfiguration(); + this.config = new RunConfiguration(); } else { - this.config = DeepCopy.copy(config); + this.config = SerializationUtils.clone(config); } } @@ -417,7 +370,7 @@ public Builder() { this(null); } - private RunImageConfiguration config; + private RunConfiguration config; public Builder env(Map env) { config.env = env; @@ -507,12 +460,7 @@ public Builder securityOpts(List securityOpts) { return this; } - public Builder net(String net) { - config.net = net; - return this; - } - - public Builder network(NetworkConfig networkConfig) { + public Builder network(NetworkConfiguration networkConfig) { config.network = networkConfig; return this; } @@ -537,7 +485,7 @@ public Builder extraHosts(List extraHosts) { return this; } - public Builder ulimits(List ulimits) { + public Builder ulimits(List ulimits) { config.ulimits = ulimits; return this; } @@ -645,8 +593,21 @@ public Builder readOnly(Boolean readOnly) { } - public RunImageConfiguration build() { + public RunConfiguration build() { return config; } } + + // =========================================================================================== + + private List splitAtCommasAndTrim(List input) { + return Optional.ofNullable(input).orElse(Collections.emptyList()) + .stream() + .filter(Objects::nonNull) + .flatMap(s -> Arrays.stream(s.split(","))) + .map(String::trim) + .filter(s -> s.length() > 0) + .collect(Collectors.toList()); + } + } diff --git a/src/main/java/io/fabric8/maven/docker/config/RunVolumeConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/run/RunVolumeConfiguration.java similarity index 81% rename from src/main/java/io/fabric8/maven/docker/config/RunVolumeConfiguration.java rename to src/main/java/io/fabric8/maven/docker/config/run/RunVolumeConfiguration.java index bad8bc9bc..61cb0dea5 100644 --- a/src/main/java/io/fabric8/maven/docker/config/RunVolumeConfiguration.java +++ b/src/main/java/io/fabric8/maven/docker/config/run/RunVolumeConfiguration.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config;/* +package io.fabric8.maven.docker.config.run;/* * * Copyright 2014 Roland Huss * @@ -16,9 +16,10 @@ */ import java.io.Serializable; -import java.util.*; +import java.util.ArrayList; +import java.util.List; -import org.apache.maven.plugins.annotations.Parameter; +import org.apache.commons.lang3.SerializationUtils; /** * Run configuration for volumes. @@ -31,14 +32,12 @@ public class RunVolumeConfiguration implements Serializable { /** * List of images names from where volumes are mounted */ - @Parameter private List from; /** * List of bind parameters for binding/mounting host directories * into the container */ - @Parameter private List bind; /** @@ -62,12 +61,21 @@ public List getBind() { public static class Builder { - private RunVolumeConfiguration config = new RunVolumeConfiguration(); + private final RunVolumeConfiguration config; public Builder() { - this.config = new RunVolumeConfiguration(); + this(null); } + public Builder(RunVolumeConfiguration that) { + if (that == null) { + this.config = new RunVolumeConfiguration(); + } else { + this.config = SerializationUtils.clone(that); + } + } + + public Builder from(List args) { if (args != null) { if (config.from == null) { diff --git a/src/main/java/io/fabric8/maven/docker/config/UlimitConfig.java b/src/main/java/io/fabric8/maven/docker/config/run/UlimitConfiguration.java similarity index 79% rename from src/main/java/io/fabric8/maven/docker/config/UlimitConfig.java rename to src/main/java/io/fabric8/maven/docker/config/run/UlimitConfiguration.java index 785bd29ad..7cf726b6a 100644 --- a/src/main/java/io/fabric8/maven/docker/config/UlimitConfig.java +++ b/src/main/java/io/fabric8/maven/docker/config/run/UlimitConfiguration.java @@ -1,82 +1,77 @@ -/* - * Projet docker-maven-plugin - * Copyright S2E 2016 - * ULimitConfig.java, 2016, - */ -package io.fabric8.maven.docker.config; - -import java.io.Serializable; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.maven.plugins.annotations.Parameter; - -/** - * Configuration for ulimit - * - * @since 0.15 - * @author Alexis Thaveau - */ -public class UlimitConfig implements Serializable { - - @Parameter - private String name; - - @Parameter - private Integer hard; - - @Parameter - private Integer soft; - - public UlimitConfig(String name, Integer hard, Integer soft) { - this.name = name; - this.hard = hard; - this.soft = soft; - } - - public String getName() { - return name; - } - - public Integer getHard() { - return hard; - } - - public Integer getSoft() { - return soft; - } - - Pattern ULIMIT_PATTERN = Pattern.compile("^(?[^=]+)=(?[^:]*):?(?[^:]*)$"); - - public UlimitConfig() {} - - public UlimitConfig(String ulimit) { - Matcher matcher = ULIMIT_PATTERN.matcher(ulimit); - if (matcher.matches()) { - name = matcher.group("name"); - hard = asInteger(matcher.group("hard")); - soft = asInteger(matcher.group("soft")); - } else { - throw new IllegalArgumentException("Invalid ulimit specification " + ulimit); - } - } - - private Integer asInteger(String number) { - if (number == null || number.length() == 0) { - return null; - } - return Integer.parseInt(number); - } - - public String serialize() { - if(hard != null && soft != null) { - return name + "="+hard+":"+soft; - } else if(hard != null) { - return name + "="+hard; - } else if(soft != null) { - return name + "=:"+soft; - } else { - return null; - } - } -} +/* + * Projet docker-maven-plugin + * Copyright S2E 2016 + * ULimitConfig.java, 2016, + */ +package io.fabric8.maven.docker.config.run; + +import java.io.Serializable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Configuration for ulimit + * + * @since 0.15 + * @author Alexis Thaveau + */ +public class UlimitConfiguration implements Serializable { + + private String name; + + private Integer hard; + + private Integer soft; + + public UlimitConfiguration(String name, Integer hard, Integer soft) { + this.name = name; + this.hard = hard; + this.soft = soft; + } + + public String getName() { + return name; + } + + public Integer getHard() { + return hard; + } + + public Integer getSoft() { + return soft; + } + + Pattern ULIMIT_PATTERN = Pattern.compile("^(?[^=]+)=(?[^:]*):?(?[^:]*)$"); + + public UlimitConfiguration() {} + + public UlimitConfiguration(String ulimit) { + Matcher matcher = ULIMIT_PATTERN.matcher(ulimit); + if (matcher.matches()) { + name = matcher.group("name"); + hard = asInteger(matcher.group("hard")); + soft = asInteger(matcher.group("soft")); + } else { + throw new IllegalArgumentException("Invalid ulimit specification " + ulimit); + } + } + + private Integer asInteger(String number) { + if (number == null || number.length() == 0) { + return null; + } + return Integer.parseInt(number); + } + + public String serialize() { + if(hard != null && soft != null) { + return name + "="+hard+":"+soft; + } else if(hard != null) { + return name + "="+hard; + } else if(soft != null) { + return name + "=:"+soft; + } else { + return null; + } + } +} diff --git a/src/main/java/io/fabric8/maven/docker/config/VolumeConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/run/VolumeConfiguration.java similarity index 87% rename from src/main/java/io/fabric8/maven/docker/config/VolumeConfiguration.java rename to src/main/java/io/fabric8/maven/docker/config/run/VolumeConfiguration.java index 9d3d1873c..0bfb33ae5 100644 --- a/src/main/java/io/fabric8/maven/docker/config/VolumeConfiguration.java +++ b/src/main/java/io/fabric8/maven/docker/config/run/VolumeConfiguration.java @@ -1,13 +1,10 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.run; -import io.fabric8.maven.docker.util.DeepCopy; - import java.io.Serializable; -import java.lang.String; import java.util.Map; -import org.apache.maven.plugins.annotations.Parameter; +import org.apache.commons.lang3.SerializationUtils; /** * Volume Configuration for Volumes to be created prior to container start @@ -18,19 +15,15 @@ public class VolumeConfiguration implements Serializable { /** Volume Name */ - @Parameter private String name; /** Volume driver for mounting the volume */ - @Parameter private String driver; /** Driver specific options */ - @Parameter private Map opts; /** Volume labels */ - @Parameter private Map labels; public String getName() { @@ -59,7 +52,7 @@ public Builder() { } public Builder(VolumeConfiguration that) { - this.config = that == null ? new VolumeConfiguration() : DeepCopy.copy(that); + this.config = that == null ? new VolumeConfiguration() : SerializationUtils.clone(that); } public Builder name(String name) { diff --git a/src/main/java/io/fabric8/maven/docker/config/WaitConfiguration.java b/src/main/java/io/fabric8/maven/docker/config/run/WaitConfiguration.java similarity index 94% rename from src/main/java/io/fabric8/maven/docker/config/WaitConfiguration.java rename to src/main/java/io/fabric8/maven/docker/config/run/WaitConfiguration.java index 906fd2848..62ab0062b 100644 --- a/src/main/java/io/fabric8/maven/docker/config/WaitConfiguration.java +++ b/src/main/java/io/fabric8/maven/docker/config/run/WaitConfiguration.java @@ -1,10 +1,8 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.run; import java.io.Serializable; import java.util.List; -import org.apache.maven.plugins.annotations.Parameter; - /** * @author roland * @since 12.10.14 @@ -20,36 +18,27 @@ public class WaitConfiguration implements Serializable { public static final String DEFAULT_STATUS_RANGE = String.format("%d..%d", DEFAULT_MIN_STATUS, DEFAULT_MAX_STATUS); - @Parameter private Integer time; /** * @deprecated Use <http><url></url></http> instead */ - @Parameter private String url; - @Parameter private HttpConfiguration http; - @Parameter private ExecConfiguration exec; - @Parameter private TcpConfiguration tcp; - @Parameter Boolean healthy; + Boolean healthy; - @Parameter private String log; - @Parameter private Integer shutdown; - @Parameter private Integer kill; - @Parameter private Integer exit; public WaitConfiguration() {} @@ -209,13 +198,10 @@ public Builder breakOnError(Boolean stop) { } public static class ExecConfiguration implements Serializable { - @Parameter private String postStart; - @Parameter private String preStop; - @Parameter private boolean breakOnError; public ExecConfiguration() {} @@ -241,16 +227,12 @@ public boolean isBreakOnError() { public static class HttpConfiguration implements Serializable { - @Parameter private String url; - @Parameter private String method = DEFAULT_HTTP_METHOD; - @Parameter private String status = DEFAULT_STATUS_RANGE; - @Parameter private boolean allowAllHosts; public HttpConfiguration() {} @@ -286,13 +268,10 @@ public enum TcpConfigMode { } public static class TcpConfiguration implements Serializable { - @Parameter private String host; - @Parameter private List ports; - @Parameter private TcpConfigMode mode; public TcpConfiguration() {} diff --git a/src/main/java/io/fabric8/maven/docker/log/LogOutputSpecFactory.java b/src/main/java/io/fabric8/maven/docker/log/LogOutputSpecFactory.java index d30a7c8ef..c6017274d 100644 --- a/src/main/java/io/fabric8/maven/docker/log/LogOutputSpecFactory.java +++ b/src/main/java/io/fabric8/maven/docker/log/LogOutputSpecFactory.java @@ -19,8 +19,8 @@ import java.util.Map; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.LogConfiguration; -import io.fabric8.maven.docker.config.RunImageConfiguration; +import io.fabric8.maven.docker.config.run.LogConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; import io.fabric8.maven.docker.util.FormatParameterReplacer; /** @@ -93,7 +93,7 @@ private void addLogFormat(LogOutputSpec.Builder builder, LogConfiguration logCon } private LogConfiguration extractLogConfiguration(ImageConfiguration imageConfiguration) { - RunImageConfiguration runConfig = imageConfiguration.getRunConfiguration(); + RunConfiguration runConfig = imageConfiguration.getRunConfiguration(); LogConfiguration logConfig = null; if (runConfig != null) { logConfig = runConfig.getLogConfiguration(); diff --git a/src/main/java/io/fabric8/maven/docker/service/BuildService.java b/src/main/java/io/fabric8/maven/docker/service/BuildService.java deleted file mode 100644 index 1d19a4782..000000000 --- a/src/main/java/io/fabric8/maven/docker/service/BuildService.java +++ /dev/null @@ -1,314 +0,0 @@ -package io.fabric8.maven.docker.service; - -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import io.fabric8.maven.docker.access.BuildOptions; -import io.fabric8.maven.docker.access.DockerAccess; -import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.assembly.DockerAssemblyManager; -import io.fabric8.maven.docker.config.AssemblyConfiguration; -import io.fabric8.maven.docker.config.BuildImageConfiguration; -import io.fabric8.maven.docker.config.CleanupMode; -import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.util.DockerFileUtil; -import io.fabric8.maven.docker.util.EnvUtil; -import io.fabric8.maven.docker.util.ImageName; -import io.fabric8.maven.docker.util.Logger; -import io.fabric8.maven.docker.util.MojoParameters; - -import com.google.common.collect.ImmutableMap; - -import org.apache.maven.plugin.MojoExecutionException; - -public class BuildService { - - private final DockerAccess docker; - private final QueryService queryService; - private final ArchiveService archiveService; - private final RegistryService registryService; - private final Logger log; - - BuildService(DockerAccess docker, QueryService queryService, RegistryService registryService, ArchiveService archiveService, Logger log) { - this.docker = docker; - this.queryService = queryService; - this.registryService = registryService; - this.archiveService = archiveService; - this.log = log; - } - - /** - * Pull the base image if needed and run the build. - * - * @param imageConfig the image configuration - * @param buildContext the build context - * @throws DockerAccessException - * @throws MojoExecutionException - */ - public void buildImage(ImageConfiguration imageConfig, ImagePullManager imagePullManager, BuildContext buildContext) - throws DockerAccessException, MojoExecutionException { - - if (imagePullManager != null) { - autoPullBaseImage(imageConfig, imagePullManager, buildContext); - } - - buildImage(imageConfig, buildContext.getMojoParameters(), checkForNocache(imageConfig), addBuildArgs(buildContext)); - } - - public void tagImage(String imageName, ImageConfiguration imageConfig) throws DockerAccessException { - - List tags = imageConfig.getBuildConfiguration().getTags(); - if (tags.size() > 0) { - log.info("%s: Tag with %s", imageConfig.getDescription(), EnvUtil.stringJoin(tags, ",")); - - for (String tag : tags) { - if (tag != null) { - docker.tag(imageName, new ImageName(imageName, tag).getFullName(), true); - } - } - - log.debug("Tagging image successful!"); - } - } - - /** - * Build an image - * - * @param imageConfig the image configuration - * @param params mojo params for the project - * @param noCache if not null, dictate the caching behaviour. Otherwise its taken from the build configuration - * @param buildArgs - * @throws DockerAccessException - * @throws MojoExecutionException - */ - protected void buildImage(ImageConfiguration imageConfig, MojoParameters params, boolean noCache, Map buildArgs) - throws DockerAccessException, MojoExecutionException { - - String imageName = imageConfig.getName(); - ImageName.validate(imageName); - - BuildImageConfiguration buildConfig = imageConfig.getBuildConfiguration(); - - String oldImageId = null; - - CleanupMode cleanupMode = buildConfig.cleanupMode(); - if (cleanupMode.isRemove()) { - oldImageId = queryService.getImageId(imageName); - } - - long time = System.currentTimeMillis(); - - if (buildConfig.getDockerArchive() != null) { - docker.loadImage(imageName, buildConfig.getAbsoluteDockerTarPath(params)); - log.info("%s: Loaded tarball in %s", buildConfig.getDockerArchive(), EnvUtil.formatDurationTill(time)); - return; - } - - File dockerArchive = archiveService.createArchive(imageName, buildConfig, params, log); - log.info("%s: Created %s in %s", imageConfig.getDescription(), dockerArchive.getName(), EnvUtil.formatDurationTill(time)); - - Map mergedBuildMap = prepareBuildArgs(buildArgs, buildConfig); - - // auto is now supported by docker, consider switching? - BuildOptions opts = - new BuildOptions(buildConfig.getBuildOptions()) - .dockerfile(getDockerfileName(buildConfig)) - .forceRemove(cleanupMode.isRemove()) - .noCache(noCache) - .buildArgs(mergedBuildMap); - String newImageId = doBuildImage(imageName, dockerArchive, opts); - log.info("%s: Built image %s", imageConfig.getDescription(), newImageId); - - if (oldImageId != null && !oldImageId.equals(newImageId)) { - try { - docker.removeImage(oldImageId, true); - log.info("%s: Removed old image %s", imageConfig.getDescription(), oldImageId); - } catch (DockerAccessException exp) { - if (cleanupMode == CleanupMode.TRY_TO_REMOVE) { - log.warn("%s: %s (old image)%s", imageConfig.getDescription(), exp.getMessage(), - (exp.getCause() != null ? " [" + exp.getCause().getMessage() + "]" : "")); - } else { - throw exp; - } - } - } - } - - private Map prepareBuildArgs(Map buildArgs, BuildImageConfiguration buildConfig) { - ImmutableMap.Builder builder = ImmutableMap.builder().putAll(buildArgs); - if (buildConfig.getArgs() != null) { - builder.putAll(buildConfig.getArgs()); - } - return builder.build(); - } - - private String getDockerfileName(BuildImageConfiguration buildConfig) { - if (buildConfig.isDockerFileMode()) { - return buildConfig.getDockerFile().getName(); - } else { - return null; - } - } - - private String doBuildImage(String imageName, File dockerArchive, BuildOptions options) - throws DockerAccessException, MojoExecutionException { - docker.buildImage(imageName, dockerArchive, options); - return queryService.getImageId(imageName); - } - - private Map addBuildArgs(BuildContext buildContext) { - Map buildArgsFromProject = addBuildArgsFromProperties(buildContext.getMojoParameters().getProject().getProperties()); - Map buildArgsFromSystem = addBuildArgsFromProperties(System.getProperties()); - return ImmutableMap.builder() - .putAll(buildContext.getBuildArgs() != null ? buildContext.getBuildArgs() : Collections.emptyMap()) - .putAll(buildArgsFromProject) - .putAll(buildArgsFromSystem) - .build(); - } - - private Map addBuildArgsFromProperties(Properties properties) { - String argPrefix = "docker.buildArg."; - Map buildArgs = new HashMap<>(); - for (Object keyObj : properties.keySet()) { - String key = (String) keyObj; - if (key.startsWith(argPrefix)) { - String argKey = key.replaceFirst(argPrefix, ""); - String value = properties.getProperty(key); - - if (!isEmpty(value)) { - buildArgs.put(argKey, value); - } - } - } - log.debug("Build args set %s", buildArgs); - return buildArgs; - } - - private void autoPullBaseImage(ImageConfiguration imageConfig, ImagePullManager imagePullManager, BuildContext buildContext) - throws DockerAccessException, MojoExecutionException { - BuildImageConfiguration buildConfig = imageConfig.getBuildConfiguration(); - - if (buildConfig.getDockerArchive() != null) { - // No auto pull needed in archive mode - return; - } - - String fromImage; - if (buildConfig.isDockerFileMode()) { - fromImage = extractBaseFromDockerfile(buildConfig, buildContext); - } else { - fromImage = extractBaseFromConfiguration(buildConfig); - } - if (fromImage != null && !DockerAssemblyManager.SCRATCH_IMAGE.equals(fromImage)) { - registryService.pullImageWithPolicy(fromImage, imagePullManager, buildContext.getRegistryConfig(), queryService.hasImage(fromImage)); - } - } - - private String extractBaseFromConfiguration(BuildImageConfiguration buildConfig) { - String fromImage; - fromImage = buildConfig.getFrom(); - if (fromImage == null) { - AssemblyConfiguration assemblyConfig = buildConfig.getAssemblyConfiguration(); - if (assemblyConfig == null) { - fromImage = DockerAssemblyManager.DEFAULT_DATA_BASE_IMAGE; - } - } - return fromImage; - } - - private String extractBaseFromDockerfile(BuildImageConfiguration buildConfig, BuildContext buildContext) { - String fromImage; - try { - File fullDockerFilePath = buildConfig.getAbsoluteDockerFilePath(buildContext.getMojoParameters()); - fromImage = DockerFileUtil.extractBaseImage( - fullDockerFilePath, - DockerFileUtil.createInterpolator(buildContext.getMojoParameters(), buildConfig.getFilter())); - } catch (IOException e) { - // Cant extract base image, so we wont try an auto pull. An error will occur later anyway when - // building the image, so we are passive here. - fromImage = null; - } - return fromImage; - } - - private boolean checkForNocache(ImageConfiguration imageConfig) { - String nocache = System.getProperty("docker.nocache"); - if (nocache != null) { - return nocache.length() == 0 || Boolean.valueOf(nocache); - } else { - BuildImageConfiguration buildConfig = imageConfig.getBuildConfiguration(); - return buildConfig.nocache(); - } - } - - private boolean isEmpty(String str) { - return str == null || str.isEmpty(); - } - - - // =========================================== - - - public static class BuildContext implements Serializable { - - private MojoParameters mojoParameters; - - private Map buildArgs; - - private RegistryService.RegistryConfig registryConfig; - - public BuildContext() { - } - - public MojoParameters getMojoParameters() { - return mojoParameters; - } - - public Map getBuildArgs() { - return buildArgs; - } - - public RegistryService.RegistryConfig getRegistryConfig() { - return registryConfig; - } - - public static class Builder { - - private BuildContext context; - - public Builder() { - this.context = new BuildContext(); - } - - public Builder(BuildContext context) { - this.context = context; - } - - public Builder mojoParameters(MojoParameters mojoParameters) { - context.mojoParameters = mojoParameters; - return this; - } - - public Builder buildArgs(Map buildArgs) { - context.buildArgs = buildArgs; - return this; - } - - public Builder registryConfig(RegistryService.RegistryConfig registryConfig) { - context.registryConfig = registryConfig; - return this; - } - - public BuildContext build() { - return context; - } - } - } - -} diff --git a/src/main/java/io/fabric8/maven/docker/service/ContainerTracker.java b/src/main/java/io/fabric8/maven/docker/service/ContainerTracker.java index 3c062e5db..4da16b175 100644 --- a/src/main/java/io/fabric8/maven/docker/service/ContainerTracker.java +++ b/src/main/java/io/fabric8/maven/docker/service/ContainerTracker.java @@ -1,10 +1,17 @@ package io.fabric8.maven.docker.service; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.RunImageConfiguration; -import io.fabric8.maven.docker.config.WaitConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import io.fabric8.maven.docker.config.run.WaitConfiguration; import io.fabric8.maven.docker.util.GavLabel; /** @@ -197,7 +204,7 @@ static class ContainerShutdownDescriptor { this.imageConfig = imageConfig; this.containerId = containerId; - RunImageConfiguration runConfig = imageConfig.getRunConfiguration(); + RunConfiguration runConfig = imageConfig.getRunConfiguration(); WaitConfiguration waitConfig = runConfig != null ? runConfig.getWaitConfiguration() : null; this.shutdownGracePeriod = waitConfig != null && waitConfig.getShutdown() != null ? waitConfig.getShutdown() : 0; this.killGracePeriod = waitConfig != null && waitConfig.getKill() != null ? waitConfig.getKill() : 0; diff --git a/src/main/java/io/fabric8/maven/docker/service/ImagePullManager.java b/src/main/java/io/fabric8/maven/docker/service/ImagePullManager.java deleted file mode 100644 index ee27616ae..000000000 --- a/src/main/java/io/fabric8/maven/docker/service/ImagePullManager.java +++ /dev/null @@ -1,114 +0,0 @@ -package io.fabric8.maven.docker.service; - -import com.google.gson.JsonObject; - -import io.fabric8.maven.docker.config.ImagePullPolicy; -import io.fabric8.maven.docker.util.AutoPullMode; -import io.fabric8.maven.docker.util.JsonFactory; - -/** - * Simple interface for a ImagePullCache manager, to load and persist the cache. - */ -public class ImagePullManager { - - // Key for the previously used image cache - private static final String CONTEXT_KEY_PREVIOUSLY_PULLED = "CONTEXT_KEY_PREVIOUSLY_PULLED"; - - // image pull policy - private final ImagePullPolicy imagePullPolicy; - - private CacheStore cacheStore; - - public ImagePullManager(CacheStore cacheStore, String imagePullPolicy, String autoPull) { - this.cacheStore = cacheStore; - this.imagePullPolicy = createPullPolicy(imagePullPolicy, autoPull); - } - - ImagePullPolicy getImagePullPolicy() { - return imagePullPolicy; - } - - public ImagePullPolicy createPullPolicy(String imagePullPolicy, String autoPull) { - if (imagePullPolicy != null) { - return ImagePullPolicy.fromString(imagePullPolicy); - } - if (autoPull != null) { - AutoPullMode autoPullMode = AutoPullMode.fromString(autoPull); - switch(autoPullMode) { - case OFF: - return ImagePullPolicy.Never; - case ALWAYS: - return ImagePullPolicy.Always; - case ON: - case ONCE: - return ImagePullPolicy.IfNotPresent; - } - } - return ImagePullPolicy.IfNotPresent; - } - - public boolean hasAlreadyPulled(String image) { - return load().has(image); - } - - public void pulled(String image) { - save(load().add(image)); - } - - - public interface CacheStore { - String get(String key); - - void put(String key, String value); - } - - public ImagePullCache load() { - - String pullCacheJson = cacheStore.get(CONTEXT_KEY_PREVIOUSLY_PULLED); - - ImagePullCache cache = new ImagePullCache(pullCacheJson); - - if (pullCacheJson == null) { - save(cache); - cacheStore.put(CONTEXT_KEY_PREVIOUSLY_PULLED, cache.toString()); - } - return cache; - } - - public void save(ImagePullCache cache) { - cacheStore.put(CONTEXT_KEY_PREVIOUSLY_PULLED, cache.toString()); - } - - /** - * Simple serializable cache for holding image names - * - * @author roland - * @since 20/07/16 - */ - class ImagePullCache { - - private JsonObject cache; - - public ImagePullCache() { - this(null); - } - - public ImagePullCache(String json) { - cache = json != null ? JsonFactory.newJsonObject(json) : new JsonObject(); - } - - public boolean has(String imageName) { - return cache.has(imageName); - } - - public ImagePullCache add(String image) { - cache.addProperty(image, Boolean.TRUE); - return this; - } - - @Override - public String toString() { - return cache.toString(); - } - } -} diff --git a/src/main/java/io/fabric8/maven/docker/service/RegistryService.java b/src/main/java/io/fabric8/maven/docker/service/RegistryService.java deleted file mode 100644 index 64bde1f78..000000000 --- a/src/main/java/io/fabric8/maven/docker/service/RegistryService.java +++ /dev/null @@ -1,228 +0,0 @@ -package io.fabric8.maven.docker.service; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Map; - -import io.fabric8.maven.docker.access.AuthConfig; -import io.fabric8.maven.docker.access.DockerAccess; -import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.config.BuildImageConfiguration; -import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.ImagePullPolicy; -import io.fabric8.maven.docker.util.AuthConfigFactory; -import io.fabric8.maven.docker.util.EnvUtil; -import io.fabric8.maven.docker.util.ImageName; -import io.fabric8.maven.docker.util.Logger; - -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.settings.Settings; - -/** - * Allows to interact with registries, eg. to push/pull images. - */ -public class RegistryService { - - private final DockerAccess docker; - private final Logger log; - - RegistryService(DockerAccess docker, Logger log) { - this.docker = docker; - this.log = log; - } - - /** - * Push a set of images to a registry - * - * @param imageConfigs images to push (but only if they have a build configuration) - * @param retries how often to retry - * @param registryConfig a global registry configuration - * @param skipTag flag to skip pushing tagged images - * @throws DockerAccessException - * @throws MojoExecutionException - */ - public void pushImages(Collection imageConfigs, - int retries, RegistryConfig registryConfig, boolean skipTag) throws DockerAccessException, MojoExecutionException { - for (ImageConfiguration imageConfig : imageConfigs) { - BuildImageConfiguration buildConfig = imageConfig.getBuildConfiguration(); - String name = imageConfig.getName(); - if (buildConfig != null) { - String configuredRegistry = EnvUtil.firstRegistryOf( - new ImageName(imageConfig.getName()).getRegistry(), - imageConfig.getRegistry(), - registryConfig.getRegistry()); - - - AuthConfig authConfig = createAuthConfig(true, new ImageName(name).getUser(), configuredRegistry, registryConfig); - - long start = System.currentTimeMillis(); - docker.pushImage(name, authConfig, configuredRegistry, retries); - log.info("Pushed %s in %s", name, EnvUtil.formatDurationTill(start)); - - if (!skipTag) { - for (String tag : imageConfig.getBuildConfiguration().getTags()) { - if (tag != null) { - docker.pushImage(new ImageName(name, tag).getFullName(), authConfig, configuredRegistry, retries); - } - } - } - } - } - } - - - /** - * Check an image, and, if autoPull is set to true, fetch it. Otherwise if the image - * is not existent, throw an error - * @param registryConfig registry configuration - * - * @throws DockerAccessException - * @throws MojoExecutionException - */ - public void pullImageWithPolicy(String image, ImagePullManager pullManager, RegistryConfig registryConfig, boolean hasImage) - throws DockerAccessException, MojoExecutionException { - - // Already pulled, so we don't need to take care - if (pullManager.hasAlreadyPulled(image)) { - return; - } - - // Check if a pull is required - if (!imageRequiresPull(hasImage, pullManager.getImagePullPolicy(), image)) { - return; - } - - ImageName imageName = new ImageName(image); - long time = System.currentTimeMillis(); - String actualRegistry = EnvUtil.firstRegistryOf( - imageName.getRegistry(), - registryConfig.getRegistry()); - docker.pullImage(imageName.getFullName(), - createAuthConfig(false, null, actualRegistry, registryConfig), actualRegistry); - log.info("Pulled %s in %s", imageName.getFullName(), EnvUtil.formatDurationTill(time)); - pullManager.pulled(image); - - if (actualRegistry != null && !imageName.hasRegistry()) { - // If coming from a registry which was not contained in the original name, add a tag from the - // full name with the registry to the short name with no-registry. - docker.tag(imageName.getFullName(actualRegistry), image, false); - } - } - - - // ============================================================================================================ - - - private boolean imageRequiresPull(boolean hasImage, ImagePullPolicy pullPolicy, String imageName) - throws MojoExecutionException { - - // The logic here is like this (see also #96): - // otherwise: don't pull - - if (pullPolicy == ImagePullPolicy.Never) { - if (!hasImage) { - throw new MojoExecutionException( - String.format("No image '%s' found and pull policy 'Never' is set. Please chose another pull policy or pull the image yourself)", imageName)); - } - return false; - } - - // If the image is not available and mode is not ImagePullPolicy.Never --> pull - if (!hasImage) { - return true; - } - - // If pullPolicy == Always --> pull, otherwise not (we have it already) - return pullPolicy == ImagePullPolicy.Always; - } - - private AuthConfig createAuthConfig(boolean isPush, String user, String registry, RegistryConfig config) - throws MojoExecutionException { - - return config.getAuthConfigFactory().createAuthConfig( - isPush, config.isSkipExtendedAuth(), config.getAuthConfig(), - config.getSettings(), user, registry); - } - - // =========================================== - - - public static class RegistryConfig implements Serializable { - - private String registry; - - private Settings settings; - - private AuthConfigFactory authConfigFactory; - - private boolean skipExtendedAuth; - - private Map authConfig; - - public RegistryConfig() { - } - - public String getRegistry() { - return registry; - } - - public Settings getSettings() { - return settings; - } - - public AuthConfigFactory getAuthConfigFactory() { - return authConfigFactory; - } - - public boolean isSkipExtendedAuth() { - return skipExtendedAuth; - } - - public Map getAuthConfig() { - return authConfig; - } - - public static class Builder { - - private RegistryConfig context = new RegistryConfig(); - - public Builder() { - this.context = new RegistryConfig(); - } - - public Builder(RegistryConfig context) { - this.context = context; - } - - public Builder registry(String registry) { - context.registry = registry; - return this; - } - - public Builder settings(Settings settings) { - context.settings = settings; - return this; - } - - public Builder authConfigFactory(AuthConfigFactory authConfigFactory) { - context.authConfigFactory = authConfigFactory; - return this; - } - - public Builder skipExtendedAuth(boolean skipExtendedAuth) { - context.skipExtendedAuth = skipExtendedAuth; - return this; - } - - public Builder authConfig(Map authConfig) { - context.authConfig = authConfig; - return this; - } - - public RegistryConfig build() { - return context; - } - } - } - -} diff --git a/src/main/java/io/fabric8/maven/docker/service/RunService.java b/src/main/java/io/fabric8/maven/docker/service/RunService.java index 717fc9cc2..9cd450467 100644 --- a/src/main/java/io/fabric8/maven/docker/service/RunService.java +++ b/src/main/java/io/fabric8/maven/docker/service/RunService.java @@ -21,7 +21,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -40,13 +39,13 @@ import io.fabric8.maven.docker.access.ExecException; import io.fabric8.maven.docker.access.NetworkCreateConfig; import io.fabric8.maven.docker.access.PortMapping; -import io.fabric8.maven.docker.config.Arguments; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.NetworkConfig; -import io.fabric8.maven.docker.config.RestartPolicy; -import io.fabric8.maven.docker.config.RunImageConfiguration; -import io.fabric8.maven.docker.config.RunVolumeConfiguration; -import io.fabric8.maven.docker.config.VolumeConfiguration; +import io.fabric8.maven.docker.config.build.Arguments; +import io.fabric8.maven.docker.config.run.NetworkConfiguration; +import io.fabric8.maven.docker.config.run.RestartPolicy; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import io.fabric8.maven.docker.config.run.RunVolumeConfiguration; +import io.fabric8.maven.docker.config.run.VolumeConfiguration; import io.fabric8.maven.docker.log.LogOutputSpecFactory; import io.fabric8.maven.docker.model.Container; import io.fabric8.maven.docker.model.ContainerDetails; @@ -84,6 +83,8 @@ public class RunService { private final LogOutputSpecFactory logConfig; + private StartOrderResolver startOrderResolver; + public RunService(DockerAccess docker, QueryService queryService, ContainerTracker tracker, @@ -91,6 +92,7 @@ public RunService(DockerAccess docker, Logger log) { this.docker = docker; this.queryService = queryService; + this.startOrderResolver = new StartOrderResolver(queryService); this.tracker = tracker; this.log = log; this.logConfig = logConfig; @@ -109,7 +111,7 @@ public String execInContainer(String containerId, String command, ImageConfigura throws DockerAccessException, ExecException { Arguments arguments = new Arguments(); arguments.setExec(Arrays.asList(EnvUtil.splitOnSpaceWithEscape(command))); - String execContainerId = docker.createExecContainer(containerId, arguments); + String execContainerId = docker.createExecContainer(containerId, arguments.getExec()); docker.startExecContainer(execContainerId, logConfig.createSpec(containerId, imageConfiguration)); ExecDetails execContainer = docker.getExecContainer(execContainerId); @@ -141,7 +143,7 @@ public String createAndStartContainer(ImageConfiguration imageConfig, File baseDir, String defaultContainerNamePattern, Date buildTimestamp) throws DockerAccessException { - RunImageConfiguration runConfig = imageConfig.getRunConfiguration(); + RunConfiguration runConfig = imageConfig.getRunConfiguration(); String imageName = imageConfig.getName(); Collection existingContainers = queryService.getContainersForImage(imageName, true); @@ -215,7 +217,7 @@ public void stopStartedContainers(boolean keepContainer, } private void collectCustomNetworks(Set networksToRemove, ContainerTracker.ContainerShutdownDescriptor descriptor, boolean removeCustomNetworks) throws DockerAccessException { - final NetworkConfig config = descriptor.getImageConfiguration().getRunConfiguration().getNetworkingConfig(); + final NetworkConfiguration config = descriptor.getImageConfiguration().getRunConfiguration().getNetworkingConfig(); if (removeCustomNetworks && config.isCustomNetwork()) { networksToRemove.add(queryService.getNetworkByName(config.getCustomNetwork())); } @@ -236,8 +238,8 @@ public String lookupContainer(String lookup) { * @param images list of images for which the order should be created * @return list of images in the right startup order */ - public List getImagesConfigsInOrder(QueryService queryService, List images) { - return StartOrderResolver.resolve(queryService, convertToResolvables(images)); + public List getImagesConfigsInOrder(List images) { + return startOrderResolver.resolve(images); } /** @@ -247,7 +249,7 @@ public List getImagesConfigsInOrder(QueryService * @param properties properties to lookup variables * @return the portmapping */ - public PortMapping createPortMapping(RunImageConfiguration runConfig, Properties properties) { + public PortMapping createPortMapping(RunConfiguration runConfig, Properties properties) { try { return new PortMapping(runConfig.getPorts(), properties); } catch (IllegalArgumentException exp) { @@ -271,20 +273,8 @@ public void run() { }); } - private List convertToResolvables(List images) { - List ret = new ArrayList<>(); - for (ImageConfiguration config : images) { - if (config.getRunConfiguration().skip()) { - log.info("%s: Skipped running", config.getDescription()); - } else { - ret.add(config); - } - } - return ret; - } - // visible for testing - ContainerCreateConfig createContainerConfig(String imageName, RunImageConfiguration runConfig, PortMapping mappedPorts, + ContainerCreateConfig createContainerConfig(String imageName, RunConfiguration runConfig, PortMapping mappedPorts, GavLabel gavLabel, Properties mavenProps, File baseDir) throws DockerAccessException { try { @@ -305,7 +295,7 @@ ContainerCreateConfig createContainerConfig(String imageName, RunImageConfigurat config.binds(volumeConfig.getBind()); } - NetworkConfig networkConfig = runConfig.getNetworkingConfig(); + NetworkConfiguration networkConfig = runConfig.getNetworkingConfig(); if(networkConfig.isCustomNetwork() && networkConfig.hasAliases()) { ContainerNetworkingConfig networkingConfig = new ContainerNetworkingConfig() @@ -330,9 +320,9 @@ private Map mergeLabels(Map labels, GavLabel run return ret; } - ContainerHostConfig createContainerHostConfig(RunImageConfiguration runConfig, PortMapping mappedPorts, File baseDir) + ContainerHostConfig createContainerHostConfig(RunConfiguration runConfig, PortMapping mappedPorts, File baseDir) throws DockerAccessException { - RestartPolicy restartPolicy = runConfig.getRestartPolicy(); + RestartPolicy restartPolicy = runConfig.getRestartPolicy() != null ? runConfig.getRestartPolicy() : RestartPolicy.DEFAULT; List links = findContainerIdsForLinks(runConfig.getLinks(), @@ -366,8 +356,8 @@ ContainerHostConfig createContainerHostConfig(RunImageConfiguration runConfig, P return config; } - private void addNetworkingConfig(ContainerHostConfig config, RunImageConfiguration runConfig) throws DockerAccessException { - NetworkConfig networkConfig = runConfig.getNetworkingConfig(); + private void addNetworkingConfig(ContainerHostConfig config, RunConfiguration runConfig) throws DockerAccessException { + NetworkConfiguration networkConfig = runConfig.getNetworkingConfig(); if (networkConfig.isStandardNetwork()) { String alias = networkConfig.getContainerAlias(); String containerId = alias != null ? findContainerId(alias, false) : null; @@ -377,7 +367,7 @@ private void addNetworkingConfig(ContainerHostConfig config, RunImageConfigurati } } - private void addVolumeConfig(ContainerHostConfig config, RunImageConfiguration runConfig, File baseDir) throws DockerAccessException { + private void addVolumeConfig(ContainerHostConfig config, RunConfiguration runConfig, File baseDir) throws DockerAccessException { RunVolumeConfiguration volConfig = runConfig.getVolumeConfiguration(); if (volConfig != null) { resolveRelativeVolumeBindings(baseDir, volConfig); diff --git a/src/main/java/io/fabric8/maven/docker/service/ServiceHub.java b/src/main/java/io/fabric8/maven/docker/service/ServiceHub.java index 404a03310..c86f7b67e 100644 --- a/src/main/java/io/fabric8/maven/docker/service/ServiceHub.java +++ b/src/main/java/io/fabric8/maven/docker/service/ServiceHub.java @@ -17,7 +17,11 @@ package io.fabric8.maven.docker.service; import io.fabric8.maven.docker.access.DockerAccess; -import io.fabric8.maven.docker.assembly.DockerAssemblyManager; +import io.fabric8.maven.docker.build.maven.assembly.DockerAssemblyManager; +import io.fabric8.maven.docker.build.docker.DockerBuildService; +import io.fabric8.maven.docker.build.docker.DockerRegistryService; +import io.fabric8.maven.docker.build.maven.MavenArchiveService; +import io.fabric8.maven.docker.build.maven.MavenCacheBackend; import io.fabric8.maven.docker.log.LogOutputSpecFactory; import io.fabric8.maven.docker.util.Logger; @@ -38,10 +42,10 @@ public class ServiceHub { private final QueryService queryService; private final RunService runService; - private final RegistryService registryService; - private final BuildService buildService; + private final DockerRegistryService registryService; + private final DockerBuildService buildService; private final MojoExecutionService mojoExecutionService; - private final ArchiveService archiveService; + private final MavenArchiveService archiveService; private final VolumeService volumeService; private final WatchService watchService; private final WaitService waitService; @@ -53,13 +57,13 @@ public class ServiceHub { this.dockerAccess = dockerAccess; mojoExecutionService = new MojoExecutionService(project, session, pluginManager); - archiveService = new ArchiveService(dockerAssemblyManager, logger); + archiveService = new MavenArchiveService(dockerAssemblyManager, logger); if (dockerAccess != null) { queryService = new QueryService(dockerAccess); - registryService = new RegistryService(dockerAccess, logger); + registryService = new DockerRegistryService(dockerAccess, logger, new MavenCacheBackend(session)); runService = new RunService(dockerAccess, queryService, containerTracker, logSpecFactory, logger); - buildService = new BuildService(dockerAccess, queryService, registryService, archiveService, logger); + buildService = new DockerBuildService(dockerAccess, registryService, logger); volumeService = new VolumeService(dockerAccess); watchService = new WatchService(archiveService, buildService, dockerAccess, mojoExecutionService, queryService, runService, logger); waitService = new WaitService(dockerAccess, queryService, logger); @@ -89,7 +93,7 @@ public DockerAccess getDockerAccess() { * * @return get the build service */ - public BuildService getBuildService() { + public DockerBuildService getBuildService() { checkDockerAccessInitialization(); return buildService; } @@ -109,7 +113,7 @@ public QueryService getQueryService() { * * @return query service */ - public RegistryService getRegistryService() { + public DockerRegistryService getRegistryService() { checkDockerAccessInitialization(); return registryService; } @@ -161,7 +165,7 @@ public WaitService getWaitService() { * * @return the archive service */ - public ArchiveService getArchiveService() { + public MavenArchiveService getArchiveService() { return archiveService; } diff --git a/src/main/java/io/fabric8/maven/docker/service/ServiceHubFactory.java b/src/main/java/io/fabric8/maven/docker/service/ServiceHubFactory.java index 06dbc24e5..2f50f90c8 100644 --- a/src/main/java/io/fabric8/maven/docker/service/ServiceHubFactory.java +++ b/src/main/java/io/fabric8/maven/docker/service/ServiceHubFactory.java @@ -1,7 +1,7 @@ package io.fabric8.maven.docker.service; import io.fabric8.maven.docker.access.DockerAccess; -import io.fabric8.maven.docker.assembly.DockerAssemblyManager; +import io.fabric8.maven.docker.build.maven.assembly.DockerAssemblyManager; import io.fabric8.maven.docker.util.Logger; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.BuildPluginManager; diff --git a/src/main/java/io/fabric8/maven/docker/service/VolumeService.java b/src/main/java/io/fabric8/maven/docker/service/VolumeService.java index 03989d1a3..0c5c4efc0 100644 --- a/src/main/java/io/fabric8/maven/docker/service/VolumeService.java +++ b/src/main/java/io/fabric8/maven/docker/service/VolumeService.java @@ -3,9 +3,7 @@ import io.fabric8.maven.docker.access.DockerAccess; import io.fabric8.maven.docker.access.DockerAccessException; import io.fabric8.maven.docker.access.VolumeCreateConfig; -import io.fabric8.maven.docker.config.VolumeConfiguration; - -import java.lang.String; +import io.fabric8.maven.docker.config.run.VolumeConfiguration; /** * Service Class for helping control Volumes diff --git a/src/main/java/io/fabric8/maven/docker/service/WaitService.java b/src/main/java/io/fabric8/maven/docker/service/WaitService.java index 5c2e64856..0a9667468 100644 --- a/src/main/java/io/fabric8/maven/docker/service/WaitService.java +++ b/src/main/java/io/fabric8/maven/docker/service/WaitService.java @@ -9,8 +9,8 @@ import io.fabric8.maven.docker.access.DockerAccess; import io.fabric8.maven.docker.access.DockerAccessException; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.RunImageConfiguration; -import io.fabric8.maven.docker.config.WaitConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import io.fabric8.maven.docker.config.run.WaitConfiguration; import io.fabric8.maven.docker.log.DefaultLogCallback; import io.fabric8.maven.docker.log.LogDispatcher; import io.fabric8.maven.docker.log.LogOutputSpec; @@ -129,7 +129,7 @@ private List prepareWaitCheckers(ImageConfiguration imageConfig, Pr } private WaitConfiguration getWaitConfiguration(ImageConfiguration imageConfig) { - RunImageConfiguration runConfig = imageConfig.getRunConfiguration(); + RunConfiguration runConfig = imageConfig.getRunConfiguration(); return runConfig.getWaitConfiguration(); } diff --git a/src/main/java/io/fabric8/maven/docker/service/WatchService.java b/src/main/java/io/fabric8/maven/docker/service/WatchService.java index 5c12c8fd7..0eccdb97f 100644 --- a/src/main/java/io/fabric8/maven/docker/service/WatchService.java +++ b/src/main/java/io/fabric8/maven/docker/service/WatchService.java @@ -6,6 +6,8 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Map; +import java.util.Properties; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -15,15 +17,17 @@ import io.fabric8.maven.docker.access.DockerAccessException; import io.fabric8.maven.docker.access.ExecException; import io.fabric8.maven.docker.access.PortMapping; -import io.fabric8.maven.docker.assembly.AssemblyFiles; +import io.fabric8.maven.docker.build.docker.DockerBuildService; +import io.fabric8.maven.docker.build.maven.MavenArchiveService; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; +import io.fabric8.maven.docker.build.maven.assembly.AssemblyFiles; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.WatchImageConfiguration; +import io.fabric8.maven.docker.config.WatchConfiguration; import io.fabric8.maven.docker.config.WatchMode; import io.fabric8.maven.docker.log.LogDispatcher; import io.fabric8.maven.docker.service.helper.StartContainerExecutor; -import io.fabric8.maven.docker.util.Logger; -import io.fabric8.maven.docker.util.MojoParameters; import io.fabric8.maven.docker.util.GavLabel; +import io.fabric8.maven.docker.util.Logger; import io.fabric8.maven.docker.util.StartOrderResolver; import io.fabric8.maven.docker.util.Task; import org.apache.maven.plugin.MojoExecutionException; @@ -35,15 +39,15 @@ */ public class WatchService { - private final ArchiveService archiveService; - private final BuildService buildService; + private final MavenArchiveService archiveService; + private final DockerBuildService buildService; private final DockerAccess dockerAccess; private final MojoExecutionService mojoExecutionService; private final QueryService queryService; private final RunService runService; private final Logger log; - public WatchService(ArchiveService archiveService, BuildService buildService, DockerAccess dockerAccess, MojoExecutionService mojoExecutionService, QueryService queryService, RunService + public WatchService(MavenArchiveService archiveService, DockerBuildService buildService, DockerAccess dockerAccess, MojoExecutionService mojoExecutionService, QueryService queryService, RunService runService, Logger log) { this.archiveService = archiveService; this.buildService = buildService; @@ -54,21 +58,20 @@ public WatchService(ArchiveService archiveService, BuildService buildService, Do this.log = log; } - public synchronized void watch(WatchContext context, BuildService.BuildContext buildContext, List images) throws DockerAccessException, - MojoExecutionException { + public synchronized void watch(WatchContext watchContext, MavenBuildContext buildContext, List images) throws + IOException { // Important to be be a single threaded scheduler since watch jobs must run serialized ScheduledExecutorService executor = null; try { executor = Executors.newSingleThreadScheduledExecutor(); - for (StartOrderResolver.Resolvable resolvable : runService.getImagesConfigsInOrder(queryService, images)) { - final ImageConfiguration imageConfig = (ImageConfiguration) resolvable; + for (ImageConfiguration imageConfig : runService.getImagesConfigsInOrder(images)) { String imageId = queryService.getImageId(imageConfig.getName()); String containerId = runService.lookupContainer(imageConfig.getName()); - ImageWatcher watcher = new ImageWatcher(imageConfig, context, imageId, containerId); + ImageWatcher watcher = new ImageWatcher(imageConfig, watchContext, imageId, containerId); long interval = watcher.getInterval(); WatchMode watchMode = watcher.getWatchMode(imageConfig); @@ -80,12 +83,12 @@ public synchronized void watch(WatchContext context, BuildService.BuildContext b imageConfig.getBuildConfiguration().getAssemblyConfiguration() != null) { if (watcher.isCopy()) { String containerBaseDir = imageConfig.getBuildConfiguration().getAssemblyConfiguration().getTargetDir(); - schedule(executor, createCopyWatchTask(watcher, context.getMojoParameters(), containerBaseDir), interval); + schedule(executor, createCopyWatchTask(watcher, buildContext, containerBaseDir), interval); tasks.add("copying artifacts"); } if (watcher.isBuild()) { - schedule(executor, createBuildWatchTask(watcher, context.getMojoParameters(), watchMode == WatchMode.both, buildContext), interval); + schedule(executor, createBuildWatchTask(watcher, watchMode == WatchMode.both, buildContext), interval); tasks.add("rebuilding"); } } @@ -100,8 +103,8 @@ public synchronized void watch(WatchContext context, BuildService.BuildContext b } } log.info("Waiting ..."); - if (!context.isKeepRunning()) { - runService.addShutdownHookForStoppingContainers(context.isKeepContainer(), context.isRemoveVolumes(), context.isAutoCreateCustomNetworks()); + if (!watchContext.isKeepRunning()) { + runService.addShutdownHookForStoppingContainers(watchContext.isKeepContainer(), watchContext.isRemoveVolumes(), watchContext.isAutoCreateCustomNetworks()); } wait(); } catch (InterruptedException e) { @@ -118,10 +121,10 @@ private void schedule(ScheduledExecutorService executor, Runnable runnable, long } private Runnable createCopyWatchTask(final ImageWatcher watcher, - final MojoParameters mojoParameters, final String containerBaseDir) throws MojoExecutionException { + final MavenBuildContext buildContext, final String containerBaseDir) throws IOException { final ImageConfiguration imageConfig = watcher.getImageConfiguration(); - final AssemblyFiles files = archiveService.getAssemblyFiles(imageConfig, mojoParameters); + final AssemblyFiles files = archiveService.getAssemblyFiles(imageConfig, buildContext); return new Runnable() { @Override public void run() { @@ -131,10 +134,10 @@ public void run() { log.info("%s: Assembly changed. Copying changed files to container ...", imageConfig.getDescription()); File changedFilesArchive = archiveService.createChangedFilesArchive(entries, files.getAssemblyDirectory(), - imageConfig.getName(), mojoParameters); + imageConfig.getName(), buildContext); dockerAccess.copyArchive(watcher.getContainerId(), changedFilesArchive, containerBaseDir); callPostExec(watcher); - } catch (MojoExecutionException | IOException | ExecException e) { + } catch (IOException | ExecException e) { log.error("%s: Error when copying files to container %s: %s", imageConfig.getDescription(), watcher.getContainerId(), e.getMessage()); } @@ -150,47 +153,42 @@ private void callPostExec(ImageWatcher watcher) throws DockerAccessException, Ex } } - private Runnable createBuildWatchTask(final ImageWatcher watcher, - final MojoParameters mojoParameters, final boolean doRestart, final BuildService.BuildContext buildContext) - throws MojoExecutionException { + private Runnable createBuildWatchTask(final ImageWatcher watcher, final boolean doRestart, final MavenBuildContext buildContext) + throws IOException { final ImageConfiguration imageConfig = watcher.getImageConfiguration(); - final AssemblyFiles files = archiveService.getAssemblyFiles(imageConfig, mojoParameters); + final AssemblyFiles files = archiveService.getAssemblyFiles(imageConfig, buildContext); if (files.isEmpty()) { log.error("No assembly files for %s. Are you sure you invoked together with the `package` goal?", imageConfig.getDescription()); - throw new MojoExecutionException("No files to watch found for " + imageConfig); + throw new IllegalArgumentException("No files to watch found for " + imageConfig); } - return new Runnable() { - @Override - public void run() { - List entries = files.getUpdatedEntriesAndRefresh(); - if (entries != null && entries.size() > 0) { - try { - log.info("%s: Assembly changed. Rebuild ...", imageConfig.getDescription()); + return () -> { + List entries = files.getUpdatedEntriesAndRefresh(); + if (entries != null && entries.size() > 0) { + try { + log.info("%s: Assembly changed. Rebuild ...", imageConfig.getDescription()); - if (watcher.getWatchContext().getImageCustomizer() != null) { - log.info("%s: Customizing the image ...", imageConfig.getDescription()); - watcher.getWatchContext().getImageCustomizer().execute(imageConfig); - } + if (watcher.getWatchContext().getImageCustomizer() != null) { + log.info("%s: Customizing the image ...", imageConfig.getDescription()); + watcher.getWatchContext().getImageCustomizer().execute(imageConfig); + } - buildService.buildImage(imageConfig, null, buildContext); + buildService.buildImage(imageConfig, buildContext, watcher.getWatchContext().getBuildArgs()); - String name = imageConfig.getName(); - watcher.setImageId(queryService.getImageId(name)); - if (doRestart) { - restartContainer(watcher); - } - callPostGoal(watcher); - } catch (Exception e) { - log.error("%s: Error when rebuilding - %s", imageConfig.getDescription(), e); + String name = imageConfig.getName(); + watcher.setImageId(queryService.getImageId(name)); + if (doRestart) { + restartContainer(watcher); } + callPostGoal(watcher); + } catch (Exception e) { + log.error("%s: Error when rebuilding - %s", imageConfig.getDescription(), e); } } }; } - private Runnable createRestartWatchTask(final ImageWatcher watcher) - throws DockerAccessException { + private Runnable createRestartWatchTask(final ImageWatcher watcher) { final String imageName = watcher.getImageName(); @@ -226,7 +224,8 @@ private Task defaultContainerRestartTask() { return watcher -> { // Stop old one ImageConfiguration imageConfig = watcher.getImageConfiguration(); - PortMapping mappedPorts = runService.createPortMapping(imageConfig.getRunConfiguration(), watcher.getWatchContext().getMojoParameters().getProject().getProperties()); + PortMapping mappedPorts = runService.createPortMapping(imageConfig.getRunConfiguration(), + watcher.getWatchContext().getProperties()); String id = watcher.getContainerId(); String optionalPreStop = getPreStopCommand(imageConfig); @@ -242,8 +241,8 @@ private Task defaultContainerRestartTask() { .log(log) .portMapping(mappedPorts) .gavLabel(watcher.watchContext.getGavLabel()) - .projectProperties(watcher.watchContext.mojoParameters.getProject().getProperties()) - .basedir(watcher.watchContext.mojoParameters.getProject().getBasedir()) + .projectProperties(watcher.watchContext.getProperties()) + .basedir(watcher.watchContext.getBasedir()) .imageConfig(imageConfig) .serviceHub(watcher.watchContext.hub) .logOutputSpecFactory(watcher.watchContext.serviceHubFactory.getLogOutputSpecFactory()) @@ -356,26 +355,26 @@ public WatchContext getWatchContext() { // ========================================================= private int getWatchInterval(ImageConfiguration imageConfig) { - WatchImageConfiguration watchConfig = imageConfig.getWatchConfiguration(); + WatchConfiguration watchConfig = imageConfig.getWatchConfiguration(); int interval = watchConfig != null ? watchConfig.getInterval() : watchContext.getWatchInterval(); return interval < 100 ? 100 : interval; } private String getPostExec(ImageConfiguration imageConfig) { - WatchImageConfiguration watchConfig = imageConfig.getWatchConfiguration(); + WatchConfiguration watchConfig = imageConfig.getWatchConfiguration(); return watchConfig != null && watchConfig.getPostExec() != null ? watchConfig.getPostExec() : watchContext.getWatchPostExec(); } private String getPostGoal(ImageConfiguration imageConfig) { - WatchImageConfiguration watchConfig = imageConfig.getWatchConfiguration(); + WatchConfiguration watchConfig = imageConfig.getWatchConfiguration(); return watchConfig != null && watchConfig.getPostGoal() != null ? watchConfig.getPostGoal() : watchContext.getWatchPostGoal(); } private WatchMode getWatchMode(ImageConfiguration imageConfig) { - WatchImageConfiguration watchConfig = imageConfig.getWatchConfiguration(); + WatchConfiguration watchConfig = imageConfig.getWatchConfiguration(); WatchMode mode = watchConfig != null ? watchConfig.getMode() : null; return mode != null ? mode : watchContext.getWatchMode(); } @@ -388,8 +387,6 @@ private WatchMode getWatchMode(ImageConfiguration imageConfig) { */ public static class WatchContext implements Serializable { - private MojoParameters mojoParameters; - private WatchMode watchMode; private int watchInterval; @@ -421,14 +418,13 @@ public static class WatchContext implements Serializable { private Date buildTimestamp; private String containerNamePattern; + private Map buildArgs; + private Properties properties; + private File basedir; public WatchContext() { } - public MojoParameters getMojoParameters() { - return mojoParameters; - } - public WatchMode getWatchMode() { return watchMode; } @@ -481,6 +477,18 @@ public String getContainerNamePattern() { return containerNamePattern; } + public Map getBuildArgs() { + return buildArgs; + } + + public Properties getProperties() { + return properties; + } + + public File getBasedir() { + return basedir; + } + public static class Builder { private WatchContext context; @@ -493,11 +501,6 @@ public Builder(WatchContext context) { this.context = context; } - public Builder mojoParameters(MojoParameters mojoParameters) { - context.mojoParameters = mojoParameters; - return this; - } - public Builder watchMode(WatchMode watchMode) { context.watchMode = watchMode; return this; @@ -573,7 +576,17 @@ public Builder serviceHubFactory(ServiceHubFactory serviceHubFactory){ return this; } - public Builder dispatcher(LogDispatcher dispatcher){ + public Builder properties(Properties properties) { + context.properties = properties; + return this; + } + + public Builder basedir(File basedir) { + context.basedir = basedir; + return this; + } + + public Builder dispatcher(LogDispatcher dispatcher) { context.dispatcher = dispatcher; return this; } @@ -588,6 +601,10 @@ public Builder containerNamePattern(String containerNamePattern) { return this; } + public Builder buildArgs(Map buildArgs) { + context.buildArgs = buildArgs; + return this; + } public WatchContext build() { return context; diff --git a/src/main/java/io/fabric8/maven/docker/service/helper/StartContainerExecutor.java b/src/main/java/io/fabric8/maven/docker/service/helper/StartContainerExecutor.java index fa9ce09dd..5dbb7cadd 100644 --- a/src/main/java/io/fabric8/maven/docker/service/helper/StartContainerExecutor.java +++ b/src/main/java/io/fabric8/maven/docker/service/helper/StartContainerExecutor.java @@ -11,11 +11,11 @@ import io.fabric8.maven.docker.access.DockerAccessException; import io.fabric8.maven.docker.access.ExecException; import io.fabric8.maven.docker.access.PortMapping; -import io.fabric8.maven.docker.config.ConfigHelper; +import io.fabric8.maven.docker.util.ConfigHelper; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.LogConfiguration; -import io.fabric8.maven.docker.config.RunImageConfiguration; -import io.fabric8.maven.docker.config.WaitConfiguration; +import io.fabric8.maven.docker.config.run.LogConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import io.fabric8.maven.docker.config.run.WaitConfiguration; import io.fabric8.maven.docker.log.LogDispatcher; import io.fabric8.maven.docker.log.LogOutputSpecFactory; import io.fabric8.maven.docker.model.Container; @@ -123,7 +123,7 @@ boolean showLogs() { } } - RunImageConfiguration runConfig = imageConfig.getRunConfiguration(); + RunConfiguration runConfig = imageConfig.getRunConfiguration(); if (runConfig != null) { LogConfiguration logConfig = runConfig.getLogConfiguration(); if (logConfig != null) { diff --git a/src/main/java/io/fabric8/maven/docker/util/AuthConfigFactory.java b/src/main/java/io/fabric8/maven/docker/util/AuthConfigFactory.java deleted file mode 100644 index 9fa4f1388..000000000 --- a/src/main/java/io/fabric8/maven/docker/util/AuthConfigFactory.java +++ /dev/null @@ -1,557 +0,0 @@ -package io.fabric8.maven.docker.util; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import io.fabric8.maven.docker.access.AuthConfig; -import io.fabric8.maven.docker.access.ecr.EcrExtendedAuth; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.settings.Server; -import org.apache.maven.settings.Settings; -import org.codehaus.plexus.PlexusContainer; -import org.codehaus.plexus.component.repository.exception.ComponentLookupException; -import org.codehaus.plexus.util.xml.Xpp3Dom; -import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; -import org.yaml.snakeyaml.Yaml; - -/** - * Factory for creating docker specific authentication configuration - * - * @author roland - * @since 29.07.14 - */ -public class AuthConfigFactory { - - // Properties for specifying username, password (can be encrypted), email and authtoken (not used yet) - // + whether to check for OpenShift authentication - public static final String AUTH_USERNAME = "username"; - public static final String AUTH_PASSWORD = "password"; - public static final String AUTH_EMAIL = "email"; - public static final String AUTH_AUTHTOKEN = "authToken"; - private static final String AUTH_USE_OPENSHIFT_AUTH = "useOpenShiftAuth"; - - static final String DOCKER_LOGIN_DEFAULT_REGISTRY = "https://index.docker.io/v1/"; - - private final PlexusContainer container; - private final Gson gson; - - private Logger log; - private static final String[] DEFAULT_REGISTRIES = new String[]{ - "docker.io", "index.docker.io", "registry.hub.docker.com" - }; - - /** - * Constructor which should be used during startup phase of a plugin - * - * @param container the container used for do decryption of passwords - */ - public AuthConfigFactory(PlexusContainer container) { - this.container = container; - this.gson = new Gson(); - } - - public void setLog(Logger log) { - this.log = log; - } - - /** - * Create an authentication config object which can be used for communication with a Docker registry - * - * The authentication information is looked up at various places (in this order): - * - *
    - *
  • From system properties
  • - *
  • From the provided map which can contain key-value pairs
  • - *
  • From the openshift settings in ~/.config/kube
  • - *
  • From the Maven settings stored typically in ~/.m2/settings.xml
  • - *
  • From the Docker settings stored in ~/.docker/config.json
  • - *
- * - * The following properties (prefix with 'docker.') and config key are evaluated: - * - *
    - *
  • username: User to authenticate
  • - *
  • password: Password to authenticate. Can be encrypted
  • - *
  • email: Optional EMail address which is send to the registry, too
  • - *
- * - * If the repository is in an aws ecr registry and skipExtendedAuth is not true, if found - * credentials are not from docker settings, they will be interpreted as iam credentials - * and exchanged for ecr credentials. - * - * @param isPush if true this AuthConfig is created for a push, if false it's for a pull - * @param skipExtendedAuth if false, do not execute extended authentication methods - * @param authConfig String-String Map holding configuration info from the plugin's configuration. Can be null in - * which case the settings are consulted. - * @param settings the global Maven settings object - * @param user user to check for - * @param registry registry to use, might be null in which case a default registry is checked, - * @return the authentication configuration or null if none could be found - * - * @throws MojoFailureException - */ - public AuthConfig createAuthConfig(boolean isPush, boolean skipExtendedAuth, Map authConfig, Settings settings, String user, String registry) - throws MojoExecutionException { - - AuthConfig ret = createStandardAuthConfig(isPush, authConfig, settings, user, registry); - if (ret != null) { - if (registry == null || skipExtendedAuth) { - return ret; - } - try { - return extendedAuthentication(ret, registry); - } catch (IOException e) { - throw new MojoExecutionException(e.getMessage(), e); - } - } - - // Finally check ~/.docker/config.json - ret = getAuthConfigFromDockerConfig(registry); - if (ret != null) { - log.debug("AuthConfig: credentials from ~/.docker/config.json"); - return ret; - } - - log.debug("AuthConfig: no credentials found"); - return null; - } - - - /** - * Try various extended authentication method. Currently only supports amazon ECR - * - * @param standardAuthConfig The locally stored credentials. - * @param registry The registry to authenticated against. - * @return The given credentials, if registry does not need extended authentication; - * else, the credentials after authentication. - * @throws IOException - * @throws MojoExecutionException - */ - private AuthConfig extendedAuthentication(AuthConfig standardAuthConfig, String registry) throws IOException, MojoExecutionException { - EcrExtendedAuth ecr = new EcrExtendedAuth(log, registry); - if (ecr.isAwsRegistry()) { - return ecr.extendedAuth(standardAuthConfig); - } - return standardAuthConfig; - } - - /** - * Create an authentication config object which can be used for communication with a Docker registry - * - * The authentication information is looked up at various places (in this order): - * - *
    - *
  • From system properties
  • - *
  • From the provided map which can contain key-value pairs
  • - *
  • From the openshift settings in ~/.config/kube
  • - *
  • From the Maven settings stored typically in ~/.m2/settings.xml
  • - *
- * - * The following properties (prefix with 'docker.') and config key are evaluated: - * - *
    - *
  • username: User to authenticate
  • - *
  • password: Password to authenticate. Can be encrypted
  • - *
  • email: Optional EMail address which is send to the registry, too
  • - *
- * - * - * @param isPush if true this AuthConfig is created for a push, if false it's for a pull - * @param authConfigMap String-String Map holding configuration info from the plugin's configuration. Can be null in - * which case the settings are consulted. - * @param settings the global Maven settings object - * @param user user to check for - * @param registry registry to use, might be null in which case a default registry is checked, - * @return the authentication configuration or null if none could be found - * - * @throws MojoFailureException - */ - private AuthConfig createStandardAuthConfig(boolean isPush, Map authConfigMap, Settings settings, String user, String registry) - throws MojoExecutionException { - AuthConfig ret; - - // Check first for specific configuration based on direction (pull or push), then for a default value - for (LookupMode lookupMode : new LookupMode[] { getLookupMode(isPush), LookupMode.DEFAULT }) { - // System properties docker.username and docker.password always take precedence - ret = getAuthConfigFromSystemProperties(lookupMode); - if (ret != null) { - log.debug("AuthConfig: credentials from system properties"); - return ret; - } - - // Check for openshift authentication either from the plugin config or from system props - ret = getAuthConfigFromOpenShiftConfig(lookupMode, authConfigMap); - if (ret != null) { - log.debug("AuthConfig: OpenShift credentials"); - return ret; - } - - // Get configuration from global plugin config - ret = getAuthConfigFromPluginConfiguration(lookupMode, authConfigMap); - if (ret != null) { - log.debug("AuthConfig: credentials from plugin config"); - return ret; - } - } - - // =================================================================== - // These are lookups based on registry only, so the direction (push or pull) doesn't matter: - - // Now lets lookup the registry & user from ~/.m2/setting.xml - ret = getAuthConfigFromSettings(settings, user, registry); - if (ret != null) { - log.debug("AuthConfig: credentials from ~/.m2/setting.xml"); - return ret; - } - - // No authentication found - return null; - } - - // =================================================================================================== - - private AuthConfig getAuthConfigFromSystemProperties(LookupMode lookupMode) throws MojoExecutionException { - Properties props = System.getProperties(); - String userKey = lookupMode.asSysProperty(AUTH_USERNAME); - String passwordKey = lookupMode.asSysProperty(AUTH_PASSWORD); - if (props.containsKey(userKey)) { - if (!props.containsKey(passwordKey)) { - throw new MojoExecutionException("No " + passwordKey + " provided for username " + props.getProperty(userKey)); - } - return new AuthConfig(props.getProperty(userKey), - decrypt(props.getProperty(passwordKey)), - props.getProperty(lookupMode.asSysProperty(AUTH_EMAIL)), - props.getProperty(lookupMode.asSysProperty(AUTH_AUTHTOKEN))); - } else { - return null; - } - } - - private AuthConfig getAuthConfigFromOpenShiftConfig(LookupMode lookupMode, Map authConfigMap) throws MojoExecutionException { - Properties props = System.getProperties(); - String useOpenAuthModeProp = lookupMode.asSysProperty(AUTH_USE_OPENSHIFT_AUTH); - // Check for system property - if (props.containsKey(useOpenAuthModeProp)) { - boolean useOpenShift = Boolean.valueOf(props.getProperty(useOpenAuthModeProp)); - if (useOpenShift) { - return validateMandatoryOpenShiftLogin(parseOpenShiftConfig(), useOpenAuthModeProp); - } else { - return null; - } - } - - // Check plugin config - Map mapToCheck = getAuthConfigMapToCheck(lookupMode,authConfigMap); - if (mapToCheck != null && mapToCheck.containsKey(AUTH_USE_OPENSHIFT_AUTH) && - Boolean.valueOf((String) mapToCheck.get(AUTH_USE_OPENSHIFT_AUTH))) { - return validateMandatoryOpenShiftLogin(parseOpenShiftConfig(), useOpenAuthModeProp); - } else { - return null; - } - } - - private AuthConfig getAuthConfigFromPluginConfiguration(LookupMode lookupMode, Map authConfig) throws MojoExecutionException { - Map mapToCheck = getAuthConfigMapToCheck(lookupMode,authConfig); - - if (mapToCheck != null && mapToCheck.containsKey(AUTH_USERNAME)) { - if (!mapToCheck.containsKey(AUTH_PASSWORD)) { - throw new MojoExecutionException("No 'password' given while using in configuration for mode " + lookupMode); - } - Map cloneConfig = new HashMap<>(mapToCheck); - cloneConfig.put(AUTH_PASSWORD, decrypt(cloneConfig.get(AUTH_PASSWORD))); - return new AuthConfig(cloneConfig); - } else { - return null; - } - } - - private AuthConfig getAuthConfigFromSettings(Settings settings, String user, String registry) throws MojoExecutionException { - Server defaultServer = null; - Server found; - for (Server server : settings.getServers()) { - String id = server.getId(); - - // Remember a default server without user as fallback for later - if (defaultServer == null) { - defaultServer = checkForServer(server, id, registry, null); - } - // Check for specific server with user part - found = checkForServer(server, id, registry, user); - if (found != null) { - return createAuthConfigFromServer(found); - } - } - return defaultServer != null ? createAuthConfigFromServer(defaultServer) : null; - } - - private AuthConfig getAuthConfigFromDockerConfig(String registry) throws MojoExecutionException { - JsonObject dockerConfig = readDockerConfig(); - if (dockerConfig == null) { - return null; - } - String registryToLookup = registry != null ? registry : DOCKER_LOGIN_DEFAULT_REGISTRY; - - if (dockerConfig.has("credHelpers") || dockerConfig.has("credsStore")) { - if (dockerConfig.has("credHelpers")) { - final JsonObject credHelpers = dockerConfig.getAsJsonObject("credHelpers"); - if (credHelpers.has(registryToLookup)) { - return extractAuthConfigFromCredentialsHelper(registryToLookup, credHelpers.get(registryToLookup).getAsString()); - } - } - if (dockerConfig.has("credsStore")) { - return extractAuthConfigFromCredentialsHelper(registryToLookup, dockerConfig.get("credsStore").getAsString()); - } - } - - if (dockerConfig.has("auths")) { - return extractAuthConfigFromAuths(registryToLookup, dockerConfig.getAsJsonObject("auths")); - } - - return null; - } - - private AuthConfig extractAuthConfigFromAuths(String registryToLookup, JsonObject auths) { - JsonObject credentials = getCredentialsNode(auths,registryToLookup); - if (credentials == null || !credentials.has("auth")) { - return null; - } - String auth = credentials.get("auth").getAsString(); - String email = credentials.has(AUTH_EMAIL) ? credentials.get(AUTH_EMAIL).getAsString() : null; - return new AuthConfig(auth,email); - } - - private AuthConfig extractAuthConfigFromCredentialsHelper(String registryToLookup, String credConfig) throws MojoExecutionException { - CredentialHelperClient credentialHelper = new CredentialHelperClient(log, credConfig); - log.debug("AuthConfig: credentials from credential helper/store %s version %s", - credentialHelper.getName(), - credentialHelper.getVersion()); - return credentialHelper.getAuthConfig(registryToLookup); - } - - private JsonObject getCredentialsNode(JsonObject auths,String registryToLookup) { - if (auths.has(registryToLookup)) { - return auths.getAsJsonObject(registryToLookup); - } - String registryWithScheme = EnvUtil.ensureRegistryHttpUrl(registryToLookup); - if (auths.has(registryWithScheme)) { - return auths.getAsJsonObject(registryWithScheme); - } - return null; - } - - // ======================================================================================================= - - private Map getAuthConfigMapToCheck(LookupMode lookupMode, Map authConfigMap) { - String configMapKey = lookupMode.getConfigMapKey(); - if (configMapKey == null) { - return authConfigMap; - } - if (authConfigMap != null) { - return (Map) authConfigMap.get(configMapKey); - } - return null; - } - - // Parse OpenShift config to get credentials, but return null if not found - private AuthConfig parseOpenShiftConfig() { - Map kubeConfig = readKubeConfig(); - if (kubeConfig == null) { - return null; - } - - String currentContextName = (String) kubeConfig.get("current-context"); - if (currentContextName == null) { - return null; - } - - for (Map contextMap : (List) kubeConfig.get("contexts")) { - if (currentContextName.equals(contextMap.get("name"))) { - return parseContext(kubeConfig, (Map) contextMap.get("context")); - } - } - - return null; - } - - private AuthConfig parseContext(Map kubeConfig, Map context) { - if (context == null) { - return null; - } - String userName = (String) context.get("user"); - if (userName == null) { - return null; - } - - List users = (List) kubeConfig.get("users"); - if (users == null) { - return null; - } - - for (Map userMap : users) { - if (userName.equals(userMap.get("name"))) { - return parseUser(userName, (Map) userMap.get("user")); - } - } - return null; - } - - private AuthConfig parseUser(String userName, Map user) { - if (user == null) { - return null; - } - String token = (String) user.get("token"); - if (token == null) { - return null; - } - - // Strip off stuff after username - Matcher matcher = Pattern.compile("^([^/]+).*$").matcher(userName); - return new AuthConfig(matcher.matches() ? matcher.group(1) : userName, - token, null, null); - } - - private AuthConfig validateMandatoryOpenShiftLogin(AuthConfig openShiftAuthConfig, String useOpenAuthModeProp) throws MojoExecutionException { - if (openShiftAuthConfig != null) { - return openShiftAuthConfig; - } - // No login found - String kubeConfigEnv = System.getenv("KUBECONFIG"); - throw new MojoExecutionException( - String.format("System property %s set, but not active user and/or token found in %s. " + - "Please use 'oc login' for connecting to OpenShift.", - useOpenAuthModeProp, kubeConfigEnv != null ? kubeConfigEnv : "~/.kube/config")); - - } - - private JsonObject readDockerConfig() { - String dockerConfig = System.getenv("DOCKER_CONFIG"); - - Reader reader = dockerConfig == null - ? getFileReaderFromDir(new File(getHomeDir(),".docker/config.json")) - : getFileReaderFromDir(new File(dockerConfig,"config.json")); - return reader != null ? gson.fromJson(reader, JsonObject.class) : null; - } - - private Map readKubeConfig() { - String kubeConfig = System.getenv("KUBECONFIG"); - - Reader reader = kubeConfig == null - ? getFileReaderFromDir(new File(getHomeDir(),".kube/config")) - : getFileReaderFromDir(new File(kubeConfig)); - if (reader != null) { - Yaml ret = new Yaml(); - return (Map) ret.load(reader); - } - return null; - } - - private Reader getFileReaderFromDir(File file) { - if (file.exists() && file.length() != 0) { - try { - return new FileReader(file); - } catch (FileNotFoundException e) { - // Shouldnt happen. Nevertheless ... - throw new IllegalStateException("Cannot find " + file,e); - } - } else { - return null; - } - } - - private File getHomeDir() { - String homeDir = System.getProperty("user.home"); - if (homeDir == null) { - homeDir = System.getenv("HOME"); - } - return new File(homeDir); - } - - - private Server checkForServer(Server server, String id, String registry, String user) { - - String[] registries = registry != null ? new String[] { registry } : DEFAULT_REGISTRIES; - for (String reg : registries) { - if (id.equals(user == null ? reg : reg + "/" + user)) { - return server; - } - } - return null; - } - - private String decrypt(String password) throws MojoExecutionException { - try { - // Done by reflection since I have classloader issues otherwise - Object secDispatcher = container.lookup(SecDispatcher.ROLE, "maven"); - Method method = secDispatcher.getClass().getMethod("decrypt",String.class); - return (String) method.invoke(secDispatcher,password); - } catch (ComponentLookupException e) { - throw new MojoExecutionException("Error looking security dispatcher",e); - } catch (ReflectiveOperationException e) { - throw new MojoExecutionException("Cannot decrypt password: " + e.getCause(),e); - } - } - - private AuthConfig createAuthConfigFromServer(Server server) throws MojoExecutionException { - return new AuthConfig( - server.getUsername(), - decrypt(server.getPassword()), - extractFromServerConfiguration(server.getConfiguration(), AUTH_EMAIL), - extractFromServerConfiguration(server.getConfiguration(), "auth") - ); - } - - private String extractFromServerConfiguration(Object configuration, String prop) { - if (configuration != null) { - Xpp3Dom dom = (Xpp3Dom) configuration; - Xpp3Dom element = dom.getChild(prop); - if (element != null) { - return element.getValue(); - } - } - return null; - } - - // ======================================================================================== - // Mode which direction to lookup (pull, push or default value for both, pull and push) - - private LookupMode getLookupMode(boolean isPush) { - return isPush ? LookupMode.PUSH : LookupMode.PULL; - } - - private enum LookupMode { - PUSH("docker.push.","push"), - PULL("docker.pull.","pull"), - DEFAULT("docker.",null); - - private final String sysPropPrefix; - private String configMapKey; - - LookupMode(String sysPropPrefix,String configMapKey) { - this.sysPropPrefix = sysPropPrefix; - this.configMapKey = configMapKey; - } - - public String asSysProperty(String prop) { - return sysPropPrefix + prop; - } - - public String getConfigMapKey() { - return configMapKey; - } - } - -} diff --git a/src/main/java/io/fabric8/maven/docker/config/ConfigHelper.java b/src/main/java/io/fabric8/maven/docker/util/ConfigHelper.java similarity index 93% rename from src/main/java/io/fabric8/maven/docker/config/ConfigHelper.java rename to src/main/java/io/fabric8/maven/docker/util/ConfigHelper.java index a0588b3fc..96a9c9191 100644 --- a/src/main/java/io/fabric8/maven/docker/config/ConfigHelper.java +++ b/src/main/java/io/fabric8/maven/docker/util/ConfigHelper.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.util; /* * * Copyright 2016 Roland Huss @@ -16,12 +16,16 @@ * limitations under the License. */ -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import io.fabric8.maven.docker.config.ImageConfiguration; import io.fabric8.maven.docker.config.handler.property.PropertyConfigHandler; import io.fabric8.maven.docker.config.handler.property.PropertyMode; -import io.fabric8.maven.docker.util.EnvUtil; -import io.fabric8.maven.docker.util.Logger; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; import org.apache.maven.shared.utils.StringUtils; @@ -118,11 +122,12 @@ public static String getExternalConfigActivationProperty(MavenProject project) { * @param log a logger for printing out diagnostic messages * @return the minimal API Docker API required to be used for the given configuration. */ - public static String initAndValidate(List images, String apiVersion, NameFormatter nameFormatter, + public static String initAndValidate(List images, String apiVersion, ImageConfiguration.NameFormatter nameFormatter, Logger log) { // Init and validate configs. After this step, getResolvedImages() contains the valid configuration. for (ImageConfiguration imageConfiguration : images) { - apiVersion = EnvUtil.extractLargerVersion(apiVersion, imageConfiguration.initAndValidate(nameFormatter, log)); + for (String version : imageConfiguration.validate(nameFormatter)) + apiVersion = EnvUtil.extractLargerVersion(apiVersion, version); } return apiVersion; } @@ -193,18 +198,5 @@ public interface Resolver { List resolve(ImageConfiguration image); } - /** - * Format an image name by replacing certain placeholders - */ - public interface NameFormatter { - String format(String name); - - NameFormatter IDENTITY = new NameFormatter() { - public String format(String name) { - return name; - } - }; - } - } diff --git a/src/main/java/io/fabric8/maven/docker/util/ContainerNamingUtil.java b/src/main/java/io/fabric8/maven/docker/util/ContainerNamingUtil.java index d8e0c90c0..47428b1ef 100644 --- a/src/main/java/io/fabric8/maven/docker/util/ContainerNamingUtil.java +++ b/src/main/java/io/fabric8/maven/docker/util/ContainerNamingUtil.java @@ -11,7 +11,8 @@ import com.google.common.collect.ImmutableSet; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.RunImageConfiguration; +import io.fabric8.maven.docker.config.ImageName; +import io.fabric8.maven.docker.config.run.RunConfiguration; import io.fabric8.maven.docker.model.Container; /** @@ -140,12 +141,12 @@ private static Set extractContainerNames(final Collection exi } private static String extractContainerNamePattern(ImageConfiguration image, String defaultContainerNamePattern) { - RunImageConfiguration runConfig = image.getRunConfiguration(); + RunConfiguration runConfig = image.getRunConfiguration(); if (runConfig != null) { if (runConfig.getContainerNamePattern() != null) { return runConfig.getContainerNamePattern(); } - if (runConfig.getNamingStrategy() == RunImageConfiguration.NamingStrategy.alias) { + if (runConfig.getNamingStrategy() == RunConfiguration.NamingStrategy.alias) { return "%a"; } } diff --git a/src/main/java/io/fabric8/maven/docker/util/DeepCopy.java b/src/main/java/io/fabric8/maven/docker/util/DeepCopy.java deleted file mode 100644 index e94ae700c..000000000 --- a/src/main/java/io/fabric8/maven/docker/util/DeepCopy.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.fabric8.maven.docker.util; -/* - * - * Copyright 2016 Roland Huss - * - * 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. - */ - -import java.io.*; - -public class DeepCopy { - - /** - * Returns a copy of the object, or null if the object cannot - * be serialized. - */ - public static T copy(T orig) { - if (orig == null) { - return null; - } - try { - // Write the object out to a byte array - ByteArrayOutputStream fbos = new ByteArrayOutputStream(); - - try (ObjectOutputStream out = new ObjectOutputStream(fbos)) { - out.writeObject(orig); - out.flush(); - } - - // Retrieve an input stream from the byte array and read - // a copy of the object back in. - try (ByteArrayInputStream fbis = new ByteArrayInputStream(fbos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(fbis)) { - return (T) in.readObject(); - } - } catch (IOException | ClassNotFoundException e) { - throw new IllegalStateException("Cannot copy " + orig, e); - } - }; -} diff --git a/src/main/java/io/fabric8/maven/docker/util/DockerFileUtil.java b/src/main/java/io/fabric8/maven/docker/util/DockerFileUtil.java index 384abf6a1..26796fc52 100644 --- a/src/main/java/io/fabric8/maven/docker/util/DockerFileUtil.java +++ b/src/main/java/io/fabric8/maven/docker/util/DockerFileUtil.java @@ -18,14 +18,16 @@ import java.io.*; import java.util.ArrayList; import java.util.List; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; import org.apache.maven.plugins.assembly.interpolation.AssemblyInterpolator; import org.apache.maven.plugins.assembly.io.DefaultAssemblyReader; import org.codehaus.plexus.interpolation.fixed.FixedStringSearchInterpolator; -import io.fabric8.maven.docker.assembly.DockerAssemblyConfigurationSource; +import io.fabric8.maven.docker.build.maven.assembly.DockerAssemblyConfigurationSource; /** @@ -42,9 +44,8 @@ private DockerFileUtil() {} * taken. * * @param dockerFile file from where to extract the base image - * @param interpolator interpolator for replacing properties */ - public static String extractBaseImage(File dockerFile, FixedStringSearchInterpolator interpolator) throws IOException { + public static String extractBaseImage(File dockerFile, Function interpolator) throws IOException { List fromLines = extractLines(dockerFile, "FROM", interpolator); if (!fromLines.isEmpty()) { String[] parts = fromLines.get(0); @@ -60,15 +61,14 @@ public static String extractBaseImage(File dockerFile, FixedStringSearchInterpol * * @param dockerFile dockerfile to examine * @param keyword keyword to extract the lines for - * @param interpolator interpolator for replacing properties * @return list of matched lines or an empty list */ - public static List extractLines(File dockerFile, String keyword, FixedStringSearchInterpolator interpolator) throws IOException { + public static List extractLines(File dockerFile, String keyword, Function interpolator) throws IOException { List ret = new ArrayList<>(); try (BufferedReader reader = new BufferedReader(new FileReader(dockerFile))) { String line; while ((line = reader.readLine()) != null) { - String lineInterpolated = interpolator.interpolate(line); + String lineInterpolated = interpolator.apply(line); String[] lineParts = lineInterpolated.split("\\s+"); if (lineParts.length > 0 && lineParts[0].equalsIgnoreCase(keyword)) { ret.add(lineParts); @@ -100,29 +100,32 @@ public static String interpolate(File dockerFile, FixedStringSearchInterpolator /** * Create an interpolator for the given maven parameters and filter configuration. * - * @param params The maven parameters. + * @param ctx The maven parameters. * @param filter The filter configuration. * @return An interpolator for replacing maven properties. */ - public static FixedStringSearchInterpolator createInterpolator(MojoParameters params, String filter) { + public static FixedStringSearchInterpolator createInterpolator(MavenBuildContext ctx, String filter) { String[] delimiters = extractDelimiters(filter); if (delimiters == null) { // Don't interpolate anything return FixedStringSearchInterpolator.create(); } - DockerAssemblyConfigurationSource configSource = new DockerAssemblyConfigurationSource(params, null, null); + DockerAssemblyConfigurationSource configSource = new DockerAssemblyConfigurationSource(ctx, null, null); // Patterned after org.apache.maven.plugins.assembly.interpolation.AssemblyExpressionEvaluator return AssemblyInterpolator - .fullInterpolator(params.getProject(), - DefaultAssemblyReader.createProjectInterpolator(params.getProject()) + .fullInterpolator(ctx.getProject(), + DefaultAssemblyReader.createProjectInterpolator(ctx.getProject()) .withExpressionMarkers(delimiters[0], delimiters[1]), configSource) .withExpressionMarkers(delimiters[0], delimiters[1]); } private static String[] extractDelimiters(String filter) { - if (filter == null || - filter.equalsIgnoreCase("false") || + if (filter == null) { + // Default interpolation scheme + return new String[] { "${", "}" }; + } + if (filter.equalsIgnoreCase("false") || filter.equalsIgnoreCase("none")) { return null; } diff --git a/src/main/java/io/fabric8/maven/docker/util/EnvUtil.java b/src/main/java/io/fabric8/maven/docker/util/EnvUtil.java index f491e2a40..544437f47 100644 --- a/src/main/java/io/fabric8/maven/docker/util/EnvUtil.java +++ b/src/main/java/io/fabric8/maven/docker/util/EnvUtil.java @@ -3,22 +3,29 @@ import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; -import com.google.common.base.*; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; +import io.fabric8.maven.docker.build.BuildContext; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.apache.maven.shared.utils.io.FileUtils; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static java.util.concurrent.TimeUnit.*; +import static java.util.concurrent.TimeUnit.HOURS; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; /** * Utility class for various (loosely related) environment related tasks. @@ -86,16 +93,13 @@ public static boolean greaterOrEqualsVersion(String versionA, String versionB) { return largerVersion != null && largerVersion.equals(versionA); } - private static final Function SPLIT_ON_LAST_COLON = new Function() { - @Override - public String[] apply(String element) { - int colon = element.lastIndexOf(':'); - if (colon < 0) { - return new String[] {element, element}; - } else { - return new String[] {element.substring(0, colon), element.substring(colon + 1)}; - } - } + private static final Function SPLIT_ON_LAST_COLON = element -> { + int colon = element.lastIndexOf(':'); + if (colon < 0) { + return new String[] {element, element}; + } else { + return new String[] {element.substring(0, colon), element.substring(colon + 1)}; + } }; /** @@ -107,64 +111,13 @@ public String[] apply(String element) { * @return return list of 2-element arrays or an empty list if the given list is empty or null */ public static List splitOnLastColon(List listToSplit) { - if (listToSplit != null) { - return Lists.transform(listToSplit, SPLIT_ON_LAST_COLON); - } - return Collections.emptyList(); - } - - private static final Function> COMMA_SPLITTER = new Function>() { - private Splitter COMMA_SPLIT = Splitter.on(",").trimResults().omitEmptyStrings(); - - @Override - public Iterable apply(String input) { - return COMMA_SPLIT.split(input); - } - }; - - private static final Predicate NOT_EMPTY = new Predicate() { - @Override - public boolean apply(@Nullable String s) { - return s!=null && !s.isEmpty(); - } - }; - - private static final Function TRIM = new Function() { - @Nullable - @Override - public String apply(@Nullable String s) { - return s!=null ?s.trim() :s; - } - }; - - /** - * Remove empty members of a list. - * @param input A list of String - * @return A list of Non-Empty (length>0) String - */ - @Nonnull - public static List removeEmptyEntries(@Nullable List input) { - if(input==null) { + if (listToSplit == null) { return Collections.emptyList(); } - Iterable trimmedInputs = Iterables.transform(input, TRIM); - Iterable nonEmptyInputs = Iterables.filter(trimmedInputs, NOT_EMPTY); - return Lists.newArrayList(nonEmptyInputs); + return listToSplit.stream().map(SPLIT_ON_LAST_COLON).collect(Collectors.toList()); } - /** - * Split each element of an Iterable at commas. - * @param input Iterable over strings. - * @return An Iterable over string which breaks down each input element at comma boundaries - */ - @Nonnull - public static List splitAtCommasAndTrim(Iterable input) { - if(input==null) { - return Collections.emptyList(); - } - Iterable nonEmptyInputs = Iterables.filter(input, Predicates.notNull()); - return Lists.newArrayList(Iterables.concat(Iterables.transform(nonEmptyInputs, COMMA_SPLITTER))); - } + public static String[] splitOnSpaceWithEscape(String toSplit) { String[] split = toSplit.split("(?:\"/\\\\|?*\\x00-\\x1F]* # Zero or more valid filename chars.\n" + - "[^<>:\"/\\\\|?*\\x00-\\x1F .] # Last char is not a space or dot. \n" + - "$ # Anchor to end of string. ", - Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS); - Matcher matcher = pattern.matcher(filename); - return matcher.matches(); - } - } diff --git a/src/main/java/io/fabric8/maven/docker/util/ImageNameFormatter.java b/src/main/java/io/fabric8/maven/docker/util/ImageNameFormatter.java index 5dbd11ea2..6336447d9 100644 --- a/src/main/java/io/fabric8/maven/docker/util/ImageNameFormatter.java +++ b/src/main/java/io/fabric8/maven/docker/util/ImageNameFormatter.java @@ -22,7 +22,7 @@ import java.util.Map; import com.google.common.base.Strings; -import io.fabric8.maven.docker.config.ConfigHelper; +import io.fabric8.maven.docker.config.ImageConfiguration; import org.apache.maven.project.MavenProject; /** @@ -32,7 +32,7 @@ * @author roland * @since 07/06/16 */ -public class ImageNameFormatter implements ConfigHelper.NameFormatter { +public class ImageNameFormatter implements ImageConfiguration.NameFormatter { private final FormatParameterReplacer formatParamReplacer; diff --git a/src/main/java/io/fabric8/maven/docker/util/MojoParameters.java b/src/main/java/io/fabric8/maven/docker/util/MojoParameters.java deleted file mode 100644 index 51bf6cc2d..000000000 --- a/src/main/java/io/fabric8/maven/docker/util/MojoParameters.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.fabric8.maven.docker.util; - -import java.util.List; - -import org.apache.maven.archiver.MavenArchiveConfiguration; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.project.MavenProject; -import org.apache.maven.settings.Settings; -import org.apache.maven.shared.filtering.MavenFileFilter; -import org.apache.maven.shared.filtering.MavenReaderFilter; - -/** - * Helper class for encapsulating Mojo params which are not Plexus components - * - * @author roland - * @since 09.05.14 - */ -public class MojoParameters { - private final MavenArchiveConfiguration archive; - private final MavenSession session; - private final MavenFileFilter mavenFileFilter; - private final MavenReaderFilter mavenFilterReader; - private final MavenProject project; - private final Settings settings; - - private final String outputDirectory; - private final String sourceDirectory; - - private final List reactorProjects; - - public MojoParameters(MavenSession session, MavenProject project, MavenArchiveConfiguration archive, MavenFileFilter mavenFileFilter, - MavenReaderFilter mavenFilterReader, Settings settings, String sourceDirectory, String outputDirectory, List reactorProjects) { - this.archive = archive; - this.session = session; - this.mavenFileFilter = mavenFileFilter; - this.mavenFilterReader = mavenFilterReader; - this.project = project; - this.settings = settings; - - this.sourceDirectory = sourceDirectory; - this.outputDirectory = outputDirectory; - - this.reactorProjects = reactorProjects; - } - - public MavenArchiveConfiguration getArchiveConfiguration() { - return archive; - } - - public String getSourceDirectory() { - return sourceDirectory; - } - - public String getOutputDirectory() { - return outputDirectory; - } - - public MavenSession getSession() { - return session; - } - - public MavenFileFilter getMavenFileFilter() { - return mavenFileFilter; - } - - public MavenReaderFilter getMavenFilterReader() { - return mavenFilterReader; - } - - public MavenProject getProject() { - return project; - } - - public Settings getSettings() { - return settings; - } - - public List getReactorProjects() { - return reactorProjects; - } -} diff --git a/src/main/java/io/fabric8/maven/docker/util/StartOrderResolver.java b/src/main/java/io/fabric8/maven/docker/util/StartOrderResolver.java index 1adee1bbc..ec76404fd 100644 --- a/src/main/java/io/fabric8/maven/docker/util/StartOrderResolver.java +++ b/src/main/java/io/fabric8/maven/docker/util/StartOrderResolver.java @@ -3,6 +3,10 @@ import java.util.*; import io.fabric8.maven.docker.access.DockerAccessException; +import io.fabric8.maven.docker.config.ImageConfiguration; +import io.fabric8.maven.docker.config.run.NetworkConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import io.fabric8.maven.docker.config.run.RunVolumeConfiguration; import io.fabric8.maven.docker.service.QueryService; import org.codehaus.plexus.util.StringUtils; @@ -16,14 +20,11 @@ public class StartOrderResolver { private final QueryService queryService; - private final List secondPass; + private final List secondPass; private final Set processedImages; - public static List resolve(QueryService queryService, List convertToResolvables) { - return new StartOrderResolver(queryService).resolve(convertToResolvables); - } - private StartOrderResolver(QueryService queryService) { + public StartOrderResolver(QueryService queryService) { this.queryService = queryService; this.secondPass = new ArrayList<>(); @@ -35,10 +36,10 @@ private StartOrderResolver(QueryService queryService) { // Only return images which should be run // Images references via volumes but with no run configuration are started once to create // an appropriate container which can be linked into the image - private List resolve(List images) { - List resolved = new ArrayList<>(); + public List resolve(List images) { + List resolved = new ArrayList<>(); // First pass: Pick all data images and all without dependencies - for (Resolvable config : images) { + for (ImageConfiguration config : images) { List volumesOrLinks = extractDependentImagesFor(config); if (volumesOrLinks == null) { // A data image only or no dependency. Add it to the list of data image which can be always @@ -54,7 +55,21 @@ private List resolve(List images) { return secondPass.size() > 0 ? resolveRemaining(resolved) : resolved; } - private List resolveRemaining(List ret) { + public static List getDependencies(ImageConfiguration image) { + RunConfiguration runConfig = image.getRunConfiguration(); + List ret = new ArrayList<>(); + if (runConfig != null) { + addVolumes(runConfig, ret); + addLinks(runConfig, ret); + addContainerNetwork(runConfig, ret); + addDependsOn(runConfig, ret); + } + return ret; + } + + // ====================================================================================================== + + private List resolveRemaining(List ret) { int retries = MAX_RESOLVE_RETRIES; String error = null; try { @@ -74,7 +89,7 @@ private List resolveRemaining(List ret) { return ret; } - private void updateProcessedImages(Resolvable config) { + private void updateProcessedImages(ImageConfiguration config) { processedImages.add(config.getName()); if (config.getAlias() != null) { processedImages.add(config.getAlias()); @@ -84,22 +99,22 @@ private void updateProcessedImages(Resolvable config) { private String remainingImagesDescription() { StringBuffer ret = new StringBuffer(); ret.append("Unresolved images:\n"); - for (Resolvable config : secondPass) { + for (ImageConfiguration config : secondPass) { ret.append("* ") .append(config.getAlias()) .append(" depends on ") - .append(StringUtils.join(config.getDependencies().toArray(), ",")) + .append(StringUtils.join(getDependencies(config).toArray(), ",")) .append("\n"); } return ret.toString(); } - private void resolveImageDependencies(List resolved) throws DockerAccessException, ResolveSteadyStateException { + private void resolveImageDependencies(List resolved) throws DockerAccessException, ResolveSteadyStateException { boolean changed = false; - Iterator iterator = secondPass.iterator(); + Iterator iterator = secondPass.iterator(); while (iterator.hasNext()) { - Resolvable config = iterator.next(); + ImageConfiguration config = iterator.next(); if (hasRequiredDependencies(config)) { updateProcessedImages(config); resolved.add(config); @@ -113,7 +128,7 @@ private void resolveImageDependencies(List resolved) throws DockerAc } } - private boolean hasRequiredDependencies(Resolvable config) throws DockerAccessException { + private boolean hasRequiredDependencies(ImageConfiguration config) throws DockerAccessException { List dependencies = extractDependentImagesFor(config); if (dependencies == null) { return false; @@ -133,19 +148,47 @@ private boolean hasRequiredDependencies(Resolvable config) throws DockerAccessEx return true; } - private List extractDependentImagesFor(Resolvable config) { - LinkedHashSet ret = new LinkedHashSet<>(config.getDependencies()); + private List extractDependentImagesFor(ImageConfiguration config) { + LinkedHashSet ret = new LinkedHashSet<>(getDependencies(config)); return ret.isEmpty() ? null : new ArrayList<>(ret); } // Exception indicating a steady state while resolving start order of images private static class ResolveSteadyStateException extends Throwable { } - public interface Resolvable { - String getName(); - String getAlias(); - List getDependencies(); + private static void addVolumes(RunConfiguration runConfig, List ret) { + RunVolumeConfiguration volConfig = runConfig.getVolumeConfiguration(); + if (volConfig != null) { + List volumeImages = volConfig.getFrom(); + if (volumeImages != null) { + ret.addAll(volumeImages); + } + } + } + + private static void addLinks(RunConfiguration runConfig, List ret) { + // Custom networks can have circular links, no need to be considered for the starting order. + if (!runConfig.getNetworkingConfig().isCustomNetwork() && runConfig.getLinks() != null) { + runConfig.getLinks() + .stream() + .map(s -> !s.contains(":") ? s : s.substring(0, s.lastIndexOf(":"))) + .forEach(ret::add); + } + } + + private static void addContainerNetwork(RunConfiguration runConfig, List ret) { + NetworkConfiguration config = runConfig.getNetworkingConfig(); + String alias = config.getContainerAlias(); + if (alias != null) { + ret.add(alias); + } } + private static void addDependsOn(RunConfiguration runConfig, List ret) { + // Only used in custom networks. + if (runConfig.getNetworkingConfig().isCustomNetwork()) { + ret.addAll(runConfig.getDependsOn()); + } + } } diff --git a/src/main/java/io/fabric8/maven/docker/util/VolumeBindingUtil.java b/src/main/java/io/fabric8/maven/docker/util/VolumeBindingUtil.java index a8e93aa19..b54bd13bb 100644 --- a/src/main/java/io/fabric8/maven/docker/util/VolumeBindingUtil.java +++ b/src/main/java/io/fabric8/maven/docker/util/VolumeBindingUtil.java @@ -1,12 +1,12 @@ package io.fabric8.maven.docker.util; -import io.fabric8.maven.docker.config.RunVolumeConfiguration; - import java.io.File; import java.io.IOException; import java.util.List; import java.util.regex.Pattern; +import io.fabric8.maven.docker.config.run.RunVolumeConfiguration; + import static io.fabric8.maven.docker.util.DockerPathUtil.resolveAbsolutely; /** diff --git a/src/main/java/io/fabric8/maven/docker/wait/HttpPingChecker.java b/src/main/java/io/fabric8/maven/docker/wait/HttpPingChecker.java index 401078af0..37445ee25 100644 --- a/src/main/java/io/fabric8/maven/docker/wait/HttpPingChecker.java +++ b/src/main/java/io/fabric8/maven/docker/wait/HttpPingChecker.java @@ -7,7 +7,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import io.fabric8.maven.docker.config.WaitConfiguration; +import io.fabric8.maven.docker.config.run.WaitConfiguration; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.RequestBuilder; diff --git a/src/test/java/integration/DockerAccessIT.java b/src/test/java/integration/DockerAccessIT.java index e70aeeb67..bdc1366e4 100644 --- a/src/test/java/integration/DockerAccessIT.java +++ b/src/test/java/integration/DockerAccessIT.java @@ -14,7 +14,7 @@ import io.fabric8.maven.docker.access.DockerMachine; import io.fabric8.maven.docker.access.PortMapping; import io.fabric8.maven.docker.access.hc.DockerAccessWithHcClient; -import io.fabric8.maven.docker.config.Arguments; +import io.fabric8.maven.docker.config.build.Arguments; import io.fabric8.maven.docker.config.DockerMachineConfiguration; import io.fabric8.maven.docker.model.Container.PortBinding; import io.fabric8.maven.docker.util.AnsiLogger; @@ -160,7 +160,7 @@ private void testStartContainer() throws DockerAccessException { private void testExecContainer() throws DockerAccessException { Arguments arguments = new Arguments(); arguments.setExec(Lists.newArrayList("echo", "test", "echo")); - String execContainerId = dockerClient.createExecContainer(this.containerId, arguments); + String execContainerId = dockerClient.createExecContainer(this.containerId, arguments.getExec()); //assertThat(dockerClient.startExecContainer(execContainerId), is("test echo")); } diff --git a/src/test/java/integration/DockerAccessWinIT.java b/src/test/java/integration/DockerAccessWinIT.java index 663ba7f8f..27e48f780 100644 --- a/src/test/java/integration/DockerAccessWinIT.java +++ b/src/test/java/integration/DockerAccessWinIT.java @@ -14,7 +14,7 @@ import io.fabric8.maven.docker.access.DockerMachine; import io.fabric8.maven.docker.access.PortMapping; import io.fabric8.maven.docker.access.hc.DockerAccessWithHcClient; -import io.fabric8.maven.docker.config.Arguments; +import io.fabric8.maven.docker.config.build.Arguments; import io.fabric8.maven.docker.model.Container.PortBinding; import io.fabric8.maven.docker.util.AnsiLogger; import io.fabric8.maven.docker.util.Logger; @@ -148,7 +148,7 @@ private void testStartContainer() throws DockerAccessException { private void testExecContainer() throws DockerAccessException { Arguments arguments = new Arguments(); arguments.setExec(Lists.newArrayList("echo", "test", "echo")); - String execContainerId = dockerClient.createExecContainer(this.containerId, arguments); + String execContainerId = dockerClient.createExecContainer(this.containerId, arguments.getExec()); //assertThat(dockerClient.startExecContainer(execContainerId), is("test echo")); } diff --git a/src/test/java/io/fabric8/maven/docker/UrlBuilderTest.java b/src/test/java/io/fabric8/maven/docker/UrlBuilderTest.java index 728e8a10e..073e6035e 100644 --- a/src/test/java/io/fabric8/maven/docker/UrlBuilderTest.java +++ b/src/test/java/io/fabric8/maven/docker/UrlBuilderTest.java @@ -22,7 +22,7 @@ import io.fabric8.maven.docker.access.BuildOptions; import io.fabric8.maven.docker.access.UrlBuilder; -import io.fabric8.maven.docker.util.ImageName; +import io.fabric8.maven.docker.config.ImageName; import org.junit.Test; import static org.junit.Assert.*; @@ -120,7 +120,7 @@ public void pullImage() throws URISyntaxException { public void tagContainer() throws URISyntaxException { UrlBuilder builder = new UrlBuilder("", "1.0"); assertEquals(new URI("/1.0/images/t1%3Alatest/tag?force=1&repo=new&tag=tag1"), - new URI(builder.tagContainer(new ImageName("t1:latest"), new ImageName("new:tag1"), true))); + new URI(builder.tagImage(new ImageName("t1:latest"), new ImageName("new:tag1"), true))); } } diff --git a/src/test/java/io/fabric8/maven/docker/access/ContainerHostConfigTest.java b/src/test/java/io/fabric8/maven/docker/access/ContainerHostConfigTest.java index 4514626e3..7fd39141a 100644 --- a/src/test/java/io/fabric8/maven/docker/access/ContainerHostConfigTest.java +++ b/src/test/java/io/fabric8/maven/docker/access/ContainerHostConfigTest.java @@ -12,8 +12,8 @@ import java.util.HashMap; import java.util.Map; -import io.fabric8.maven.docker.config.LogConfiguration; -import io.fabric8.maven.docker.config.UlimitConfig; +import io.fabric8.maven.docker.config.run.LogConfiguration; +import io.fabric8.maven.docker.config.run.UlimitConfiguration; import io.fabric8.maven.docker.util.JsonFactory; import static org.junit.Assert.assertEquals; @@ -57,8 +57,8 @@ public void testUlimits() throws JSONException { ContainerHostConfig hc = new ContainerHostConfig(); hc.ulimits(Collections.singletonList( data[1].toString().contains("=") ? - new UlimitConfig((String) data[1]) : - new UlimitConfig((String) data[1], (Integer) data[2], (Integer) data[3]))); + new UlimitConfiguration((String) data[1]) : + new UlimitConfiguration((String) data[1], (Integer) data[2], (Integer) data[3]))); assertEquals(JsonFactory.newJsonObject((String) data[0]), hc.toJsonObject()); } diff --git a/src/test/java/io/fabric8/maven/docker/access/hc/DockerAccessWithHcClientTest.java b/src/test/java/io/fabric8/maven/docker/access/hc/DockerAccessWithHcClientTest.java index 42342b393..9dd81db52 100644 --- a/src/test/java/io/fabric8/maven/docker/access/hc/DockerAccessWithHcClientTest.java +++ b/src/test/java/io/fabric8/maven/docker/access/hc/DockerAccessWithHcClientTest.java @@ -4,9 +4,9 @@ import java.io.IOException; import java.util.Map; -import io.fabric8.maven.docker.access.AuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuth; import io.fabric8.maven.docker.access.hc.util.ClientBuilder; -import io.fabric8.maven.docker.config.ArchiveCompression; +import io.fabric8.maven.docker.config.build.ArchiveCompression; import io.fabric8.maven.docker.util.Logger; import mockit.Expectations; import mockit.Mocked; @@ -21,7 +21,7 @@ public class DockerAccessWithHcClientTest { - private AuthConfig authConfig; + private RegistryAuth registryAuth; private DockerAccessWithHcClient client; @@ -179,7 +179,7 @@ private void thenImageWasPushed() { private void whenPushImage() { try { - client.pushImage(imageName, authConfig, registry, pushRetries); + client.pushImage(imageName, "", registry, pushRetries); } catch (Exception e) { thrownException = e; } @@ -194,7 +194,7 @@ private void whenLoadImage() { private void whenSaveImage() { try { - client.saveImage(imageName, filename, compression); + client.saveImage(imageName, filename); } catch (Exception e) { thrownException = e; } diff --git a/src/test/java/io/fabric8/maven/docker/service/BuildServiceTest.java b/src/test/java/io/fabric8/maven/docker/build/DockerBuildServiceTest.java similarity index 71% rename from src/test/java/io/fabric8/maven/docker/service/BuildServiceTest.java rename to src/test/java/io/fabric8/maven/docker/build/DockerBuildServiceTest.java index 8948a2ad0..11c0f255f 100644 --- a/src/test/java/io/fabric8/maven/docker/service/BuildServiceTest.java +++ b/src/test/java/io/fabric8/maven/docker/build/DockerBuildServiceTest.java @@ -1,34 +1,37 @@ -package io.fabric8.maven.docker.service; +package io.fabric8.maven.docker.build; import java.io.File; +import java.io.IOException; import java.util.Collections; import io.fabric8.maven.docker.access.BuildOptions; import io.fabric8.maven.docker.access.DockerAccess; import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.assembly.DockerAssemblyManager; -import io.fabric8.maven.docker.config.BuildImageConfiguration; +import io.fabric8.maven.docker.build.docker.DockerBuildService; +import io.fabric8.maven.docker.build.docker.DockerRegistryService; +import io.fabric8.maven.docker.build.maven.MavenArchiveService; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; +import io.fabric8.maven.docker.build.maven.assembly.DockerAssemblyManager; +import io.fabric8.maven.docker.config.build.BuildConfiguration; import io.fabric8.maven.docker.config.ImageConfiguration; +import io.fabric8.maven.docker.service.QueryService; import io.fabric8.maven.docker.util.Logger; -import io.fabric8.maven.docker.util.MojoParameters; import mockit.Expectations; import mockit.FullVerifications; import mockit.Injectable; import mockit.Mocked; import mockit.Tested; import mockit.Verifications; -import org.apache.maven.plugin.MojoExecutionException; -import org.junit.Before; import org.junit.Test; -public class BuildServiceTest { +public class DockerBuildServiceTest { private static final String NEW_IMAGE_ID = "efg789efg789"; private static final String OLD_IMAGE_ID = "abc123abc123"; @Tested - private BuildService buildService; + private DockerBuildService buildService; @Injectable private DockerAccess docker; @@ -44,30 +47,23 @@ public class BuildServiceTest { private String oldImageId; @Mocked - private MojoParameters params; + private MavenBuildContext buildContext; @Injectable private QueryService queryService; @Injectable - private ArchiveService archiveService; + private MavenArchiveService archiveService; @Injectable - private RegistryService registryService; + private DockerRegistryService registryService; - @Before - public void setup() throws Exception { - new Expectations() {{ - archiveService.createArchive(anyString, (BuildImageConfiguration) any, (MojoParameters) any, log); - result = new File("docker-build.tar"); - }}; - } @Test public void testBuildImageWithCleanup() throws Exception { givenAnImageConfiguration(true); givenImageIds(OLD_IMAGE_ID, NEW_IMAGE_ID); - whenBuildImage(true,false); + whenBuildImage(true); thenImageIsBuilt(); thenOldImageIsRemoved(); } @@ -76,7 +72,7 @@ public void testBuildImageWithCleanup() throws Exception { public void testBuildImageWithNoCleanup() throws Exception { givenAnImageConfiguration(false); givenImageIds(OLD_IMAGE_ID, NEW_IMAGE_ID); - whenBuildImage(false,false); + whenBuildImage(false); thenImageIsBuilt(); thenOldImageIsNotRemoved(); } @@ -85,7 +81,7 @@ public void testBuildImageWithNoCleanup() throws Exception { public void testCleanupCachedImage() throws Exception { givenAnImageConfiguration(true); givenImageIds(OLD_IMAGE_ID, OLD_IMAGE_ID); - whenBuildImage(false, false); + whenBuildImage(false); thenImageIsBuilt(); thenOldImageIsNotRemoved(); } @@ -94,13 +90,13 @@ public void testCleanupCachedImage() throws Exception { public void testCleanupNoExistingImage() throws Exception { givenAnImageConfiguration(true); givenImageIds(null, NEW_IMAGE_ID); - whenBuildImage(false, false); + whenBuildImage(false); thenImageIsBuilt(); thenOldImageIsNotRemoved(); } private void givenAnImageConfiguration(Boolean cleanup) { - BuildImageConfiguration buildConfig = new BuildImageConfiguration.Builder() + BuildConfiguration buildConfig = new BuildConfiguration.Builder() .cleanup(cleanup.toString()) .build(); @@ -114,7 +110,7 @@ private void givenAnImageConfiguration(Boolean cleanup) { private void givenImageIds(final String oldImageId, final String newImageId) throws DockerAccessException { this.oldImageId = oldImageId; new Expectations() {{ - queryService.getImageId(imageConfig.getName()); result = new String[] { oldImageId, newImageId }; + docker.getImageId(imageConfig.getName()); result = new String[] { oldImageId, newImageId }; }}; } @@ -127,7 +123,7 @@ private void thenImageIsBuilt() throws DockerAccessException { }}; } - private void thenOldImageIsNotRemoved() throws DockerAccessException { + private void thenOldImageIsNotRemoved() { new FullVerifications(docker) {{ }}; @@ -139,9 +135,11 @@ private void thenOldImageIsRemoved() throws DockerAccessException { }}; } - private void whenBuildImage(boolean cleanup, boolean nocache) throws DockerAccessException, MojoExecutionException { + private void whenBuildImage(boolean cleanup) throws IOException { new Expectations() {{ docker.buildImage(withEqual(imageConfig.getName()), (File) any, (BuildOptions) any); + buildContext.createImageContentArchive(withEqual(imageConfig.getName()), (BuildConfiguration) any, withEqual(log)); + result = new File("docker-build.tar"); }}; if (cleanup) { new Expectations() {{ @@ -149,7 +147,7 @@ private void whenBuildImage(boolean cleanup, boolean nocache) throws DockerAcces }}; } - buildService.buildImage(imageConfig, params, nocache, Collections.emptyMap()); + buildService.buildImage(imageConfig, buildContext, Collections.emptyMap()); } } diff --git a/src/test/java/io/fabric8/maven/docker/service/RegistryServiceTest.java b/src/test/java/io/fabric8/maven/docker/build/DockerRegistryServiceTest.java similarity index 77% rename from src/test/java/io/fabric8/maven/docker/service/RegistryServiceTest.java rename to src/test/java/io/fabric8/maven/docker/build/DockerRegistryServiceTest.java index e97218004..31b1b880e 100644 --- a/src/test/java/io/fabric8/maven/docker/service/RegistryServiceTest.java +++ b/src/test/java/io/fabric8/maven/docker/build/DockerRegistryServiceTest.java @@ -1,16 +1,22 @@ -package io.fabric8.maven.docker.service; +package io.fabric8.maven.docker.build; +import java.io.IOException; import java.util.HashMap; import java.util.Map; -import io.fabric8.maven.docker.access.AuthConfig; import io.fabric8.maven.docker.access.DockerAccess; import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.config.ImagePullPolicy; -import io.fabric8.maven.docker.util.AuthConfigFactory; +import io.fabric8.maven.docker.build.auth.RegistryAuth; +import io.fabric8.maven.docker.build.auth.RegistryAuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuthFactory; +import io.fabric8.maven.docker.build.docker.DockerRegistryService; +import io.fabric8.maven.docker.build.docker.ImagePullCache; +import io.fabric8.maven.docker.build.maven.MavenRegistryContext; +import io.fabric8.maven.docker.config.ImageName; +import io.fabric8.maven.docker.config.build.ImagePullPolicy; import io.fabric8.maven.docker.util.AutoPullMode; -import io.fabric8.maven.docker.util.ImageName; import io.fabric8.maven.docker.util.Logger; +import mockit.Expectations; import mockit.Mocked; import mockit.Verifications; import org.junit.Before; @@ -24,15 +30,15 @@ * @author roland * @since 23.11.17 */ -public class RegistryServiceTest { +public class DockerRegistryServiceTest { private Exception actualException; private String imageName; private ImagePullPolicy imagePullPolicy; - private TestCacheStore cacheStore; + private TestBackend cacheStore; private AutoPullMode autoPullMode; - private RegistryService registryService; + private DockerRegistryService registryService; private boolean hasImage; private String registry; private Map authConfig; @@ -44,7 +50,7 @@ public class RegistryServiceTest { private Logger logger; @Mocked - private AuthConfigFactory authConfigFactory; + private RegistryAuthFactory registryAuthFactory; @Before public void setup() { @@ -52,8 +58,8 @@ public void setup() { } private void reset() { - registryService = new RegistryService(docker, logger); - cacheStore = new TestCacheStore(); + cacheStore = new TestBackend(); + registryService = new DockerRegistryService(docker, logger, cacheStore); authConfig = new HashMap(); imageName = null; @@ -87,7 +93,8 @@ public void pullImageAutopullAlways() throws Exception { } } - private void checkPulledButNotTagged() throws DockerAccessException { + private void checkPulledButNotTagged() throws IOException { + givenEmptyAuthConfig(); whenAutoPullImage(); @@ -161,12 +168,13 @@ private void thenExceptionThrown() { } @Test - public void pullWithCustomRegistry() throws DockerAccessException { + public void pullWithCustomRegistry() throws IOException { givenAnImage("myregistry.com/user/test:1.0.1"); givenHasImage(false); givenPreviousPulled(false); givenRegistry("anotherRegistry.com"); givenImagePullPolicy(ImagePullPolicy.IfNotPresent); + givenEmptyAuthConfig(); whenAutoPullImage(); @@ -176,12 +184,13 @@ public void pullWithCustomRegistry() throws DockerAccessException { } @Test - public void tagForCustomRegistry() throws DockerAccessException { + public void tagForCustomRegistry() throws IOException { givenAnImage("user/test:1.0.1"); givenHasImage(false); givenPreviousPulled(false); givenRegistry("anotherRegistry.com"); givenImagePullPolicy(ImagePullPolicy.IfNotPresent); + givenEmptyAuthConfig(); whenAutoPullImage(); @@ -199,7 +208,7 @@ private void thenNoExceptionThrown() { } private void thenImageHasNotBeenPulled() throws DockerAccessException { new Verifications() {{ - docker.pullImage(anyString, (AuthConfig) withNotNull(), anyString); times = 0; + docker.pullImage(anyString, withNotNull(), anyString);times = 0; }}; } @@ -222,32 +231,34 @@ private void thenImageHasBeenPulled() throws DockerAccessException { private void thenImageHasBeenPulledWithRegistry(final String registry) throws DockerAccessException { new Verifications() {{ - docker.pullImage(imageName, (AuthConfig) withNotNull(), registry); + docker.pullImage(imageName, withNotNull(), registry); }}; assertTrue(cacheStore.get(imageName) != null); } private void whenAutoPullImage() { - try { - String iPolicyS = imagePullPolicy != null ? imagePullPolicy.toString() : null; - String autoPullModeS = autoPullMode != null ? autoPullMode.toString() : null; - ImagePullManager pullManager = new ImagePullManager(cacheStore,iPolicyS, autoPullModeS); - RegistryService.RegistryConfig.Builder registryConfigBuilder = - new RegistryService.RegistryConfig.Builder() - .authConfigFactory(authConfigFactory) - .authConfig(authConfig); - if (registry != null) { - registryConfigBuilder.registry(registry); - } - registryService.pullImageWithPolicy(imageName, pullManager, registryConfigBuilder.build(), hasImage); + try { + MavenRegistryContext buildContext = + new MavenRegistryContext.Builder() + .authRegistryAuthFactory(registryAuthFactory) + .pullRegistry(registry) + .build(); + registryService.pullImage(imageName, imagePullPolicy, buildContext); } catch (Exception e) { //e.printStackTrace(); this.actualException = e; } } + private void givenEmptyAuthConfig() throws IOException { + new Expectations() {{ + registryAuthFactory.createAuthConfig((RegistryAuthConfig.Kind) any, anyString, anyString); + result = RegistryAuth.EMPTY_REGISTRY_AUTH; + }}; + } + private void givenImagePullPolicy(ImagePullPolicy policy) { this.imagePullPolicy = policy; } @@ -280,7 +291,7 @@ private void givenAnImage(String imageName) { this.imageName = imageName; } - private class TestCacheStore implements ImagePullManager.CacheStore { + private class TestBackend implements ImagePullCache.Backend { String cache; diff --git a/src/test/java/io/fabric8/maven/docker/build/auth/RegistryAuthFactoryTest.java b/src/test/java/io/fabric8/maven/docker/build/auth/RegistryAuthFactoryTest.java new file mode 100644 index 000000000..1f6be1318 --- /dev/null +++ b/src/test/java/io/fabric8/maven/docker/build/auth/RegistryAuthFactoryTest.java @@ -0,0 +1,516 @@ +package io.fabric8.maven.docker.build.auth; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import io.fabric8.maven.docker.build.auth.extended.EcrExtendedRegistryAuthHandler; +import io.fabric8.maven.docker.build.auth.handler.FromConfigRegistryAuthHandler; +import io.fabric8.maven.docker.build.auth.handler.OpenShiftRegistryAuthHandler; +import io.fabric8.maven.docker.build.auth.handler.SystemPropertyRegistryAuthHandler; +import io.fabric8.maven.docker.build.docker.DockerRegistryAuthHandler; +import io.fabric8.maven.docker.build.maven.SettingsRegistrysAuthHandler; +import io.fabric8.maven.docker.util.JsonFactory; +import io.fabric8.maven.docker.util.Logger; +import mockit.Expectations; +import mockit.Mock; +import mockit.Mocked; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.settings.Server; +import org.apache.maven.settings.Settings; +import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.util.Base64; +import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; + +import static java.util.Collections.singletonMap; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * @author roland + * @since 29.07.14 + */ + +public class RegistryAuthFactoryTest { + + public static final String ECR_NAME = "123456789012.dkr.ecr.bla.amazonaws.com"; + + @Mocked + Settings settings; + + @Mocked + private Logger log; + + private RegistryAuthFactory factory; + + private RegistryAuthConfig.Kind kind = RegistryAuthConfig.Kind.PUSH; + + private Gson gson; + + public static final class MockSecDispatcher implements SecDispatcher { + @Mock + public String decrypt(String password) { + return password; + } + } + + @Mocked + PlexusContainer container; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void containerSetup() throws ComponentLookupException { + final SecDispatcher secDispatcher = new MockSecDispatcher(); + new Expectations() {{ + container.lookup(SecDispatcher.ROLE, "maven"); minTimes = 0; result = secDispatcher; + + }}; + + gson = new Gson(); + } + + private void setupAuthConfigFactory(RegistryAuthConfig registryAuthConfig) { + factory = new RegistryAuthFactory.Builder() + .decryptor(d -> d) + .log(log) + .registryAuthConfig(registryAuthConfig) + .addRegistryAuthHandler(new SystemPropertyRegistryAuthHandler(registryAuthConfig, log)) + .addRegistryAuthHandler(new OpenShiftRegistryAuthHandler(registryAuthConfig, log)) + .addRegistryAuthHandler(new FromConfigRegistryAuthHandler(registryAuthConfig, log)) + .addRegistryAuthHandler(new SettingsRegistrysAuthHandler(settings, log)) + .addRegistryAuthHandler(new DockerRegistryAuthHandler(log)) + .addExtendedRegistryAuthHandler(new EcrExtendedRegistryAuthHandler(log)) + .build(); + } + + private void setupDefaultAuthConfigFactory() { + setupAuthConfigFactory( + new RegistryAuthConfig.Builder() + .skipExtendedAuthentication(false) + .propertyPrefix("docker") + .build()); + } + + + private void setupOpenshiftAuthUsage() { + setupAuthConfigFactory( + new RegistryAuthConfig.Builder() + .skipExtendedAuthentication(false) + .propertyPrefix("docker") + .addHandlerConfig("openshift", OpenShiftRegistryAuthHandler.AUTH_USE_OPENSHIFT_AUTH, "true") + .build()); + } + + + @Test + public void testEmpty() throws Exception { + setupDefaultAuthConfigFactory(); + executeWithTempHomeDir(homeDir -> assertEquals(factory.createAuthConfig(kind, null, "blubberbla:1611"), RegistryAuth.EMPTY_REGISTRY_AUTH)); + } + + + @Test + public void testSystemProperty() throws Exception { + setupDefaultAuthConfigFactory(); + System.setProperty("docker.push.username","roland"); + System.setProperty("docker.push.password", "secret"); + System.setProperty("docker.push.email", "roland@jolokia.org"); + try { + RegistryAuth config = factory.createAuthConfig(RegistryAuthConfig.Kind.PUSH, null, null); + verifyAuthConfig(config,"roland","secret","roland@jolokia.org"); + } finally { + System.clearProperty("docker.push.username"); + System.clearProperty("docker.push.password"); + System.clearProperty("docker.push.email"); + } + } + + + @Test + public void testDockerAuthLogin() throws Exception { + setupDefaultAuthConfigFactory(); + + executeWithTempHomeDir(homeDir -> { + checkDockerAuthLogin(homeDir, "https://index.docker.io/v1/", null); + checkDockerAuthLogin(homeDir,"localhost:5000","localhost:5000"); + checkDockerAuthLogin(homeDir,"https://localhost:5000","localhost:5000"); + }); + } + + @Test + public void testDockerLoginNoConfig() throws MojoExecutionException, IOException { + setupDefaultAuthConfigFactory(); + + executeWithTempHomeDir(dir -> { + RegistryAuth config = factory.createAuthConfig(kind, "roland", null); + assertTrue(config == RegistryAuth.EMPTY_REGISTRY_AUTH); + }); + } + + @Test + public void testDockerLoginFallsBackToAuthWhenCredentialHelperDoesNotMatchDomain() throws MojoExecutionException, IOException { + setupDefaultAuthConfigFactory(); + + executeWithTempHomeDir(homeDir -> { + writeDockerConfigJson(createDockerConfig(homeDir),null,singletonMap("registry1", "credHelper1-does-not-exist")); + RegistryAuth config = factory.createAuthConfig(kind, "roland", "localhost:5000"); + verifyAuthConfig(config,"roland","secret","roland@jolokia.org"); + }); + } + + @Test + public void testDockerLoginNoAuthConfigFoundWhenCredentialHelperDoesNotMatchDomainOrAuth() throws MojoExecutionException, IOException { + setupDefaultAuthConfigFactory(); + + executeWithTempHomeDir(homeDir -> { + writeDockerConfigJson(createDockerConfig(homeDir),null,singletonMap("registry1", "credHelper1-does-not-exist")); + RegistryAuth config = factory.createAuthConfig(kind, "roland", "does-not-exist-either:5000"); + assertTrue(config == RegistryAuth.EMPTY_REGISTRY_AUTH); + }); + } + + @Test + public void testDockerLoginSelectCredentialHelper() throws MojoExecutionException, IOException { + setupDefaultAuthConfigFactory(); + + executeWithTempHomeDir(homeDir -> { + writeDockerConfigJson(createDockerConfig(homeDir),"credsStore-does-not-exist",singletonMap("registry1", "credHelper1-does-not-exist")); + expectedException.expect(RuntimeException.class); + expectedException.expectCause(Matchers.allOf( + instanceOf(IOException.class), + hasProperty("message",startsWith("Failed to start 'docker-credential-credHelper1-does-not-exist version'")) + )); + factory.createAuthConfig(kind, "roland", "registry1"); + }); + } + + @Test + public void testDockerLoginSelectCredentialsStore() throws MojoExecutionException, IOException { + setupDefaultAuthConfigFactory(); + + executeWithTempHomeDir(homeDir -> { + writeDockerConfigJson(createDockerConfig(homeDir),"credsStore-does-not-exist",singletonMap("registry1", "credHelper1-does-not-exist")); + expectedException.expect(RuntimeException.class); + expectedException.expectCause(Matchers.allOf( + instanceOf(IOException.class), + hasProperty("message",startsWith("Failed to start 'docker-credential-credsStore-does-not-exist version'")) + )); + factory.createAuthConfig(kind, "roland", null); + }); + } + + @Test + public void testDockerLoginDefaultToCredentialsStore() throws MojoExecutionException, IOException { + setupDefaultAuthConfigFactory(); + + executeWithTempHomeDir(homeDir -> { + writeDockerConfigJson(createDockerConfig(homeDir),"credsStore-does-not-exist",singletonMap("registry1", "credHelper1-does-not-exist")); + expectedException.expect(RuntimeException.class); + expectedException.expectCause(Matchers.allOf( + instanceOf(IOException.class), + hasProperty("message",startsWith("Failed to start 'docker-credential-credsStore-does-not-exist version'")) + )); + factory.createAuthConfig(kind, "roland", "registry2"); + }); + } + + private void executeWithTempHomeDir(HomeDirExecutor executor) throws IOException, MojoExecutionException { + String userHome = System.getProperty("user.home"); + try { + File tempDir = Files.createTempDirectory("d-m-p").toFile(); + System.setProperty("user.home", tempDir.getAbsolutePath()); + executor.exec(tempDir); + } finally { + System.setProperty("user.home",userHome); + } + + } + + interface HomeDirExecutor { + void exec(File dir) throws IOException, MojoExecutionException; + } + + private void checkDockerAuthLogin(File homeDir,String configRegistry,String lookupRegistry) + throws IOException { + setupDefaultAuthConfigFactory(); + + writeDockerConfigJson(createDockerConfig(homeDir), "roland", "secret", "roland@jolokia.org", configRegistry); + RegistryAuth config = factory.createAuthConfig(kind, "roland", lookupRegistry); + verifyAuthConfig(config,"roland","secret","roland@jolokia.org"); + } + + private File createDockerConfig(File homeDir) { + File dockerDir = new File(homeDir,".docker"); + dockerDir.mkdirs(); + return dockerDir; + } + + private void writeDockerConfigJson(File dockerDir, String user, String password, + String email, String registry) throws IOException { + File configFile = new File(dockerDir,"config.json"); + + JsonObject config = new JsonObject(); + addAuths(config,user,password,email,registry); + + try (Writer writer = new FileWriter(configFile)){ + gson.toJson(config, writer); + } + } + + private void writeDockerConfigJson(File dockerDir,String credsStore,Map credHelpers) throws IOException { + File configFile = new File(dockerDir,"config.json"); + + JsonObject config = new JsonObject(); + if (!credHelpers.isEmpty()){ + config.add("credHelpers", JsonFactory.newJsonObject(credHelpers)); + } + + if (credsStore!=null) { + config.addProperty("credsStore",credsStore); + } + + addAuths(config,"roland","secret","roland@jolokia.org", "localhost:5000"); + + try (Writer writer = new FileWriter(configFile)){ + gson.toJson(config, writer); + } + } + + private void addAuths(JsonObject config,String user,String password,String email,String registry) { + JsonObject auths = new JsonObject(); + JsonObject value = new JsonObject(); + value.addProperty("auth", new String(Base64.encodeBase64((user + ":" + password).getBytes()))); + value.addProperty("email",email); + auths.add(registry, value); + config.add("auths",auths); + } + + @Test + public void testOpenShiftConfigFromPluginConfig() throws Exception { + setupOpenshiftAuthUsage(); + + executeWithTempHomeDir(homeDir -> { + createOpenShiftConfig(homeDir,"openshift_simple_config.yaml"); + RegistryAuth config = factory.createAuthConfig(kind, "roland", null); + verifyAuthConfig(config,"admin","token123",null); + }); + } + + @Test + public void testOpenShiftConfigFromSystemProps() throws Exception { + setupDefaultAuthConfigFactory(); + + try { + System.setProperty("docker.useOpenShiftAuth","true"); + executeWithTempHomeDir(homeDir -> { + createOpenShiftConfig(homeDir, "openshift_simple_config.yaml"); + RegistryAuth config = factory.createAuthConfig(kind, "roland", null); + verifyAuthConfig(config, "admin", "token123", null); + }); + } finally { + System.getProperties().remove("docker.useOpenShiftAuth"); + } + } + + @Test + public void testOpenShiftConfigFromSystemPropsNegative() throws Exception { + setupOpenshiftAuthUsage(); + + try { + System.setProperty("docker.useOpenShiftAuth","false"); + executeWithTempHomeDir(homeDir -> { + createOpenShiftConfig(homeDir, "openshift_simple_config.yaml"); + RegistryAuth config = factory.createAuthConfig(kind, "roland", null); + assertTrue(config == RegistryAuth.EMPTY_REGISTRY_AUTH); + }); + } finally { + System.getProperties().remove("docker.useOpenShiftAuth"); + } + } + + @Test + public void testOpenShiftConfigNotLoggedIn() throws Exception { + setupOpenshiftAuthUsage(); + + executeWithTempHomeDir(homeDir -> { + createOpenShiftConfig(homeDir,"openshift_nologin_config.yaml"); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage(containsString("~/.kube/config")); + factory.createAuthConfig(kind, "roland", null); + }); + + } + + + private void createOpenShiftConfig(File homeDir,String testConfig) throws IOException { + File kubeDir = new File(homeDir,".kube"); + kubeDir.mkdirs(); + File config = new File(kubeDir,"config"); + IOUtil.copy(getClass().getResourceAsStream(testConfig),new FileWriter(config)); + } + + @Test + public void testSystemPropertyNoPassword() throws IOException { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("No password provided for username secret"); + checkException("docker.username"); + } + + private void checkException(String key) throws IOException { + setupDefaultAuthConfigFactory(); + + System.setProperty(key, "secret"); + try { + factory.createAuthConfig(kind, null, null); + } finally { + System.clearProperty(key); + } + } + + @Test + public void testFromPluginConfiguration() throws IOException { + setupAuthConfigFactoryWithConfigData(); + + RegistryAuth config = factory.createAuthConfig(kind, null, null); + verifyAuthConfig(config, "roland", "secret", "roland@jolokia.org"); + } + + private void setupAuthConfigFactoryWithConfigData() { + setupAuthConfigFactory( + new RegistryAuthConfig.Builder() + .skipExtendedAuthentication(false) + .addDefaultConfig(RegistryAuth.USERNAME, "roland") + .addDefaultConfig(RegistryAuth.PASSWORD, "secret") + .addDefaultConfig(RegistryAuth.EMAIL, "roland@jolokia.org") + .build()); + } + + private void setupAuthConfigFactoryWithConfigDataForKind(RegistryAuthConfig.Kind kind) { + setupAuthConfigFactory( + new RegistryAuthConfig.Builder() + .skipExtendedAuthentication(false) + .addKindConfig(kind, RegistryAuth.USERNAME, "roland") + .addKindConfig(kind, RegistryAuth.PASSWORD, "secret") + .addKindConfig(kind, RegistryAuth.EMAIL, "roland@jolokia.org") + .build()); + } + + @Test + public void testFromPluginConfigurationPull() throws IOException { + setupAuthConfigFactoryWithConfigDataForKind(RegistryAuthConfig.Kind.PULL); + + RegistryAuth config = factory.createAuthConfig(RegistryAuthConfig.Kind.PULL, null, null); + verifyAuthConfig(config, "roland", "secret", "roland@jolokia.org"); + } + + + @Test + public void testFromPluginConfigurationFailed() throws IOException { + setupAuthConfigFactory(new RegistryAuthConfig.Builder().addDefaultConfig(RegistryAuth.USERNAME, "adming").build()); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage(containsString("password")); + factory.createAuthConfig(kind, null, null); + } + + @Test + public void testFromSettingsSimple() throws IOException { + setupServers(); + setupDefaultAuthConfigFactory(); + + RegistryAuth config = factory.createAuthConfig(kind, "roland", "test.org"); + assertNotNull(config); + verifyAuthConfig(config, "roland", "secret", "roland@jolokia.org"); + } + + @Test + public void testFromSettingsDefault() throws IOException { + setupServers(); + setupDefaultAuthConfigFactory(); + + RegistryAuth config = factory.createAuthConfig(kind, "fabric8io", "test.org"); + assertNotNull(config); + verifyAuthConfig(config, "fabric8io", "secret2", "fabric8io@redhat.com"); + } + + @Test + public void testFromSettingsDefault2() throws IOException { + setupServers(); + setupDefaultAuthConfigFactory(); + + RegistryAuth config = factory.createAuthConfig(kind, "tanja", null); + assertNotNull(config); + verifyAuthConfig(config,"tanja","doublesecret","tanja@jolokia.org"); + } + + @Test + public void testWrongUserName() throws IOException, MojoExecutionException { + setupDefaultAuthConfigFactory(); + + executeWithTempHomeDir(homeDir -> { + setupServers(); + assertEquals(factory.createAuthConfig(kind, "roland", "another.repo.org"), RegistryAuth.EMPTY_REGISTRY_AUTH); + }); + } + + + private void setupServers() { + new Expectations() {{ + List servers = new ArrayList<>(); + + servers.add(create(ECR_NAME, "roland", "secret", "roland@jolokia.org")); + servers.add(create("test.org", "fabric8io", "secret2", "fabric8io@redhat.com")); + servers.add(create("test.org/roland", "roland", "secret", "roland@jolokia.org")); + servers.add(create("docker.io", "tanja", "doublesecret", "tanja@jolokia.org")); + servers.add(create("another.repo.org/joe", "joe", "3secret", "joe@foobar.com")); + settings.getServers(); + result = servers; + } + + private Server create(String id, String user, String password, String email) { + Server server = new Server(); + server.setId(id); + server.setUsername(user); + server.setPassword(password); + Xpp3Dom dom = new Xpp3Dom("configuration"); + Xpp3Dom emailD = new Xpp3Dom("email"); + emailD.setValue(email); + dom.addChild(emailD); + server.setConfiguration(dom); + return server; + } + }; + } + + private void verifyAuthConfig(RegistryAuth config, String username, String password, String email) { + JsonObject params = gson.fromJson(new String(Base64.decodeBase64(config.toHeaderValue().getBytes())), JsonObject.class); + assertEquals(username,params.get("username").getAsString()); + assertEquals(password,params.get("password").getAsString()); + if (email != null) { + assertEquals(email, params.get("email").getAsString()); + } + } + +} diff --git a/src/test/java/io/fabric8/maven/docker/util/AuthConfigTest.java b/src/test/java/io/fabric8/maven/docker/build/auth/RegistryAuthTest.java similarity index 62% rename from src/test/java/io/fabric8/maven/docker/util/AuthConfigTest.java rename to src/test/java/io/fabric8/maven/docker/build/auth/RegistryAuthTest.java index ff685796d..28551ac31 100644 --- a/src/test/java/io/fabric8/maven/docker/util/AuthConfigTest.java +++ b/src/test/java/io/fabric8/maven/docker/build/auth/RegistryAuthTest.java @@ -1,15 +1,14 @@ -package io.fabric8.maven.docker.util; +package io.fabric8.maven.docker.build.auth; import com.google.gson.JsonObject; +import io.fabric8.maven.docker.util.JsonFactory; import org.apache.commons.codec.binary.Base64; import org.junit.Test; import java.util.HashMap; import java.util.Map; -import io.fabric8.maven.docker.access.AuthConfig; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -17,32 +16,30 @@ * @author roland * @since 30.07.14 */ -public class AuthConfigTest { +public class RegistryAuthTest { @Test public void simpleConstructor() { - Map map = new HashMap(); - map.put("username","roland"); - map.put("password","#>secrets??"); - map.put("email","roland@jolokia.org"); - AuthConfig config = new AuthConfig(map); - check(config); - } - - @Test - public void mapConstructor() { - AuthConfig config = new AuthConfig("roland","#>secrets??","roland@jolokia.org",null); + RegistryAuth config = new RegistryAuth.Builder() + .username("roland") + .password("#>secrets??") + .email("roland@jolokia.org") + .build(); check(config); } @Test public void dockerLoginConstructor() { - AuthConfig config = new AuthConfig(Base64.encodeBase64String("roland:#>secrets??".getBytes()),"roland@jolokia.org"); + RegistryAuth config = + new RegistryAuth.Builder() + .withCredentialsEncoded(Base64.encodeBase64String("roland:#>secrets??".getBytes())) + .email("roland@jolokia.org") + .build(); check(config); } - private void check(AuthConfig config) { + private void check(RegistryAuth config) { // Since Base64.decodeBase64 handles URL-safe encoding, must explicitly check // the correct characters are used assertEquals( diff --git a/src/test/java/io/fabric8/maven/docker/access/ecr/AwsSigner4RequestTest.java b/src/test/java/io/fabric8/maven/docker/build/auth/extended/ecr/AwsSigner4RequestTest.java similarity index 84% rename from src/test/java/io/fabric8/maven/docker/access/ecr/AwsSigner4RequestTest.java rename to src/test/java/io/fabric8/maven/docker/build/auth/extended/ecr/AwsSigner4RequestTest.java index 5dbf55a07..f2abe2ae7 100644 --- a/src/test/java/io/fabric8/maven/docker/access/ecr/AwsSigner4RequestTest.java +++ b/src/test/java/io/fabric8/maven/docker/build/auth/extended/ecr/AwsSigner4RequestTest.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.access.ecr; +package io.fabric8.maven.docker.build.auth.extended.ecr; import io.fabric8.maven.docker.access.util.RequestUtil; import java.nio.charset.StandardCharsets; @@ -10,7 +10,7 @@ import org.junit.Assert; import org.junit.Test; -import io.fabric8.maven.docker.access.AuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuth; /** * Test aws request signing @@ -54,8 +54,12 @@ public void testSign() throws Exception { Date signingTime = AwsSigner4Request.TIME_FORMAT.parse("20150830T123600Z"); AwsSigner4Request sr = new AwsSigner4Request("us-east-1", "service", request, signingTime); - AuthConfig credentials = new AuthConfig("AKIDEXAMPLE", "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", null, null); - + RegistryAuth credentials = + new RegistryAuth.Builder() + .username("AKIDEXAMPLE") + .password("wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY") + .build(); + Assert.assertEquals(TASK1, signer.task1(sr)); Assert.assertEquals(TASK2, signer.task2(sr)); @@ -72,7 +76,12 @@ public void includesAuthTokenAsAwsSecurityToken() { HttpUriRequest request = RequestUtil.newGet("https://someService.us-east-1.amazonaws.com/"); request.setHeader("host", request.getURI().getHost()); String awsSecurityToken = "securityToken"; - AuthConfig credentials = new AuthConfig("awsAccessKeyId", "awsSecretAccessKey", null, awsSecurityToken); + RegistryAuth credentials = + new RegistryAuth.Builder() + .username("awsAccessKeyId") + .password( "awsSecretAccessKey") + .auth(awsSecurityToken) + .build(); AwsSigner4 signer = new AwsSigner4("us-east-1", "someService"); signer.sign(request, credentials, new Date()); diff --git a/src/test/java/io/fabric8/maven/docker/access/ecr/EcrExtendedAuthTest.java b/src/test/java/io/fabric8/maven/docker/build/auth/extended/ecr/EcrExtendedAuthTest.java similarity index 85% rename from src/test/java/io/fabric8/maven/docker/access/ecr/EcrExtendedAuthTest.java rename to src/test/java/io/fabric8/maven/docker/build/auth/extended/ecr/EcrExtendedAuthTest.java index 6ed922ed0..65fb0131b 100644 --- a/src/test/java/io/fabric8/maven/docker/access/ecr/EcrExtendedAuthTest.java +++ b/src/test/java/io/fabric8/maven/docker/build/auth/extended/ecr/EcrExtendedAuthTest.java @@ -1,8 +1,8 @@ -package io.fabric8.maven.docker.access.ecr; +package io.fabric8.maven.docker.build.auth.extended.ecr; import org.junit.Test; -import io.fabric8.maven.docker.access.AuthConfig; +import io.fabric8.maven.docker.build.auth.RegistryAuth; import io.fabric8.maven.docker.util.Logger; import mockit.Expectations; import mockit.Mocked; @@ -48,7 +48,11 @@ public void testIsAws() { @Test public void testHeaders() throws ParseException { EcrExtendedAuth eea = new EcrExtendedAuth(logger, "123456789012.dkr.ecr.eu-west-1.amazonaws.com"); - AuthConfig localCredentials = new AuthConfig("username", "password", null, null); + RegistryAuth localCredentials = + new RegistryAuth.Builder() + .username("username") + .password("password") + .build(); Date signingTime = AwsSigner4Request.TIME_FORMAT.parse("20161217T211058Z"); HttpPost request = eea.createSignedRequest(localCredentials, signingTime); assertEquals("ecr.eu-west-1.amazonaws.com", request.getFirstHeader("host").getValue()); @@ -77,8 +81,12 @@ CloseableHttpClient createClient() { } }; - AuthConfig localCredentials = new AuthConfig("username", "password", null, null); - AuthConfig awsCredentials = eea.extendedAuth(localCredentials); + RegistryAuth localCredentials = + new RegistryAuth.Builder() + .username("username") + .password("password") + .build(); + RegistryAuth awsCredentials = eea.extendedAuth(localCredentials); assertEquals("AWS", awsCredentials.getUsername()); assertEquals("password", awsCredentials.getPassword()); diff --git a/src/test/java/io/fabric8/maven/docker/assembly/DockerFileBuilderTest.java b/src/test/java/io/fabric8/maven/docker/build/docker/DockerFileBuilderTest.java similarity index 89% rename from src/test/java/io/fabric8/maven/docker/assembly/DockerFileBuilderTest.java rename to src/test/java/io/fabric8/maven/docker/build/docker/DockerFileBuilderTest.java index 625821f49..319a57a97 100644 --- a/src/test/java/io/fabric8/maven/docker/assembly/DockerFileBuilderTest.java +++ b/src/test/java/io/fabric8/maven/docker/build/docker/DockerFileBuilderTest.java @@ -1,11 +1,14 @@ -package io.fabric8.maven.docker.assembly; +package io.fabric8.maven.docker.build.docker; import java.io.IOException; +import java.nio.charset.Charset; import java.util.*; import java.util.regex.Pattern; -import io.fabric8.maven.docker.config.*; import com.google.common.collect.ImmutableMap; +import io.fabric8.maven.docker.config.build.Arguments; +import io.fabric8.maven.docker.config.build.HealthCheckConfiguration; +import io.fabric8.maven.docker.config.build.HealthCheckMode; import org.apache.commons.io.IOUtils; import org.junit.Test; @@ -19,17 +22,17 @@ public class DockerFileBuilderTest { public void testBuildDockerFile() throws Exception { Arguments a = Arguments.Builder.get().withParam("c1").withParam("c2").build(); String dockerfileContent = new DockerFileBuilder().add("/src", "/dest") - .baseImage("image") - .cmd(a) - .env(ImmutableMap.of("foo", "bar")) - .basedir("/export") - .expose(Collections.singletonList("8080")) - .maintainer("maintainer@example.com") - .workdir("/tmp") - .labels(ImmutableMap.of("com.acme.foobar", "How are \"you\" ?")) - .volumes(Collections.singletonList("/vol1")) - .run(Arrays.asList("echo something", "echo second")) - .content(); + .baseImage("image") + .cmd(a) + .env(ImmutableMap.of("foo", "bar")) + .basedir("/export") + .expose(Collections.singletonList("8080")) + .maintainer("maintainer@example.com") + .workdir("/tmp") + .labels(ImmutableMap.of("com.acme.foobar", "How are \"you\" ?")) + .volumes(Collections.singletonList("/vol1")) + .run(Arrays.asList("echo something", "echo second")) + .content(); String expected = loadFile("docker/Dockerfile.test"); assertEquals(expected, stripCR(dockerfileContent)); } @@ -249,7 +252,7 @@ private String stripCR(String input){ } private String loadFile(String fileName) throws IOException { - return stripCR(IOUtils.toString(getClass().getClassLoader().getResource(fileName))); + return stripCR(IOUtils.toString(getClass().getClassLoader().getResource(fileName), Charset.defaultCharset())); } private static Map dockerfileToMap(String dockerFile) { diff --git a/src/test/java/io/fabric8/maven/docker/assembly/DockerAssemblyConfigurationSourceTest.java b/src/test/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyConfigurationSourceTest.java similarity index 69% rename from src/test/java/io/fabric8/maven/docker/assembly/DockerAssemblyConfigurationSourceTest.java rename to src/test/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyConfigurationSourceTest.java index 6593d1509..fa6f01e2a 100644 --- a/src/test/java/io/fabric8/maven/docker/assembly/DockerAssemblyConfigurationSourceTest.java +++ b/src/test/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyConfigurationSourceTest.java @@ -1,20 +1,21 @@ -package io.fabric8.maven.docker.assembly; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +package io.fabric8.maven.docker.build.maven.assembly; import java.io.File; import java.util.Arrays; -import io.fabric8.maven.docker.config.AssemblyConfiguration; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; +import io.fabric8.maven.docker.config.build.AssemblyConfiguration; import io.fabric8.maven.docker.util.EnvUtil; -import io.fabric8.maven.docker.util.MojoParameters; import org.apache.maven.project.MavenProject; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + public class DockerAssemblyConfigurationSourceTest { private AssemblyConfiguration assemblyConfig; @@ -38,48 +39,53 @@ public void permissionMode() { assertTrue(exp.getMessage().contains("blub")); } - AssemblyConfiguration config = new AssemblyConfiguration.Builder().ignorePermissions(false).permissions("ignore").build(); - assertTrue(config.isIgnorePermissions());; + AssemblyConfiguration config = new AssemblyConfiguration.Builder().permissions("ignore").build(); + assertSame(config.getPermissions(), AssemblyConfiguration.PermissionMode.ignore);; } @Test public void testCreateSourceAbsolute() { - testCreateSource(buildParameters(".", "/src/docker".replace("/", File.separator), "/output/docker".replace("/", File.separator))); + testCreateSource(buildBuildContetxt(".", "/src/docker".replace("/", File.separator), "/output/docker".replace("/", File.separator))); } @Test public void testCreateSourceRelative() { - testCreateSource(buildParameters(".","src/docker".replace("/", File.separator), "output/docker".replace("/", File.separator))); + testCreateSource(buildBuildContetxt(".","src/docker".replace("/", File.separator), "output/docker".replace("/", File.separator))); } @Test public void testOutputDirHasImage() { String image = "image"; - MojoParameters params = buildParameters(".", "src/docker", "output/docker"); - DockerAssemblyConfigurationSource source = new DockerAssemblyConfigurationSource(params, - new BuildDirs(image, params),assemblyConfig); + MavenBuildContext context = buildBuildContetxt(".", "src/docker", "output/docker"); + DockerAssemblyConfigurationSource source = new DockerAssemblyConfigurationSource(context, + new BuildDirs(image, context), assemblyConfig); assertTrue(containsDir(image, source.getOutputDirectory())); assertTrue(containsDir(image, source.getWorkingDirectory())); assertTrue(containsDir(image, source.getTemporaryRootDirectory())); } - private MojoParameters buildParameters(String projectDir, String sourceDir, String outputDir) { + private MavenBuildContext buildBuildContetxt(String projectDir, String sourceDir, String outputDir) { MavenProject mavenProject = new MavenProject(); mavenProject.setFile(new File(projectDir)); - return new MojoParameters(null, mavenProject, null, null, null, null, sourceDir, outputDir, null); + return new MavenBuildContext.Builder() + .project(mavenProject) + .sourceDirectory(sourceDir) + .outputDirectory(outputDir) + .build(); } @Test public void testEmptyAssemblyConfig() { - DockerAssemblyConfigurationSource source = new DockerAssemblyConfigurationSource( - new MojoParameters(null, null, null, null, null, null, "/src/docker", "/output/docker", null), - null,null - ); + MavenBuildContext buildContext = new MavenBuildContext.Builder() + .sourceDirectory("/src/docker") + .outputDirectory("/output/docker") + .build(); + DockerAssemblyConfigurationSource source = new DockerAssemblyConfigurationSource(buildContext,null,null); assertEquals(0,source.getDescriptors().length); } - private void testCreateSource(MojoParameters params) { + private void testCreateSource(MavenBuildContext params) { DockerAssemblyConfigurationSource source = new DockerAssemblyConfigurationSource(params, new BuildDirs("image", params), assemblyConfig); @@ -119,10 +125,12 @@ public void testReactorProjects() { MavenProject reactorProject2 = new MavenProject(); reactorProject2.setFile(new File("../reactor-2")); - DockerAssemblyConfigurationSource source = new DockerAssemblyConfigurationSource( - new MojoParameters(null, null, null, null, null, null, "/src/docker", "/output/docker", Arrays.asList(new MavenProject[] { reactorProject1, reactorProject2 })), - null,null - ); + MavenBuildContext buildContext = new MavenBuildContext.Builder() + .sourceDirectory("/src/docker") + .outputDirectory("/output/docker") + .reactorProjects(Arrays.asList(reactorProject1, reactorProject2)) + .build(); + DockerAssemblyConfigurationSource source = new DockerAssemblyConfigurationSource(buildContext,null,null); assertEquals(2,source.getReactorProjects().size()); } } diff --git a/src/test/java/io/fabric8/maven/docker/assembly/DockerAssemblyManagerTest.java b/src/test/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyManagerTest.java similarity index 74% rename from src/test/java/io/fabric8/maven/docker/assembly/DockerAssemblyManagerTest.java rename to src/test/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyManagerTest.java index 848a740a9..0fe9b16a2 100644 --- a/src/test/java/io/fabric8/maven/docker/assembly/DockerAssemblyManagerTest.java +++ b/src/test/java/io/fabric8/maven/docker/build/maven/assembly/DockerAssemblyManagerTest.java @@ -1,27 +1,28 @@ -package io.fabric8.maven.docker.assembly; +package io.fabric8.maven.docker.build.maven.assembly; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.Date; +import java.util.function.Function; -import io.fabric8.maven.docker.config.AssemblyConfiguration; -import io.fabric8.maven.docker.config.BuildImageConfiguration; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; +import io.fabric8.maven.docker.build.docker.DockerFileBuilder; +import io.fabric8.maven.docker.config.build.AssemblyConfiguration; +import io.fabric8.maven.docker.config.build.BuildConfiguration; import io.fabric8.maven.docker.util.AnsiLogger; import io.fabric8.maven.docker.util.DockerFileUtil; import io.fabric8.maven.docker.util.Logger; -import io.fabric8.maven.docker.util.MojoParameters; import mockit.Expectations; import mockit.Injectable; import mockit.Mock; -import mockit.MockUp; import mockit.Tested; import mockit.Verifications; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.MavenArtifactRepository; import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.logging.SystemStreamLog; import org.apache.maven.plugins.assembly.AssemblerConfigurationSource; import org.apache.maven.plugins.assembly.InvalidAssemblerConfigurationException; import org.apache.maven.plugins.assembly.archive.ArchiveCreationException; @@ -30,11 +31,9 @@ import org.apache.maven.plugins.assembly.io.AssemblyReadException; import org.apache.maven.plugins.assembly.io.AssemblyReader; import org.apache.maven.plugins.assembly.model.Assembly; -import org.apache.maven.plugin.logging.SystemStreamLog; import org.apache.maven.project.MavenProject; import org.apache.maven.settings.Settings; import org.codehaus.plexus.archiver.manager.ArchiverManager; -import org.codehaus.plexus.interpolation.fixed.FixedStringSearchInterpolator; import org.codehaus.plexus.util.ReflectionUtils; import org.junit.Test; @@ -59,7 +58,7 @@ public class DockerAssemblyManagerTest { @Test public void testNoAssembly() { - BuildImageConfiguration buildConfig = new BuildImageConfiguration(); + BuildConfiguration buildConfig = new BuildConfiguration(); AssemblyConfiguration assemblyConfig = buildConfig.getAssemblyConfiguration(); DockerFileBuilder builder = assemblyManager.createDockerFileBuilder(buildConfig, assemblyConfig); @@ -70,33 +69,32 @@ public void testNoAssembly() { } @Test - public void assemblyFiles(@Injectable final MojoParameters mojoParams, + public void assemblyFiles(@Injectable final MavenBuildContext mavenBuildContext, @Injectable final MavenProject project, - @Injectable final Assembly assembly) throws AssemblyFormattingException, ArchiveCreationException, InvalidAssemblerConfigurationException, MojoExecutionException, AssemblyReadException, IllegalAccessException { + @Injectable final Assembly assembly) throws AssemblyFormattingException, ArchiveCreationException, InvalidAssemblerConfigurationException, AssemblyReadException, IllegalAccessException, IOException { ReflectionUtils.setVariableValueInObject(assemblyManager, "trackArchiver", trackArchiver); new Expectations() {{ - mojoParams.getOutputDirectory(); + mavenBuildContext.getOutputDirectory(); result = "target/"; times = 3; - mojoParams.getProject(); - project.getBasedir(); - result = "."; + mavenBuildContext.getBasedir(); + result = new File("."); assemblyReader.readAssemblies((AssemblerConfigurationSource) any); result = Arrays.asList(assembly); }}; - BuildImageConfiguration buildConfig = createBuildConfig(); + BuildConfiguration buildConfig = createBuildConfig(); - assemblyManager.getAssemblyFiles("testImage", buildConfig, mojoParams, new AnsiLogger(new SystemStreamLog(),true,true)); + assemblyManager.getAssemblyFiles("testImage", buildConfig, mavenBuildContext, new AnsiLogger(new SystemStreamLog(),true,true)); } @Test public void testCopyValidVerifyGivenDockerfile(@Injectable final Logger logger) throws IOException { - BuildImageConfiguration buildConfig = createBuildConfig(); + BuildConfiguration buildConfig = createBuildConfig(); assemblyManager.verifyGivenDockerfile( new File(getClass().getResource("/docker/Dockerfile_assembly_verify_copy_valid.test").getPath()), @@ -112,7 +110,7 @@ public void testCopyValidVerifyGivenDockerfile(@Injectable final Logger logger) @Test public void testCopyInvalidVerifyGivenDockerfile(@Injectable final Logger logger) throws IOException { - BuildImageConfiguration buildConfig = createBuildConfig(); + BuildConfiguration buildConfig = createBuildConfig(); assemblyManager.verifyGivenDockerfile( new File(getClass().getResource("/docker/Dockerfile_assembly_verify_copy_invalid.test").getPath()), @@ -127,7 +125,7 @@ buildConfig, createInterpolator(buildConfig), @Test public void testCopyChownValidVerifyGivenDockerfile(@Injectable final Logger logger) throws IOException { - BuildImageConfiguration buildConfig = createBuildConfig(); + BuildConfiguration buildConfig = createBuildConfig(); assemblyManager.verifyGivenDockerfile( new File(getClass().getResource("/docker/Dockerfile_assembly_verify_copy_chown_valid.test").getPath()), @@ -141,23 +139,23 @@ public void testCopyChownValidVerifyGivenDockerfile(@Injectable final Logger log } - private BuildImageConfiguration createBuildConfig() { - return new BuildImageConfiguration.Builder() + private BuildConfiguration createBuildConfig() { + return new BuildConfiguration.Builder() .assembly(new AssemblyConfiguration.Builder() .descriptorRef("artifact") .build()) .build(); } - private FixedStringSearchInterpolator createInterpolator(BuildImageConfiguration buildConfig) { + private Function createInterpolator(BuildConfiguration buildConfig) { MavenProject project = new MavenProject(); project.setArtifactId("docker-maven-plugin"); - return DockerFileUtil.createInterpolator(mockMojoParams(project), buildConfig.getFilter()); + return s -> DockerFileUtil.createInterpolator(mockMavenBuildContext(project), buildConfig.getFilter()).interpolate(s); } - private MojoParameters mockMojoParams(MavenProject project) { + private MavenBuildContext mockMavenBuildContext(MavenProject project) { Settings settings = new Settings(); ArtifactRepository localRepository = new MavenArtifactRepository() { @Mock @@ -167,7 +165,15 @@ public String getBasedir() { }; @SuppressWarnings("deprecation") MavenSession session = new MavenSession(null, settings, localRepository, null, null, Collections.emptyList(), ".", null, null, new Date()); - return new MojoParameters(session, project, null, null, null, settings, "src", "target", Collections.singletonList(project)); + + return new MavenBuildContext.Builder() + .project(project) + .session(session) + .settings(settings) + .sourceDirectory("src") + .outputDirectory("target") + .reactorProjects(Collections.singletonList(project)) + .build(); } } diff --git a/src/test/java/io/fabric8/maven/docker/assembly/MappingTrackArchiverTest.java b/src/test/java/io/fabric8/maven/docker/build/maven/assembly/MappingTrackArchiverTest.java similarity index 93% rename from src/test/java/io/fabric8/maven/docker/assembly/MappingTrackArchiverTest.java rename to src/test/java/io/fabric8/maven/docker/build/maven/assembly/MappingTrackArchiverTest.java index 74b725a55..515f30731 100644 --- a/src/test/java/io/fabric8/maven/docker/assembly/MappingTrackArchiverTest.java +++ b/src/test/java/io/fabric8/maven/docker/build/maven/assembly/MappingTrackArchiverTest.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.assembly;/* +package io.fabric8.maven.docker.build.maven.assembly;/* * * Copyright 2014 Roland Huss * @@ -18,6 +18,8 @@ import java.io.File; import java.util.List; +import io.fabric8.maven.docker.build.maven.assembly.AssemblyFiles; +import io.fabric8.maven.docker.build.maven.assembly.MappingTrackArchiver; import mockit.Injectable; import org.apache.commons.io.FileUtils; import org.apache.maven.execution.MavenSession; diff --git a/src/test/java/io/fabric8/maven/docker/config/BuildImageConfigurationTest.java b/src/test/java/io/fabric8/maven/docker/config/BuildImageConfigurationTest.java deleted file mode 100644 index 94b017992..000000000 --- a/src/test/java/io/fabric8/maven/docker/config/BuildImageConfigurationTest.java +++ /dev/null @@ -1,149 +0,0 @@ -package io.fabric8.maven.docker.config; -/* - * - * Copyright 2016 Roland Huss - * - * 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. - */ - -import java.io.File; - -import io.fabric8.maven.docker.util.Logger; -import mockit.Expectations; -import mockit.Mocked; -import org.junit.Test; - -import static io.fabric8.maven.docker.config.ArchiveCompression.gzip; -import static io.fabric8.maven.docker.config.ArchiveCompression.none; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * @author roland - * @since 04/04/16 - */ - -public class BuildImageConfigurationTest { - - @Mocked - Logger logger; - - @Test - public void empty() { - BuildImageConfiguration config = new BuildImageConfiguration(); - config.initAndValidate(logger); - assertFalse(config.isDockerFileMode()); - } - - @Test - public void simpleDockerfile() { - BuildImageConfiguration config = - new BuildImageConfiguration.Builder(). - dockerFile("src/docker/Dockerfile").build(); - config.initAndValidate(logger); - assertTrue(config.isDockerFileMode()); - assertEquals(config.getDockerFile(),new File("src/docker/Dockerfile")); - } - - @Test - public void simpleDockerfileDir() { - BuildImageConfiguration config = - new BuildImageConfiguration.Builder(). - dockerFileDir("src/docker/").build(); - config.initAndValidate(logger); - assertTrue(config.isDockerFileMode()); - assertEquals(config.getDockerFile(),new File("src/docker/Dockerfile")); - } - - @Test - public void DockerfileDirAndDockerfileAlsoSet() { - BuildImageConfiguration config = - new BuildImageConfiguration.Builder(). - dockerFileDir("/tmp/"). - dockerFile("Dockerfile").build(); - config.initAndValidate(logger); - assertTrue(config.isDockerFileMode()); - assertEquals(config.getDockerFile(),new File("/tmp/Dockerfile")); - } - - @Test(expected=IllegalArgumentException.class) - public void DockerfileDirAndDockerfileAlsoSetButDockerfileIsAbsoluteExceptionThrown() { - BuildImageConfiguration config = - new BuildImageConfiguration.Builder(). - dockerFileDir("/tmp/"). - dockerFile("/Dockerfile").build(); - config.initAndValidate(logger); - } - - @Test - public void deprecatedDockerfileDir() { - AssemblyConfiguration assemblyConfig = new AssemblyConfiguration.Builder().dockerFileDir("src/docker").build(); - BuildImageConfiguration config = - new BuildImageConfiguration.Builder(). - assembly(assemblyConfig).build(); - - new Expectations() {{ - logger.warn(withSubstring("deprecated")); - }}; - - config.initAndValidate(logger); - assertTrue(config.isDockerFileMode()); - assertEquals(config.getDockerFile(),new File("src/docker/Dockerfile")); - } - - @Test - public void dockerFileAndArchive() { - BuildImageConfiguration config = - new BuildImageConfiguration.Builder(). - dockerArchive("this"). - dockerFile("that").build(); - - try { - config.initAndValidate(logger); - } catch (IllegalArgumentException expected) { - return; - } - fail("Should have failed."); - } - - @Test - public void dockerArchive() { - BuildImageConfiguration config = - new BuildImageConfiguration.Builder(). - dockerArchive("this").build(); - config.initAndValidate(logger); - - assertFalse(config.isDockerFileMode()); - assertEquals(new File("this"), config.getDockerArchive()); - } - - @Test - public void compression() { - BuildImageConfiguration config = - new BuildImageConfiguration.Builder(). - compression("gzip").build(); - assertEquals(gzip, config.getCompression()); - - config = new BuildImageConfiguration.Builder().build(); - assertEquals(none, config.getCompression()); - - config = - new BuildImageConfiguration.Builder(). - compression(null).build(); - assertEquals(none, config.getCompression()); - } - - -} diff --git a/src/test/java/io/fabric8/maven/docker/config/ConfigHelperTest.java b/src/test/java/io/fabric8/maven/docker/config/ConfigHelperTest.java index 455d30420..1413787e4 100644 --- a/src/test/java/io/fabric8/maven/docker/config/ConfigHelperTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/ConfigHelperTest.java @@ -19,6 +19,7 @@ import java.util.*; import io.fabric8.maven.docker.util.AnsiLogger; +import io.fabric8.maven.docker.util.ConfigHelper; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.logging.SystemStreamLog; import org.apache.maven.project.MavenProject; @@ -140,7 +141,7 @@ public void filter() throws Exception { @Test public void initAndValidate() throws Exception { List configs = Arrays.asList(new ImageConfiguration.Builder().name("test").build()); - String api = ConfigHelper.initAndValidate(configs, "v1.16", ConfigHelper.NameFormatter.IDENTITY, null); + String api = ConfigHelper.initAndValidate(configs, "v1.16", ImageConfiguration.NameFormatter.IDENTITY, null); assertEquals("v1.16",api); } diff --git a/src/test/java/io/fabric8/maven/docker/config/ImageConfigResolverTest.java b/src/test/java/io/fabric8/maven/docker/config/ImageConfigResolverTest.java index c4f5b4c9b..1c4c152f7 100644 --- a/src/test/java/io/fabric8/maven/docker/config/ImageConfigResolverTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/ImageConfigResolverTest.java @@ -19,6 +19,7 @@ import io.fabric8.maven.docker.config.handler.ExternalConfigHandler; import io.fabric8.maven.docker.config.handler.ImageConfigResolver; +import io.fabric8.maven.docker.util.ConfigHelper; import io.fabric8.maven.docker.util.Logger; import mockit.Mocked; import org.apache.maven.execution.MavenSession; diff --git a/src/test/java/io/fabric8/maven/docker/util/ImageNameTest.java b/src/test/java/io/fabric8/maven/docker/config/ImageNameTest.java similarity index 99% rename from src/test/java/io/fabric8/maven/docker/util/ImageNameTest.java rename to src/test/java/io/fabric8/maven/docker/config/ImageNameTest.java index 9bcd779c4..af3622059 100644 --- a/src/test/java/io/fabric8/maven/docker/util/ImageNameTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/ImageNameTest.java @@ -1,5 +1,6 @@ -package io.fabric8.maven.docker.util; +package io.fabric8.maven.docker.config; +import io.fabric8.maven.docker.config.ImageName; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/io/fabric8/maven/docker/config/build/BuildConfigurationTest.java b/src/test/java/io/fabric8/maven/docker/config/build/BuildConfigurationTest.java new file mode 100644 index 000000000..ab3657949 --- /dev/null +++ b/src/test/java/io/fabric8/maven/docker/config/build/BuildConfigurationTest.java @@ -0,0 +1,143 @@ +package io.fabric8.maven.docker.config.build; +/* + * + * Copyright 2016 Roland Huss + * + * 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. + */ + +import java.io.File; + +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.util.EnvUtil; +import io.fabric8.maven.docker.util.Logger; +import mockit.Mocked; +import org.junit.Test; + +import static io.fabric8.maven.docker.config.build.ArchiveCompression.bzip2; +import static io.fabric8.maven.docker.config.build.ArchiveCompression.gzip; +import static io.fabric8.maven.docker.config.build.ArchiveCompression.none; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * @author roland + * @since 04/04/16 + */ + +public class BuildConfigurationTest { + + @Mocked + Logger logger; + + @Test + public void empty() { + BuildConfiguration config = new BuildConfiguration(); + config.validate(); + assertFalse(config.isDockerFileMode()); + } + + @Test + public void simpleDockerfile() { + BuildConfiguration config = + new BuildConfiguration.Builder(). + dockerFile("src/docker/Dockerfile").build(); + config.validate(); + assertTrue(config.isDockerFileMode()); + assertEquals(config.calculateDockerFilePath(),new File("src/docker/Dockerfile")); + } + + @Test + public void simpleDockerfileDir() { + BuildConfiguration config = + new BuildConfiguration.Builder(). + contextDir("src/docker/").build(); + config.validate(); + assertTrue(config.isDockerFileMode()); + assertEquals(config.calculateDockerFilePath(),new File("src/docker/Dockerfile")); + } + + @Test + public void DockerfileDirAndDockerfileAlsoSet() { + BuildConfiguration config = + new BuildConfiguration.Builder(). + contextDir("/tmp/"). + dockerFile("Dockerfile").build(); + config.validate(); + assertTrue(config.isDockerFileMode()); + assertEquals(config.calculateDockerFilePath(),new File("/tmp/Dockerfile")); + } + + @Test + public void dockerFileAndArchive() { + BuildConfiguration config = + new BuildConfiguration.Builder(). + dockerArchive("this"). + dockerFile("that").build(); + + try { + config.validate(); + } catch (IllegalArgumentException expected) { + return; + } + fail("Should have failed."); + } + + @Test + public void dockerArchive() { + BuildConfiguration config = + new BuildConfiguration.Builder(). + dockerArchive("this").build(); + config.validate(); + + assertFalse(config.isDockerFileMode()); + assertEquals("this", config.getDockerArchive()); + } + + @Test + public void compression() { + BuildConfiguration config = + new BuildConfiguration.Builder(). + compression("gzip").build(); + assertEquals(gzip, config.getCompression()); + + config = new BuildConfiguration.Builder().build(); + assertEquals(none, config.getCompression()); + + config = + new BuildConfiguration.Builder(). + compression("bzip2").build(); + assertEquals(bzip2, config.getCompression()); + + try { + new BuildConfiguration.Builder(). + compression("bzip").build(); + fail(); + } catch (Exception exp) { + assertTrue(exp.getMessage().contains("bzip")); + } + } + + + @Test + public void isValidWindowsFileName() { + BuildConfiguration cfg = new BuildConfiguration(); + assertFalse(cfg.isValidWindowsFileName("/Dockerfile")); + assertTrue(cfg.isValidWindowsFileName("Dockerfile")); + assertFalse(cfg.isValidWindowsFileName("Dockerfile/")); + } + + +} diff --git a/src/test/java/io/fabric8/maven/docker/config/CleanupModeTest.java b/src/test/java/io/fabric8/maven/docker/config/build/CleanupModeTest.java similarity index 85% rename from src/test/java/io/fabric8/maven/docker/config/CleanupModeTest.java rename to src/test/java/io/fabric8/maven/docker/config/build/CleanupModeTest.java index 85277cc36..fccb908c5 100644 --- a/src/test/java/io/fabric8/maven/docker/config/CleanupModeTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/build/CleanupModeTest.java @@ -1,6 +1,6 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.build; /* - * + * * Copyright 2016 Roland Huss * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,8 +16,9 @@ * limitations under the License. */ +import io.fabric8.maven.docker.config.build.CleanupMode; import org.junit.Test; -import static io.fabric8.maven.docker.config.CleanupMode.*; +import static io.fabric8.maven.docker.config.build.CleanupMode.*; import static org.junit.Assert.*; /** @@ -39,7 +40,7 @@ public void parse() { }; for (int i = 0; i < data.length; i += 2) { - assertEquals(data[i+1],CleanupMode.parse((String) data[i])); + assertEquals(data[i+1], CleanupMode.parse((String) data[i])); } } diff --git a/src/test/java/io/fabric8/maven/docker/config/HealthCheckConfigTest.java b/src/test/java/io/fabric8/maven/docker/config/build/HealthCheckConfigTest.java similarity index 94% rename from src/test/java/io/fabric8/maven/docker/config/HealthCheckConfigTest.java rename to src/test/java/io/fabric8/maven/docker/config/build/HealthCheckConfigTest.java index 8f184c986..9a6aa02c0 100644 --- a/src/test/java/io/fabric8/maven/docker/config/HealthCheckConfigTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/build/HealthCheckConfigTest.java @@ -1,5 +1,8 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.build; +import io.fabric8.maven.docker.config.build.Arguments; +import io.fabric8.maven.docker.config.build.HealthCheckConfiguration; +import io.fabric8.maven.docker.config.build.HealthCheckMode; import org.junit.Test; /** diff --git a/src/test/java/io/fabric8/maven/docker/config/handler/AbstractConfigHandlerTest.java b/src/test/java/io/fabric8/maven/docker/config/handler/AbstractConfigHandlerTest.java index 37ffa30d9..e45bdb612 100644 --- a/src/test/java/io/fabric8/maven/docker/config/handler/AbstractConfigHandlerTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/handler/AbstractConfigHandlerTest.java @@ -1,7 +1,7 @@ package io.fabric8.maven.docker.config.handler; -import io.fabric8.maven.docker.config.RestartPolicy; -import io.fabric8.maven.docker.config.RunImageConfiguration; +import io.fabric8.maven.docker.config.run.RestartPolicy; +import io.fabric8.maven.docker.config.run.RunConfiguration; import java.util.Arrays; import java.util.List; @@ -16,12 +16,12 @@ protected List a(String ... args) { } protected abstract String getEnvPropertyFile(); - - protected abstract RunImageConfiguration.NamingStrategy getRunNamingStrategy(); - + + protected abstract RunConfiguration.NamingStrategy getRunNamingStrategy(); + protected abstract void validateEnv(Map env); - - protected void validateRunConfiguration(RunImageConfiguration runConfig) { + + protected void validateRunConfiguration(RunConfiguration runConfig) { assertEquals(a("/foo", "/tmp:/tmp"), runConfig.getVolumeConfiguration().getBind()); assertEquals(a("CAP"), runConfig.getCapAdd()); assertEquals(a("CAP"), runConfig.getCapDrop()); @@ -39,16 +39,16 @@ protected void validateRunConfiguration(RunImageConfiguration runConfig) { assertEquals((Long) 1L, runConfig.getCpuShares()); assertEquals("0,1", runConfig.getCpuSet()); assertEquals(getEnvPropertyFile(),runConfig.getEnvPropertyFile()); - + assertEquals("/tmp/props.txt", runConfig.getPortPropertyFile()); assertEquals(a("8081:8080"), runConfig.getPorts()); assertEquals(true, runConfig.getPrivileged()); assertEquals("tomcat", runConfig.getUser()); assertEquals(a("from"), runConfig.getVolumeConfiguration().getFrom()); assertEquals("foo", runConfig.getWorkingDir()); - + validateEnv(runConfig.getEnv()); - + // not sure it's worth it to implement 'equals/hashcode' for these RestartPolicy policy = runConfig.getRestartPolicy(); assertEquals("on-failure", policy.getName()); diff --git a/src/test/java/io/fabric8/maven/docker/config/handler/ArchiveCompressionTest.java b/src/test/java/io/fabric8/maven/docker/config/handler/ArchiveCompressionTest.java index 3d2dd4f0b..fc8966b31 100644 --- a/src/test/java/io/fabric8/maven/docker/config/handler/ArchiveCompressionTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/handler/ArchiveCompressionTest.java @@ -1,6 +1,6 @@ package io.fabric8.maven.docker.config.handler; -import io.fabric8.maven.docker.config.ArchiveCompression; +import io.fabric8.maven.docker.config.build.ArchiveCompression; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeConfigHandlerTest.java b/src/test/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeConfigHandlerTest.java index 213b909b9..cac3ed7dd 100644 --- a/src/test/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeConfigHandlerTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/handler/compose/DockerComposeConfigHandlerTest.java @@ -1,10 +1,10 @@ package io.fabric8.maven.docker.config.handler.compose; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.NetworkConfig; -import io.fabric8.maven.docker.config.RestartPolicy; -import io.fabric8.maven.docker.config.RunImageConfiguration; -import io.fabric8.maven.docker.config.RunVolumeConfiguration; +import io.fabric8.maven.docker.config.run.NetworkConfiguration; +import io.fabric8.maven.docker.config.run.RestartPolicy; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import io.fabric8.maven.docker.config.run.RunVolumeConfiguration; import io.fabric8.maven.docker.config.handler.ExternalConfigHandlerException; import mockit.Expectations; import mockit.Injectable; @@ -73,14 +73,14 @@ public void simple() throws IOException, MavenFilteringException { public void networkAliases() throws IOException, MavenFilteringException { setupComposeExpectations("docker-compose-network-aliases.yml"); List configs = handler.resolve(unresolved, project, session); - + // Service 1 has 1 network (network1) with 2 aliases (alias1, alias2) - NetworkConfig netSvc = configs.get(0).getRunConfiguration().getNetworkingConfig(); + NetworkConfiguration netSvc = configs.get(0).getRunConfiguration().getNetworkingConfig(); assertEquals("network1", netSvc.getName()); assertEquals(2, netSvc.getAliases().size()); assertEquals("alias1", netSvc.getAliases().get(0)); assertEquals("alias2", netSvc.getAliases().get(1)); - + // Service 2 has 1 network (network1) with no aliases netSvc = configs.get(1).getRunConfiguration().getNetworkingConfig(); assertEquals("network1", netSvc.getName()); @@ -92,7 +92,7 @@ public void networkAliases() throws IOException, MavenFilteringException { assertEquals(1, netSvc.getAliases().size()); assertEquals("alias1", netSvc.getAliases().get(0)); } - + @Test public void positiveVersionTest() throws IOException, MavenFilteringException { for (String composeFile : new String[] { "version/compose-version-2.yml", "version/compose-version-2x.yml"} ) { @@ -101,7 +101,7 @@ public void positiveVersionTest() throws IOException, MavenFilteringException { } } - + @Test public void negativeVersionTest() throws IOException, MavenFilteringException { for (String composeFile : new String[] { "version/compose-wrong-version.yml", "version/compose-no-version.yml"} ) { @@ -146,7 +146,7 @@ private File getAsFile(String resource) throws IOException { } - void validateRunConfiguration(RunImageConfiguration runConfig) { + void validateRunConfiguration(RunConfiguration runConfig) { validateVolumeConfig(runConfig.getVolumeConfiguration()); diff --git a/src/test/java/io/fabric8/maven/docker/config/handler/property/PropertyConfigHandlerTest.java b/src/test/java/io/fabric8/maven/docker/config/handler/property/PropertyConfigHandlerTest.java index 4e599118f..668633508 100644 --- a/src/test/java/io/fabric8/maven/docker/config/handler/property/PropertyConfigHandlerTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/handler/property/PropertyConfigHandlerTest.java @@ -25,17 +25,16 @@ import java.util.Map; import java.util.Properties; -import io.fabric8.maven.docker.config.Arguments; -import io.fabric8.maven.docker.config.AssemblyConfiguration; -import io.fabric8.maven.docker.config.BuildImageConfiguration; -import io.fabric8.maven.docker.config.CleanupMode; -import io.fabric8.maven.docker.config.ConfigHelper; +import io.fabric8.maven.docker.config.build.Arguments; +import io.fabric8.maven.docker.config.build.AssemblyConfiguration; +import io.fabric8.maven.docker.config.build.BuildConfiguration; +import io.fabric8.maven.docker.config.build.CleanupMode; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.LogConfiguration; -import io.fabric8.maven.docker.config.RestartPolicy; -import io.fabric8.maven.docker.config.RunImageConfiguration; -import io.fabric8.maven.docker.config.UlimitConfig; -import io.fabric8.maven.docker.config.WaitConfiguration; +import io.fabric8.maven.docker.config.run.LogConfiguration; +import io.fabric8.maven.docker.config.run.RestartPolicy; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import io.fabric8.maven.docker.config.run.UlimitConfiguration; +import io.fabric8.maven.docker.config.run.WaitConfiguration; import io.fabric8.maven.docker.config.handler.AbstractConfigHandlerTest; import mockit.Expectations; import mockit.Mocked; @@ -43,8 +42,6 @@ import org.junit.Before; import org.junit.Test; -import static io.fabric8.maven.docker.config.BuildImageConfiguration.DEFAULT_CLEANUP; -import static io.fabric8.maven.docker.config.BuildImageConfiguration.DEFAULT_FILTER; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -73,10 +70,10 @@ public void setUp() throws Exception { @Test public void testSkipBuild() { - assertFalse(resolveExternalImageConfig(getSkipTestData(ConfigKey.SKIP_BUILD, false)).getBuildConfiguration().skip()); - assertTrue(resolveExternalImageConfig(getSkipTestData(ConfigKey.SKIP_BUILD, true)).getBuildConfiguration().skip()); + assertFalse(resolveExternalImageConfig(getSkipTestData(ConfigKey.SKIP_BUILD, false)).getBuildConfiguration().getSkip()); + assertTrue(resolveExternalImageConfig(getSkipTestData(ConfigKey.SKIP_BUILD, true)).getBuildConfiguration().getSkip()); - assertFalse(resolveExternalImageConfig(new String[] {k(ConfigKey.NAME), "image", k(ConfigKey.FROM), "busybox"}).getBuildConfiguration().skip()); + assertNull(resolveExternalImageConfig(new String[] {k(ConfigKey.NAME), "image", k(ConfigKey.FROM), "busybox"}).getBuildConfiguration().getSkip()); } @Test @@ -108,7 +105,7 @@ public void testPorts() { "docker.from", "busybox" )); assertEquals(1,configs.size()); - RunImageConfiguration runConfig = configs.get(0).getRunConfiguration(); + RunConfiguration runConfig = configs.get(0).getRunConfiguration(); List portsAsList = runConfig.getPorts(); String[] ports = new ArrayList<>(portsAsList).toArray(new String[portsAsList.size()]); assertArrayEquals(new String[] { @@ -116,7 +113,7 @@ public void testPorts() { "9090", "0.0.0.0:80:80" },ports); - BuildImageConfiguration buildConfig = configs.get(0).getBuildConfiguration(); + BuildConfiguration buildConfig = configs.get(0).getBuildConfiguration(); ports = new ArrayList<>(buildConfig.getPorts()).toArray(new String[buildConfig.getPorts().size()]); assertArrayEquals(new String[]{"8080", "9090", "80"}, ports); } @@ -126,11 +123,11 @@ public void testPorts() { public void testPortsFromConfigAndProperties() { imageConfiguration = new ImageConfiguration.Builder() .externalConfig(new HashMap()) - .buildConfig(new BuildImageConfiguration.Builder() + .buildConfig(new BuildConfiguration.Builder() .ports(Arrays.asList("1234")) .build() ) - .runConfig(new RunImageConfiguration.Builder() + .runConfig(new RunConfiguration.Builder() .ports(Arrays.asList("jolokia.port:1234")) .build() ) @@ -146,7 +143,7 @@ public void testPortsFromConfigAndProperties() { "docker.from", "busybox" )); assertEquals(1,configs.size()); - RunImageConfiguration runConfig = configs.get(0).getRunConfiguration(); + RunConfiguration runConfig = configs.get(0).getRunConfiguration(); List portsAsList = runConfig.getPorts(); String[] ports = new ArrayList<>(portsAsList).toArray(new String[portsAsList.size()]); assertArrayEquals(new String[] { @@ -154,7 +151,7 @@ public void testPortsFromConfigAndProperties() { "0.0.0.0:80:80", "jolokia.port:1234" },ports); - BuildImageConfiguration buildConfig = configs.get(0).getBuildConfiguration(); + BuildConfiguration buildConfig = configs.get(0).getBuildConfiguration(); ports = new ArrayList<>(buildConfig.getPorts()).toArray(new String[buildConfig.getPorts().size()]); assertArrayEquals(new String[]{"9090", "80", "1234"}, ports); } @@ -180,7 +177,7 @@ public void testRunCommands() { assertEquals(1, configs.size()); - BuildImageConfiguration buildConfig = configs.get(0).getBuildConfiguration(); + BuildConfiguration buildConfig = configs.get(0).getBuildConfiguration(); String[] runCommands = new ArrayList<>(buildConfig.getRunCmds()).toArray(new String[buildConfig.getRunCmds().size()]); assertArrayEquals(new String[]{"foo", "bar", "wibble"}, runCommands); } @@ -189,7 +186,7 @@ public void testRunCommands() { public void testRunCommandsFromPropertiesAndConfig() { imageConfiguration = new ImageConfiguration.Builder() .externalConfig(new HashMap()) - .buildConfig(new BuildImageConfiguration.Builder() + .buildConfig(new BuildConfiguration.Builder() .runCmds(Arrays.asList("some","ignored","value")) .build() ) @@ -208,7 +205,7 @@ public void testRunCommandsFromPropertiesAndConfig() { assertEquals(1, configs.size()); - BuildImageConfiguration buildConfig = configs.get(0).getBuildConfiguration(); + BuildConfiguration buildConfig = configs.get(0).getBuildConfiguration(); String[] runCommands = new ArrayList<>(buildConfig.getRunCmds()).toArray(new String[buildConfig.getRunCmds().size()]); assertArrayEquals(new String[]{"propconf", "withrun", "used"}, runCommands); } @@ -217,7 +214,7 @@ public void testRunCommandsFromPropertiesAndConfig() { public void testRunCommandsFromConfigAndProperties() { imageConfiguration = new ImageConfiguration.Builder() .externalConfig(externalConfigMode(PropertyMode.Fallback)) - .buildConfig(new BuildImageConfiguration.Builder() + .buildConfig(new BuildConfiguration.Builder() .runCmds(Arrays.asList("some","configured","value")) .build() ) @@ -234,7 +231,7 @@ public void testRunCommandsFromConfigAndProperties() { assertEquals(1, configs.size()); - BuildImageConfiguration buildConfig = configs.get(0).getBuildConfiguration(); + BuildConfiguration buildConfig = configs.get(0).getBuildConfiguration(); String[] runCommands = new ArrayList<>(buildConfig.getRunCmds()).toArray(new String[buildConfig.getRunCmds().size()]); assertArrayEquals(new String[]{"some", "configured", "value"}, runCommands); } @@ -250,7 +247,7 @@ public void testEntrypoint() { assertEquals(1, configs.size()); - BuildImageConfiguration buildConfig = configs.get(0).getBuildConfiguration(); + BuildConfiguration buildConfig = configs.get(0).getBuildConfiguration(); assertArrayEquals(new String[]{"/entrypoint.sh", "--from-property"}, buildConfig.getEntryPoint().asStrings().toArray()); } @@ -258,7 +255,7 @@ public void testEntrypoint() { public void testEntrypointExecFromConfig() { imageConfiguration = new ImageConfiguration.Builder() .externalConfig(externalConfigMode(PropertyMode.Fallback)) - .buildConfig(new BuildImageConfiguration.Builder() + .buildConfig(new BuildConfiguration.Builder() .entryPoint(new Arguments(Arrays.asList("/entrypoint.sh", "--from-property"))) .build() ) @@ -272,7 +269,7 @@ public void testEntrypointExecFromConfig() { assertEquals(1, configs.size()); - BuildImageConfiguration buildConfig = configs.get(0).getBuildConfiguration(); + BuildConfiguration buildConfig = configs.get(0).getBuildConfiguration(); assertArrayEquals(new String[]{"/entrypoint.sh", "--from-property"}, buildConfig.getEntryPoint().asStrings().toArray()); } @@ -280,7 +277,7 @@ public void testEntrypointExecFromConfig() { public void testDefaultLogEnabledConfiguration() { imageConfiguration = new ImageConfiguration.Builder() .externalConfig(externalConfigMode(PropertyMode.Override)) - .buildConfig(new BuildImageConfiguration.Builder() + .buildConfig(new BuildConfiguration.Builder() .build() ) .build(); @@ -293,7 +290,7 @@ imageConfiguration, props( assertEquals(1, configs.size()); - RunImageConfiguration runConfiguration = configs.get(0).getRunConfiguration(); + RunConfiguration runConfiguration = configs.get(0).getRunConfiguration(); assertNull(runConfiguration.getLogConfiguration().isEnabled()); assertFalse(runConfiguration.getLogConfiguration().isActivated()); @@ -314,7 +311,7 @@ imageConfiguration, props( // If image configuration has non-blank log configuration, it should become enabled imageConfiguration = new ImageConfiguration.Builder() .externalConfig(externalConfigMode(PropertyMode.Override)) - .runConfig(new RunImageConfiguration.Builder() + .runConfig(new RunConfiguration.Builder() .log(new LogConfiguration.Builder().color("red").build()) .build() ) @@ -365,7 +362,7 @@ imageConfiguration, props( public void testExplicitLogEnabledConfiguration() { imageConfiguration = new ImageConfiguration.Builder() .externalConfig(externalConfigMode(PropertyMode.Override)) - .runConfig(new RunImageConfiguration.Builder() + .runConfig(new RunConfiguration.Builder() .log(new LogConfiguration.Builder().color("red").build()) .build() ) @@ -379,7 +376,7 @@ imageConfiguration, props( "docker.log.enabled", "true") ); - RunImageConfiguration runConfiguration = getRunImageConfiguration(configs); + RunConfiguration runConfiguration = getRunImageConfiguration(configs); assertTrue(runConfiguration.getLogConfiguration().isEnabled()); assertTrue(runConfiguration.getLogConfiguration().isActivated()); assertEquals("red", runConfiguration.getLogConfiguration().getColor()); @@ -403,7 +400,7 @@ imageConfiguration, props( // Disabled by config imageConfiguration = new ImageConfiguration.Builder() .externalConfig(externalConfigMode(PropertyMode.Fallback)) - .runConfig(new RunImageConfiguration.Builder() + .runConfig(new RunConfiguration.Builder() .log(new LogConfiguration.Builder().enabled(false).color("red").build()) .build() ) @@ -452,7 +449,7 @@ imageConfiguration, props( public void testLogFile() { imageConfiguration = new ImageConfiguration.Builder() .externalConfig(externalConfigMode(PropertyMode.Override)) - .runConfig(new RunImageConfiguration.Builder() + .runConfig(new RunConfiguration.Builder() .log(new LogConfiguration.Builder().file("myfile").build()) .build() ) @@ -466,14 +463,14 @@ imageConfiguration, props( assertEquals(1, configs.size()); - RunImageConfiguration runConfiguration = configs.get(0).getRunConfiguration(); + RunConfiguration runConfiguration = configs.get(0).getRunConfiguration(); assertNull(runConfiguration.getLogConfiguration().isEnabled()); assertTrue(runConfiguration.getLogConfiguration().isActivated()); assertEquals("myfile", runConfiguration.getLogConfiguration().getFileLocation()); imageConfiguration = new ImageConfiguration.Builder() .externalConfig(externalConfigMode(PropertyMode.Override)) - .runConfig(new RunImageConfiguration.Builder() + .runConfig(new RunConfiguration.Builder() .build() ) .build(); @@ -493,7 +490,7 @@ imageConfiguration, props( assertEquals("myfilefromprop", runConfiguration.getLogConfiguration().getFileLocation()); } - private RunImageConfiguration getRunImageConfiguration(List configs) { + private RunConfiguration getRunImageConfiguration(List configs) { assertEquals(1, configs.size()); return configs.get(0).getRunConfiguration(); } @@ -503,7 +500,7 @@ public void testBuildFromDockerFileMerged() { imageConfiguration = new ImageConfiguration.Builder() .name("myimage") .externalConfig(externalConfigMode(PropertyMode.Override)) - .buildConfig(new BuildImageConfiguration.Builder() + .buildConfig(new BuildConfiguration.Builder() .dockerFile("/some/path") .build() ) @@ -515,13 +512,13 @@ imageConfiguration, props() assertEquals(1, configs.size()); - BuildImageConfiguration buildConfiguration = configs.get(0).getBuildConfiguration(); + BuildConfiguration buildConfiguration = configs.get(0).getBuildConfiguration(); assertNotNull(buildConfiguration); - buildConfiguration.initAndValidate(null); + buildConfiguration.validate(); Path absolutePath = Paths.get(".").toAbsolutePath(); String expectedPath = absolutePath.getRoot() + "some" + File.separator + "path"; - assertEquals(expectedPath, buildConfiguration.getDockerFile().getAbsolutePath()); + assertEquals(expectedPath, buildConfiguration.calculateDockerFilePath().getAbsolutePath()); } @Test @@ -611,8 +608,8 @@ public void testAssembly() throws Exception { AssemblyConfiguration config = configs.get(0).getBuildConfiguration().getAssemblyConfiguration(); assertEquals("user", config.getUser()); assertEquals("project", config.getDescriptorRef()); - assertFalse(config.exportTargetDir()); - assertTrue(config.isIgnorePermissions()); + assertNull(config.getExportTargetDir()); + assertFalse(config.getPermissions() == AssemblyConfiguration.PermissionMode.ignore); } @Test @@ -620,7 +617,7 @@ public void testNoCleanup() throws Exception { String[] testData = new String[] {k(ConfigKey.NAME), "image", k(ConfigKey.CLEANUP), "none", k(ConfigKey.FROM), "base" }; ImageConfiguration config = resolveExternalImageConfig(testData); - assertEquals(CleanupMode.NONE, config.getBuildConfiguration().cleanupMode()); + assertEquals(CleanupMode.NONE, CleanupMode.parse(config.getBuildConfiguration().getCleanupMode())); } @Test @@ -635,25 +632,25 @@ public void testNoBuildConfig() throws Exception { public void testDockerfile() throws Exception { String[] testData = new String[] { k(ConfigKey.NAME), "image", k(ConfigKey.DOCKER_FILE_DIR), "src/main/docker/", k(ConfigKey.FROM), "busybox" }; ImageConfiguration config = resolveExternalImageConfig(testData); - config.initAndValidate(ConfigHelper.NameFormatter.IDENTITY, null); + config.validate(ImageConfiguration.NameFormatter.IDENTITY); assertTrue(config.getBuildConfiguration().isDockerFileMode()); - assertEquals(new File("src/main/docker/Dockerfile"), config.getBuildConfiguration().getDockerFile()); + assertEquals(new File("src/main/docker/Dockerfile"), config.getBuildConfiguration().calculateDockerFilePath()); } @Test public void testDockerArchive() { String[] testData = new String[] { k(ConfigKey.NAME), "image", k(ConfigKey.DOCKER_ARCHIVE), "dockerLoad.tar", k(ConfigKey.FROM), "busybox" }; ImageConfiguration config = resolveExternalImageConfig(testData); - config.initAndValidate(ConfigHelper.NameFormatter.IDENTITY, null); + config.validate(ImageConfiguration.NameFormatter.IDENTITY); assertFalse(config.getBuildConfiguration().isDockerFileMode()); - assertEquals(new File("dockerLoad.tar"), config.getBuildConfiguration().getDockerArchive()); + assertEquals("dockerLoad.tar", config.getBuildConfiguration().getDockerArchive()); } @Test(expected = IllegalArgumentException.class) public void testInvalidDockerFileArchiveConfig() { String[] testData = new String[] { k(ConfigKey.NAME), "image", k(ConfigKey.DOCKER_FILE_DIR), "src/main/docker/", k(ConfigKey.DOCKER_ARCHIVE), "dockerLoad.tar", k(ConfigKey.FROM), "base" }; ImageConfiguration config = resolveExternalImageConfig(testData); - config.initAndValidate(ConfigHelper.NameFormatter.IDENTITY, null); + config.validate(ImageConfiguration.NameFormatter.IDENTITY); } @Test @@ -661,7 +658,7 @@ public void testNoCacheDisabled() throws Exception { String[] testData = new String[] {k(ConfigKey.NAME), "image", k(ConfigKey.NOCACHE), "false", k(ConfigKey.FROM), "base" }; ImageConfiguration config = resolveExternalImageConfig(testData); - assertEquals(false, config.getBuildConfiguration().nocache()); + assertEquals(false, config.getBuildConfiguration().getNoCache()); } @Test @@ -669,7 +666,7 @@ public void testNoCacheEnabled() throws Exception { String[] testData = new String[] {k(ConfigKey.NAME), "image", k(ConfigKey.NOCACHE), "true", k(ConfigKey.FROM), "base" }; ImageConfiguration config = resolveExternalImageConfig(testData); - assertEquals(true, config.getBuildConfiguration().nocache()); + assertEquals(true, config.getBuildConfiguration().getNoCache()); } @Test @@ -677,7 +674,7 @@ public void testNoOptimise() throws Exception { String[] testData = new String[] {k(ConfigKey.NAME), "image", k(ConfigKey.OPTIMISE), "false", k(ConfigKey.FROM), "base" }; ImageConfiguration config = resolveExternalImageConfig(testData); - assertEquals(false, config.getBuildConfiguration().optimise()); + assertEquals(false, config.getBuildConfiguration().getOptimise()); } @Test @@ -701,7 +698,7 @@ public void testFilterDefault() { String[] testData = new String[] {k(ConfigKey.NAME), "image", k(ConfigKey.FROM), "base" }; ImageConfiguration config = resolveExternalImageConfig(testData); - assertEquals(DEFAULT_FILTER, config.getBuildConfiguration().getFilter()); + assertNull(config.getBuildConfiguration().getFilter()); } @Test @@ -718,7 +715,7 @@ public void testCleanupDefault() { String[] testData = new String[] {k(ConfigKey.NAME), "image", k(ConfigKey.FROM), "base" }; ImageConfiguration config = resolveExternalImageConfig(testData); - assertEquals(DEFAULT_CLEANUP, config.getBuildConfiguration().cleanupMode().toParameter()); + assertEquals(null, config.getBuildConfiguration().getCleanupMode()); } @Test @@ -727,7 +724,7 @@ public void testCleanup() { String[] testData = new String[] {k(ConfigKey.NAME), "image", k(ConfigKey.FROM), "base", k(ConfigKey.CLEANUP), mode.toParameter() }; ImageConfiguration config = resolveExternalImageConfig(testData); - assertEquals(mode, config.getBuildConfiguration().cleanupMode()); + assertEquals(mode, CleanupMode.parse(config.getBuildConfiguration().getCleanupMode())); } @@ -735,10 +732,10 @@ public void testCleanup() { public void testUlimit() { imageConfiguration = new ImageConfiguration.Builder() .externalConfig(new HashMap()) - .runConfig(new RunImageConfiguration.Builder() + .runConfig(new RunConfiguration.Builder() .ulimits(Arrays.asList( - new UlimitConfig("memlock", 100, 50), - new UlimitConfig("nfile", 1024, 512) + new UlimitConfiguration("memlock", 100, 50), + new UlimitConfiguration("nfile", 1024, 512) )) .build() ) @@ -759,8 +756,8 @@ public void testUlimit() { )); assertEquals(1,configs.size()); - RunImageConfiguration runConfig = configs.get(0).getRunConfiguration(); - List ulimits = runConfig.getUlimits(); + RunConfiguration runConfig = configs.get(0).getRunConfiguration(); + List ulimits = runConfig.getUlimits(); assertEquals(4, ulimits.size()); assertUlimitEquals(ulimit("memlock",10,10),runConfig.getUlimits().get(0)); @@ -794,8 +791,8 @@ protected String getEnvPropertyFile() { } @Override - protected RunImageConfiguration.NamingStrategy getRunNamingStrategy() { - return RunImageConfiguration.NamingStrategy.none; + protected RunConfiguration.NamingStrategy getRunNamingStrategy() { + return RunConfiguration.NamingStrategy.none; } @Override @@ -852,8 +849,8 @@ private ImageConfiguration resolveExternalImageConfig(String[] testData) { return resolvedImageConfigs.get(0); } - private void validateBuildConfiguration(BuildImageConfiguration buildConfig) { - assertEquals(CleanupMode.TRY_TO_REMOVE, buildConfig.cleanupMode()); + private void validateBuildConfiguration(BuildConfiguration buildConfig) { + assertEquals(CleanupMode.TRY_TO_REMOVE, CleanupMode.parse(buildConfig.getCleanupMode())); assertEquals("command.sh", buildConfig.getCmd().getShell()); assertEquals("image", buildConfig.getFrom()); assertEquals("image-ext", buildConfig.getFromExt().get("name")); @@ -861,7 +858,7 @@ private void validateBuildConfiguration(BuildImageConfiguration buildConfig) { assertEquals("registry", buildConfig.getRegistry()); assertEquals(a("/foo"), buildConfig.getVolumes()); assertEquals("fabric8io@redhat.com",buildConfig.getMaintainer()); - assertEquals(false, buildConfig.nocache()); + assertNull(buildConfig.getNoCache()); assertEquals("Always", buildConfig.getImagePullPolicy()); validateEnv(buildConfig.getEnv()); @@ -877,8 +874,8 @@ private void validateBuildConfiguration(BuildImageConfiguration buildConfig) { assertEquals("/maven", assemblyConfig.getTargetDir()); assertEquals("assembly.xml", assemblyConfig.getDescriptor()); assertNull(assemblyConfig.getUser()); - assertNull(assemblyConfig.exportTargetDir()); - assertFalse(assemblyConfig.isIgnorePermissions()); + assertNull(assemblyConfig.getExportTargetDir()); + assertFalse(assemblyConfig.getPermissions() == AssemblyConfiguration.PermissionMode.ignore); } private void validateArgs(Map args) { @@ -893,7 +890,7 @@ private void validateBuildOptions(Map buildOptions) { assertEquals("2147483648", buildOptions.get("shmsize")); } - protected void validateRunConfiguration(RunImageConfiguration runConfig) { + protected void validateRunConfiguration(RunConfiguration runConfig) { assertEquals(a("/foo", "/tmp:/tmp"), runConfig.getVolumeConfiguration().getBind()); assertEquals(a("CAP"), runConfig.getCapAdd()); assertEquals(a("CAP"), runConfig.getCapDrop()); @@ -958,8 +955,8 @@ protected void validateRunConfiguration(RunImageConfiguration runConfig) { assertEquals("10", config.getDriver().getOpts().get("max-file")); } - private UlimitConfig ulimit(String name, Integer hard, Integer soft) { - return new UlimitConfig(name, hard, soft); + private UlimitConfiguration ulimit(String name, Integer hard, Integer soft) { + return new UlimitConfiguration(name, hard, soft); } private Properties props(String ... args) { @@ -975,8 +972,6 @@ private String[] getTestAssemblyData() { k(ConfigKey.FROM), "busybox", k(ConfigKey.ASSEMBLY_BASEDIR), "/basedir", k(ConfigKey.ASSEMBLY_DESCRIPTOR_REF), "project", - k(ConfigKey.ASSEMBLY_EXPORT_BASEDIR), "false", - k(ConfigKey.ASSEMBLY_IGNORE_PERMISSIONS), "true", k(ConfigKey.ASSEMBLY_USER), "user", k(ConfigKey.NAME), "image", }; @@ -996,7 +991,7 @@ private String[] getTestData() { k(ConfigKey.CPUSHARES), "1", k(ConfigKey.CMD), "command.sh", k(ConfigKey.DNS) + ".1", "8.8.8.8", - k(ConfigKey.NET), "host", + k(ConfigKey.NETWORK_MODE), "host", k(ConfigKey.DNS_SEARCH) + ".1", "example.com", k(ConfigKey.DOMAINNAME), "domain.com", k(ConfigKey.ENTRYPOINT), "entrypoint.sh", @@ -1058,7 +1053,7 @@ private String[] getSkipTestData(ConfigKey key, boolean value) { private String k(ConfigKey from) { return from.asPropertyKey(); } - private void assertUlimitEquals(UlimitConfig expected, UlimitConfig actual){ + private void assertUlimitEquals(UlimitConfiguration expected, UlimitConfiguration actual){ assertEquals(expected.getName(), actual.getName()); assertEquals(expected.getSoft(), actual.getSoft()); assertEquals(expected.getHard(), actual.getHard()); diff --git a/src/test/java/io/fabric8/maven/docker/config/LogConfigurationTest.java b/src/test/java/io/fabric8/maven/docker/config/run/LogConfigurationTest.java similarity index 95% rename from src/test/java/io/fabric8/maven/docker/config/LogConfigurationTest.java rename to src/test/java/io/fabric8/maven/docker/config/run/LogConfigurationTest.java index a1427a9f3..c84e95607 100644 --- a/src/test/java/io/fabric8/maven/docker/config/LogConfigurationTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/run/LogConfigurationTest.java @@ -1,5 +1,6 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.run; +import io.fabric8.maven.docker.config.run.LogConfiguration; import org.junit.Test; import static org.junit.Assert.*; diff --git a/src/test/java/io/fabric8/maven/docker/config/NetworkingConfigTest.java b/src/test/java/io/fabric8/maven/docker/config/run/NetworkingConfigTest.java similarity index 81% rename from src/test/java/io/fabric8/maven/docker/config/NetworkingConfigTest.java rename to src/test/java/io/fabric8/maven/docker/config/run/NetworkingConfigTest.java index 580d76e44..b39d30589 100644 --- a/src/test/java/io/fabric8/maven/docker/config/NetworkingConfigTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/run/NetworkingConfigTest.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.run; /* * * Copyright 2016 Roland Huss @@ -22,7 +22,7 @@ import static org.junit.Assert.*; -import static io.fabric8.maven.docker.config.NetworkConfig.Mode.*; +import static io.fabric8.maven.docker.config.run.NetworkConfiguration.Mode.*; /** * @author roland @@ -41,9 +41,9 @@ public void simple() { none, null, "None", "none", "true", "false", null, null }; for (int i = 0; i < data.length; i += 8) { - for (NetworkConfig config : new NetworkConfig[]{ - new NetworkConfig((NetworkConfig.Mode) data[i],(String) data[i + 1]), - new NetworkConfig((String) data[i + 2])}) { + for (NetworkConfiguration config : new NetworkConfiguration[]{ + new NetworkConfiguration((NetworkConfiguration.Mode) data[i], (String) data[i + 1]), + new NetworkConfiguration((String) data[i + 2])}) { if (config.isStandardNetwork()) { assertEquals(data[i + 3], config.getStandardMode("containerId")); } else { @@ -65,7 +65,7 @@ public void simple() { @Test public void empty() { for (String str : new String[]{ null, "" }) { - NetworkConfig config = new NetworkConfig(str); + NetworkConfiguration config = new NetworkConfiguration(str); assertFalse(config.isStandardNetwork()); assertFalse(config.isCustomNetwork()); assertNull(config.getContainerAlias()); @@ -75,10 +75,10 @@ public void empty() { @Test public void builder() { - NetworkConfig config = new NetworkConfig.Builder().build(); + NetworkConfiguration config = new NetworkConfiguration.Builder().build(); assertNull(config); - config = new NetworkConfig.Builder().name("hello").aliases(Arrays.asList("alias1", "alias2")).build(); + config = new NetworkConfiguration.Builder().name("hello").aliases(Arrays.asList("alias1", "alias2")).build(); assertTrue(config.isCustomNetwork()); assertEquals("hello",config.getCustomNetwork()); assertEquals(2,config.getAliases().size()); diff --git a/src/test/java/io/fabric8/maven/docker/config/run/RunConfigurationTest.java b/src/test/java/io/fabric8/maven/docker/config/run/RunConfigurationTest.java new file mode 100644 index 000000000..9168bcc8e --- /dev/null +++ b/src/test/java/io/fabric8/maven/docker/config/run/RunConfigurationTest.java @@ -0,0 +1,49 @@ +package io.fabric8.maven.docker.config.run; + +import java.util.List; + +import org.junit.Test; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author roland + * @since 19.10.18 + */ +public class RunConfigurationTest { + + + @Test + public void splitAtCommas() { + List data[] = new List[] { + asList("db,postgres:9:db", "postgres:db"), asList("db", "postgres:9:db", "postgres:db"), + asList("a1,b2,,c3", null, "m4 , m9", null), asList("a1", "b2", "c3", "m4", "m9"), + asList(",,, ,,,, , ,,, ,", ", ,,, , , ,, a"), asList("a") + }; + + for (int i = 0; i < data.length; i += 2) { + RunConfiguration config = prepareWithLinks(data[i]); + assertThat(config.getLinks()).containsExactly((String[]) data[i + 1].toArray()); + } + } + + @Test + public void splitAtCommasEmpty() { + assertThat(prepareWithLinks().getLinks()).isEmpty(); + assertThat(prepareWithLinks("").getLinks()).isEmpty(); + assertThat(new RunConfiguration.Builder().build().getLinks()).isEmpty(); + } + + + private RunConfiguration prepareWithLinks(String ... links) { + return prepareWithLinks(asList(links)); + } + + private RunConfiguration prepareWithLinks(List links) { + return new RunConfiguration.Builder() + .links(links) + .build(); + } + +} diff --git a/src/test/java/io/fabric8/maven/docker/config/UlimitConfigTest.java b/src/test/java/io/fabric8/maven/docker/config/run/UlimitConfigurationTest.java similarity index 88% rename from src/test/java/io/fabric8/maven/docker/config/UlimitConfigTest.java rename to src/test/java/io/fabric8/maven/docker/config/run/UlimitConfigurationTest.java index e68e800bf..afd2a08d9 100644 --- a/src/test/java/io/fabric8/maven/docker/config/UlimitConfigTest.java +++ b/src/test/java/io/fabric8/maven/docker/config/run/UlimitConfigurationTest.java @@ -1,4 +1,4 @@ -package io.fabric8.maven.docker.config; +package io.fabric8.maven.docker.config.run; /* * * Copyright 2016 Roland Huss @@ -24,7 +24,7 @@ * @author roland * @since 19/07/16 */ -public class UlimitConfigTest { +public class UlimitConfigurationTest { @Test public void simple() { @@ -36,7 +36,7 @@ public void simple() { }; for (int i = 0; i < data.length; i+=4) { - UlimitConfig config = new UlimitConfig(data[0].toString()); + UlimitConfiguration config = new UlimitConfiguration(data[0].toString()); assertEquals(data[1], config.getName()); assertEquals(data[2], config.getHard()); assertEquals(data[3], config.getSoft()); @@ -52,7 +52,7 @@ public void illegalFormat() { for (String test : data) { try { - new UlimitConfig(test); + new UlimitConfiguration(test); fail(); } catch (IllegalArgumentException exp) { // expected @@ -70,7 +70,7 @@ public void invalidNumber() { for (String test : data) { try { - new UlimitConfig(test); + new UlimitConfiguration(test); fail(); } catch (NumberFormatException exp) { // expected diff --git a/src/test/java/io/fabric8/maven/docker/log/LogOutputSpecFactoryTest.java b/src/test/java/io/fabric8/maven/docker/log/LogOutputSpecFactoryTest.java index 2e18a3115..7fad34c21 100644 --- a/src/test/java/io/fabric8/maven/docker/log/LogOutputSpecFactoryTest.java +++ b/src/test/java/io/fabric8/maven/docker/log/LogOutputSpecFactoryTest.java @@ -4,8 +4,8 @@ import java.util.Collection; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.LogConfiguration; -import io.fabric8.maven.docker.config.RunImageConfiguration; +import io.fabric8.maven.docker.config.run.LogConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -50,7 +50,7 @@ public void prefix() { private LogOutputSpec createSpec(String prefix) { LogOutputSpecFactory factory = new LogOutputSpecFactory(false, false, null); LogConfiguration logConfig = new LogConfiguration.Builder().prefix(prefix).build(); - RunImageConfiguration runConfig = new RunImageConfiguration.Builder().log(logConfig).build(); + RunConfiguration runConfig = new RunConfiguration.Builder().log(logConfig).build(); ImageConfiguration imageConfiguration = new ImageConfiguration.Builder().alias(ALIAS).name(NAME).runConfig(runConfig).build(); return factory.createSpec(CONTAINER_ID,imageConfiguration); } diff --git a/src/test/java/io/fabric8/maven/docker/service/ContainerTrackerTest.java b/src/test/java/io/fabric8/maven/docker/service/ContainerTrackerTest.java index 98688dfd5..046809afc 100644 --- a/src/test/java/io/fabric8/maven/docker/service/ContainerTrackerTest.java +++ b/src/test/java/io/fabric8/maven/docker/service/ContainerTrackerTest.java @@ -18,10 +18,10 @@ import java.util.*; -import io.fabric8.maven.docker.config.RunImageConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; import io.fabric8.maven.docker.util.GavLabel; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.WaitConfiguration; +import io.fabric8.maven.docker.config.run.WaitConfiguration; import org.junit.Before; import org.junit.Test; @@ -169,7 +169,7 @@ private ImageConfiguration getImageConfiguration(String name, String alias, int return new ImageConfiguration.Builder() .name(name) .alias(alias) - .runConfig(new RunImageConfiguration.Builder() + .runConfig(new RunConfiguration.Builder() .wait(waitConfig) .build()) .build(); diff --git a/src/test/java/io/fabric8/maven/docker/service/LoadImageTest.java b/src/test/java/io/fabric8/maven/docker/service/LoadImageTest.java index a8cf53db0..a5805eb60 100644 --- a/src/test/java/io/fabric8/maven/docker/service/LoadImageTest.java +++ b/src/test/java/io/fabric8/maven/docker/service/LoadImageTest.java @@ -1,28 +1,30 @@ package io.fabric8.maven.docker.service; import java.io.File; +import java.io.IOException; import java.util.Collections; import io.fabric8.maven.docker.access.DockerAccess; import io.fabric8.maven.docker.access.DockerAccessException; -import io.fabric8.maven.docker.config.BuildImageConfiguration; -import io.fabric8.maven.docker.config.ConfigHelper; +import io.fabric8.maven.docker.build.docker.DockerBuildService; +import io.fabric8.maven.docker.build.docker.DockerRegistryService; +import io.fabric8.maven.docker.build.maven.MavenArchiveService; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; +import io.fabric8.maven.docker.config.build.BuildConfiguration; import io.fabric8.maven.docker.config.ImageConfiguration; import io.fabric8.maven.docker.util.Logger; -import io.fabric8.maven.docker.util.MojoParameters; import mockit.Expectations; import mockit.Injectable; import mockit.Mocked; import mockit.Tested; import mockit.Verifications; -import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.junit.Test; public class LoadImageTest { @Tested - private BuildService buildService; + private DockerBuildService buildService; @Injectable private DockerAccess docker; @@ -36,33 +38,32 @@ public class LoadImageTest { private MavenProject project; @Mocked - private MojoParameters params; + private MavenBuildContext buildContext; @Injectable private QueryService queryService; @Injectable - private ArchiveService archiveService; + private MavenArchiveService archiveService; @Injectable - private RegistryService registryService; + private DockerRegistryService registryService; private String dockerArchive; @Test - public void testLoadImage() throws DockerAccessException, MojoExecutionException { - givenMojoParameters(); + public void testLoadImage() throws IOException { + givenBuildContext(); givenAnImageConfiguration(); givenDockerArchive("test.tar"); whenBuildImage(); thenImageIsBuilt(); } - private void givenMojoParameters() { + private void givenBuildContext() { new Expectations() {{ - params.getProject(); - project.getBasedir(); result = "/maven-project"; - params.getSourceDirectory(); result = "src/main/docker"; + buildContext.getBasedir(); result = "/maven-project"; + buildContext.getSourceDirectory();result = "src/main/docker"; }}; } @@ -71,7 +72,7 @@ private void givenDockerArchive(String s) { } private void givenAnImageConfiguration() { - BuildImageConfiguration buildConfig = new BuildImageConfiguration.Builder() + BuildConfiguration buildConfig = new BuildConfiguration.Builder() .dockerArchive("test.tar") .build(); @@ -80,11 +81,11 @@ private void givenAnImageConfiguration() { .alias("build-alias") .buildConfig(buildConfig) .build(); - imageConfig.initAndValidate(ConfigHelper.NameFormatter.IDENTITY,log); + imageConfig.validate(ImageConfiguration.NameFormatter.IDENTITY); } - private void whenBuildImage() throws DockerAccessException, MojoExecutionException { - buildService.buildImage(imageConfig, params, false, Collections.emptyMap()); + private void whenBuildImage() throws IOException { + buildService.buildImage(imageConfig, buildContext, Collections.emptyMap()); } private void thenImageIsBuilt() throws DockerAccessException { diff --git a/src/test/java/io/fabric8/maven/docker/service/RunServiceTest.java b/src/test/java/io/fabric8/maven/docker/service/RunServiceTest.java index baf5be0f2..f8d22c93f 100644 --- a/src/test/java/io/fabric8/maven/docker/service/RunServiceTest.java +++ b/src/test/java/io/fabric8/maven/docker/service/RunServiceTest.java @@ -2,7 +2,7 @@ import com.google.gson.JsonObject; -import io.fabric8.maven.docker.config.VolumeConfiguration; +import io.fabric8.maven.docker.config.run.VolumeConfiguration; import org.apache.commons.io.IOUtils; import org.apache.maven.execution.MavenSession; import org.apache.maven.project.MavenProject; @@ -13,6 +13,7 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.Field; +import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -25,14 +26,14 @@ import io.fabric8.maven.docker.access.DockerAccess; import io.fabric8.maven.docker.access.DockerAccessException; import io.fabric8.maven.docker.access.PortMapping; -import io.fabric8.maven.docker.config.Arguments; +import io.fabric8.maven.docker.config.build.Arguments; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.NetworkConfig; -import io.fabric8.maven.docker.config.RestartPolicy; -import io.fabric8.maven.docker.config.RunImageConfiguration; -import io.fabric8.maven.docker.config.RunVolumeConfiguration; -import io.fabric8.maven.docker.config.UlimitConfig; -import io.fabric8.maven.docker.config.WaitConfiguration; +import io.fabric8.maven.docker.config.run.NetworkConfiguration; +import io.fabric8.maven.docker.config.run.RestartPolicy; +import io.fabric8.maven.docker.config.run.RunConfiguration; +import io.fabric8.maven.docker.config.run.RunVolumeConfiguration; +import io.fabric8.maven.docker.config.run.UlimitConfiguration; +import io.fabric8.maven.docker.config.run.WaitConfiguration; import io.fabric8.maven.docker.log.LogOutputSpec; import io.fabric8.maven.docker.log.LogOutputSpecFactory; import io.fabric8.maven.docker.util.JsonFactory; @@ -68,7 +69,7 @@ public class RunServiceTest { private Properties properties; - private RunImageConfiguration runConfig; + private RunConfiguration runConfig; private RunService runService; @@ -232,7 +233,7 @@ public void shutdownWithKeepingContainer() throws Exception { public void shutdownWithPreStopExecConfig() throws Exception { new Expectations() {{ - docker.createExecContainer(container, (Arguments) withNotNull());result = "execContainerId"; + docker.createExecContainer(container, withNotNull());result = "execContainerId"; docker.startExecContainer("execContainerId", (LogOutputSpec) any); docker.stopContainer(container, 0); log.info(withSubstring("Stop"), @@ -291,7 +292,7 @@ private ImageConfiguration createImageConfig(int wait, int kill) { return new ImageConfiguration.Builder() .name("test_name") .alias("testAlias") - .runConfig(new RunImageConfiguration.Builder() + .runConfig(new RunConfiguration.Builder() .wait(new WaitConfiguration.Builder() .shutdown(wait) .kill(kill) @@ -304,7 +305,7 @@ private ImageConfiguration createImageConfigWithExecConfig(int wait) { return new ImageConfiguration.Builder() .name("test_name") .alias("testAlias") - .runConfig(new RunImageConfiguration.Builder() + .runConfig(new RunConfiguration.Builder() .wait(new WaitConfiguration.Builder() .shutdown(wait) .preStop("pre-stop-command") @@ -329,7 +330,7 @@ private void givenAnImageConfiguration(String name, String alias, String contain private void givenARunConfiguration() { runConfig = - new RunImageConfiguration.Builder() + new RunConfiguration.Builder() .hostname("hostname") .domainname("domain.com") .user("user") @@ -355,14 +356,13 @@ private void givenARunConfiguration() { .capDrop(capDrop()) .securityOpts(securityOpts()) .restartPolicy(restartPolicy()) - .net("custom_network") .network(networkConfiguration()) .readOnly(false) .build(); } - private NetworkConfig networkConfiguration() { - NetworkConfig config = new NetworkConfig("custom_network"); + private NetworkConfiguration networkConfiguration() { + NetworkConfiguration config = new NetworkConfiguration("custom_network"); config.addAlias("net-alias"); return config; } @@ -413,8 +413,8 @@ private Map env() { return env; } - private List ulimits(){ - return Collections.singletonList(new UlimitConfig("memlock=1024:2048")); + private List ulimits(){ + return Collections.singletonList(new UlimitConfiguration("memlock=1024:2048")); } private List extraHosts() { @@ -426,7 +426,7 @@ private List links() { } private String loadFile(String fileName) throws IOException { - return IOUtils.toString(getClass().getClassLoader().getResource(fileName)); + return IOUtils.toString(getClass().getClassLoader().getResource(fileName), Charset.defaultCharset()); } private File getBaseDirectory() { diff --git a/src/test/java/io/fabric8/maven/docker/service/VolumeServiceTest.java b/src/test/java/io/fabric8/maven/docker/service/VolumeServiceTest.java index e55d1f106..ed9e598fd 100644 --- a/src/test/java/io/fabric8/maven/docker/service/VolumeServiceTest.java +++ b/src/test/java/io/fabric8/maven/docker/service/VolumeServiceTest.java @@ -10,7 +10,7 @@ import io.fabric8.maven.docker.access.DockerAccess; import io.fabric8.maven.docker.access.VolumeCreateConfig; -import io.fabric8.maven.docker.config.VolumeConfiguration; +import io.fabric8.maven.docker.config.run.VolumeConfiguration; import io.fabric8.maven.docker.util.JsonFactory; import mockit.Delegate; import mockit.Expectations; diff --git a/src/test/java/io/fabric8/maven/docker/service/helper/StartContainerExecutorTest.java b/src/test/java/io/fabric8/maven/docker/service/helper/StartContainerExecutorTest.java index 9fdd16041..4d39b833e 100644 --- a/src/test/java/io/fabric8/maven/docker/service/helper/StartContainerExecutorTest.java +++ b/src/test/java/io/fabric8/maven/docker/service/helper/StartContainerExecutorTest.java @@ -1,10 +1,10 @@ package io.fabric8.maven.docker.service.helper; +import io.fabric8.maven.docker.config.run.LogConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; import org.junit.Test; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.LogConfiguration; -import io.fabric8.maven.docker.config.RunImageConfiguration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -38,7 +38,7 @@ public void getExposedPropertyKeyPart_withoutRunConfig() { public void getExposedPropertyKeyPart_withRunConfig() { // Given - final RunImageConfiguration runConfig = new RunImageConfiguration.Builder() + final RunConfiguration runConfig = new RunConfiguration.Builder() .exposedPropertyKey("key") .build(); @@ -85,7 +85,7 @@ public void showLogs_withoutRunConfig() { public void showLogs_withoutLogConfigButFollowTrue() { // Given - final RunImageConfiguration runConfig = new RunImageConfiguration.Builder() + final RunConfiguration runConfig = new RunConfiguration.Builder() .exposedPropertyKey("key") .build(); @@ -116,7 +116,7 @@ public void showLogs_withLogConfigDisabled() { .enabled(false) .build(); - final RunImageConfiguration runConfig = new RunImageConfiguration.Builder() + final RunConfiguration runConfig = new RunConfiguration.Builder() .exposedPropertyKey("key") .log(logConfig) .build(); @@ -147,7 +147,7 @@ public void showLogs_withLogConfigEnabled() { .enabled(true) .build(); - final RunImageConfiguration runConfig = new RunImageConfiguration.Builder() + final RunConfiguration runConfig = new RunConfiguration.Builder() .exposedPropertyKey("key") .log(logConfig) .build(); diff --git a/src/test/java/io/fabric8/maven/docker/util/AuthConfigFactoryTest.java b/src/test/java/io/fabric8/maven/docker/util/AuthConfigFactoryTest.java deleted file mode 100644 index 198e22031..000000000 --- a/src/test/java/io/fabric8/maven/docker/util/AuthConfigFactoryTest.java +++ /dev/null @@ -1,476 +0,0 @@ -package io.fabric8.maven.docker.util; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import io.fabric8.maven.docker.access.AuthConfig; -import mockit.Expectations; -import mockit.Mock; -import mockit.Mocked; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.settings.Server; -import org.apache.maven.settings.Settings; -import org.codehaus.plexus.PlexusContainer; -import org.codehaus.plexus.component.repository.exception.ComponentLookupException; -import org.codehaus.plexus.util.Base64; -import org.codehaus.plexus.util.IOUtil; -import org.codehaus.plexus.util.xml.Xpp3Dom; -import org.hamcrest.Matchers; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; - -import static java.util.Collections.singletonMap; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -/** - * @author roland - * @since 29.07.14 - */ - -public class AuthConfigFactoryTest { - - public static final String ECR_NAME = "123456789012.dkr.ecr.bla.amazonaws.com"; - - @Mocked - Settings settings; - - @Mocked - private Logger log; - - private AuthConfigFactory factory; - - private boolean isPush = true; - - private Gson gson; - - public static final class MockSecDispatcher implements SecDispatcher { - @Mock - public String decrypt(String password) { - return password; - } - } - - @Mocked - PlexusContainer container; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Before - public void containerSetup() throws ComponentLookupException { - final SecDispatcher secDispatcher = new MockSecDispatcher(); - new Expectations() {{ - container.lookup(SecDispatcher.ROLE, "maven"); minTimes = 0; result = secDispatcher; - - }}; - factory = new AuthConfigFactory(container); - factory.setLog(log); - - gson = new Gson(); - } - - @Test - public void testEmpty() throws Exception { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - assertNull(factory.createAuthConfig(isPush,false,null,settings,null,"blubberbla:1611")); - } - }); - } - - @Test - public void testSystemProperty() throws Exception { - System.setProperty("docker.push.username","roland"); - System.setProperty("docker.push.password", "secret"); - System.setProperty("docker.push.email", "roland@jolokia.org"); - try { - AuthConfig config = factory.createAuthConfig(true, false, null, settings, null, null); - verifyAuthConfig(config,"roland","secret","roland@jolokia.org"); - } finally { - System.clearProperty("docker.push.username"); - System.clearProperty("docker.push.password"); - System.clearProperty("docker.push.email"); - } - } - - - @Test - public void testDockerAuthLogin() throws Exception { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - checkDockerAuthLogin(homeDir,AuthConfigFactory.DOCKER_LOGIN_DEFAULT_REGISTRY,null); - checkDockerAuthLogin(homeDir,"localhost:5000","localhost:5000"); - checkDockerAuthLogin(homeDir,"https://localhost:5000","localhost:5000"); - } - }); - } - - @Test - public void testDockerLoginNoConfig() throws MojoExecutionException, IOException { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File dir) throws IOException, MojoExecutionException { - AuthConfig config = factory.createAuthConfig(isPush, false, null, settings, "roland", null); - assertNull(config); - } - }); - } - - @Test - public void testDockerLoginFallsBackToAuthWhenCredentialHelperDoesNotMatchDomain() throws MojoExecutionException, IOException { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - writeDockerConfigJson(createDockerConfig(homeDir),null,singletonMap("registry1", "credHelper1-does-not-exist")); - AuthConfig config = factory.createAuthConfig(isPush,false,null,settings,"roland","localhost:5000"); - verifyAuthConfig(config,"roland","secret","roland@jolokia.org"); - } - }); - } - - @Test - public void testDockerLoginNoAuthConfigFoundWhenCredentialHelperDoesNotMatchDomainOrAuth() throws MojoExecutionException, IOException { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - writeDockerConfigJson(createDockerConfig(homeDir),null,singletonMap("registry1", "credHelper1-does-not-exist")); - AuthConfig config = factory.createAuthConfig(isPush,false,null,settings,"roland","does-not-exist-either:5000"); - assertNull(config); - } - }); - } - - @Test - public void testDockerLoginSelectCredentialHelper() throws MojoExecutionException, IOException { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - writeDockerConfigJson(createDockerConfig(homeDir),"credsStore-does-not-exist",singletonMap("registry1", "credHelper1-does-not-exist")); - expectedException.expect(MojoExecutionException.class); - expectedException.expectCause(Matchers.allOf( - instanceOf(IOException.class), - hasProperty("message",startsWith("Failed to start 'docker-credential-credHelper1-does-not-exist version'")) - )); - factory.createAuthConfig(isPush,false,null,settings,"roland","registry1"); - } - }); - } - - @Test - public void testDockerLoginSelectCredentialsStore() throws MojoExecutionException, IOException { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - writeDockerConfigJson(createDockerConfig(homeDir),"credsStore-does-not-exist",singletonMap("registry1", "credHelper1-does-not-exist")); - expectedException.expect(MojoExecutionException.class); - expectedException.expectCause(Matchers.allOf( - instanceOf(IOException.class), - hasProperty("message",startsWith("Failed to start 'docker-credential-credsStore-does-not-exist version'")) - )); - factory.createAuthConfig(isPush,false,null,settings,"roland",null); - } - }); - } - - @Test - public void testDockerLoginDefaultToCredentialsStore() throws MojoExecutionException, IOException { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - writeDockerConfigJson(createDockerConfig(homeDir),"credsStore-does-not-exist",singletonMap("registry1", "credHelper1-does-not-exist")); - expectedException.expect(MojoExecutionException.class); - expectedException.expectCause(Matchers.allOf( - instanceOf(IOException.class), - hasProperty("message",startsWith("Failed to start 'docker-credential-credsStore-does-not-exist version'")) - )); - factory.createAuthConfig(isPush,false,null,settings,"roland","registry2"); - } - }); - } - - private void executeWithTempHomeDir(HomeDirExecutor executor) throws IOException, MojoExecutionException { - String userHome = System.getProperty("user.home"); - try { - File tempDir = Files.createTempDirectory("d-m-p").toFile(); - System.setProperty("user.home", tempDir.getAbsolutePath()); - executor.exec(tempDir); - } finally { - System.setProperty("user.home",userHome); - } - - } - - interface HomeDirExecutor { - void exec(File dir) throws IOException, MojoExecutionException; - } - - private void checkDockerAuthLogin(File homeDir,String configRegistry,String lookupRegistry) - throws IOException, MojoExecutionException { - writeDockerConfigJson(createDockerConfig(homeDir), "roland", "secret", "roland@jolokia.org", configRegistry); - AuthConfig config = factory.createAuthConfig(isPush, false, null, settings, "roland", lookupRegistry); - verifyAuthConfig(config,"roland","secret","roland@jolokia.org"); - } - - private File createDockerConfig(File homeDir) - throws IOException { - File dockerDir = new File(homeDir,".docker"); - dockerDir.mkdirs(); - return dockerDir; - } - - private void writeDockerConfigJson(File dockerDir, String user, String password, - String email, String registry) throws IOException { - File configFile = new File(dockerDir,"config.json"); - - JsonObject config = new JsonObject(); - addAuths(config,user,password,email,registry); - - try (Writer writer = new FileWriter(configFile)){ - gson.toJson(config, writer); - } - } - - private void writeDockerConfigJson(File dockerDir,String credsStore,Map credHelpers) throws IOException { - File configFile = new File(dockerDir,"config.json"); - - JsonObject config = new JsonObject(); - if (!credHelpers.isEmpty()){ - config.add("credHelpers", JsonFactory.newJsonObject(credHelpers)); - } - - if (credsStore!=null) { - config.addProperty("credsStore",credsStore); - } - - addAuths(config,"roland","secret","roland@jolokia.org", "localhost:5000"); - - try (Writer writer = new FileWriter(configFile)){ - gson.toJson(config, writer); - } - } - - private void addAuths(JsonObject config,String user,String password,String email,String registry) { - JsonObject auths = new JsonObject(); - JsonObject value = new JsonObject(); - value.addProperty("auth", new String(Base64.encodeBase64((user + ":" + password).getBytes()))); - value.addProperty("email",email); - auths.add(registry, value); - config.add("auths",auths); - } - - @Test - public void testOpenShiftConfigFromPluginConfig() throws Exception { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - createOpenShiftConfig(homeDir,"openshift_simple_config.yaml"); - Map authConfigMap = new HashMap<>(); - authConfigMap.put("useOpenShiftAuth","true"); - AuthConfig config = factory.createAuthConfig(isPush, false, authConfigMap, settings, "roland", null); - verifyAuthConfig(config,"admin","token123",null); - } - }); - } - - @Test - public void testOpenShiftConfigFromSystemProps() throws Exception { - try { - System.setProperty("docker.useOpenShiftAuth","true"); - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - createOpenShiftConfig(homeDir, "openshift_simple_config.yaml"); - AuthConfig config = factory.createAuthConfig(isPush, false, null, settings, "roland", null); - verifyAuthConfig(config, "admin", "token123", null); - } - }); - } finally { - System.getProperties().remove("docker.useOpenShiftAuth"); - } - } - - @Test - public void testOpenShiftConfigFromSystemPropsNegative() throws Exception { - try { - System.setProperty("docker.useOpenShiftAuth","false"); - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - createOpenShiftConfig(homeDir, "openshift_simple_config.yaml"); - Map authConfigMap = new HashMap<>(); - authConfigMap.put("useOpenShiftAuth","true"); - AuthConfig config = factory.createAuthConfig(isPush, false, authConfigMap, settings, "roland", null); - assertNull(config); - } - }); - } finally { - System.getProperties().remove("docker.useOpenShiftAuth"); - } - } - - @Test - public void testOpenShiftConfigNotLoggedIn() throws Exception { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - createOpenShiftConfig(homeDir,"openshift_nologin_config.yaml"); - Map authConfigMap = new HashMap<>(); - authConfigMap.put("useOpenShiftAuth","true"); - expectedException.expect(MojoExecutionException.class); - expectedException.expectMessage(containsString("~/.kube/config")); - factory.createAuthConfig(isPush,false,authConfigMap,settings,"roland",null); - } - }); - - } - - private void createOpenShiftConfig(File homeDir,String testConfig) throws IOException { - File kubeDir = new File(homeDir,".kube"); - kubeDir.mkdirs(); - File config = new File(kubeDir,"config"); - IOUtil.copy(getClass().getResourceAsStream(testConfig),new FileWriter(config)); - } - - @Test - public void testSystemPropertyNoPassword() throws Exception { - expectedException.expect(MojoExecutionException.class); - expectedException.expectMessage("No docker.password provided for username secret"); - checkException("docker.username"); - } - - private void checkException(String key) throws MojoExecutionException { - System.setProperty(key, "secret"); - try { - factory.createAuthConfig(isPush, false, null, settings, null, null); - } finally { - System.clearProperty(key); - } - } - - @Test - public void testFromPluginConfiguration() throws MojoExecutionException { - Map pluginConfig = new HashMap(); - pluginConfig.put("username", "roland"); - pluginConfig.put("password", "secret"); - pluginConfig.put("email", "roland@jolokia.org"); - - AuthConfig config = factory.createAuthConfig(isPush, false, pluginConfig, settings, null, null); - verifyAuthConfig(config, "roland", "secret", "roland@jolokia.org"); - } - - @Test - public void testFromPluginConfigurationPull() throws MojoExecutionException { - Map pullConfig = new HashMap(); - pullConfig.put("username", "roland"); - pullConfig.put("password", "secret"); - pullConfig.put("email", "roland@jolokia.org"); - Map pluginConfig = new HashMap(); - pluginConfig.put("pull",pullConfig); - AuthConfig config = factory.createAuthConfig(false, false, pluginConfig, settings, null, null); - verifyAuthConfig(config, "roland", "secret", "roland@jolokia.org"); - } - - - @Test - public void testFromPluginConfigurationFailed() throws MojoExecutionException { - Map pluginConfig = new HashMap(); - pluginConfig.put("username","admin"); - expectedException.expect(MojoExecutionException.class); - expectedException.expectMessage("No 'password' given while using in configuration for mode DEFAULT"); - factory.createAuthConfig(isPush,false,pluginConfig,settings,null,null); - } - - @Test - public void testFromSettingsSimple() throws MojoExecutionException { - setupServers(); - AuthConfig config = factory.createAuthConfig(isPush, false, null, settings, "roland", "test.org"); - assertNotNull(config); - verifyAuthConfig(config, "roland", "secret", "roland@jolokia.org"); - } - - @Test - public void testFromSettingsDefault() throws MojoExecutionException { - setupServers(); - AuthConfig config = factory.createAuthConfig(isPush, false, null, settings, "fabric8io", "test.org"); - assertNotNull(config); - verifyAuthConfig(config, "fabric8io", "secret2", "fabric8io@redhat.com"); - } - - @Test - public void testFromSettingsDefault2() throws MojoExecutionException { - setupServers(); - AuthConfig config = factory.createAuthConfig(isPush, false, null, settings, "tanja", null); - assertNotNull(config); - verifyAuthConfig(config,"tanja","doublesecret","tanja@jolokia.org"); - } - - @Test - public void testWrongUserName() throws IOException, MojoExecutionException { - executeWithTempHomeDir(new HomeDirExecutor() { - @Override - public void exec(File homeDir) throws IOException, MojoExecutionException { - setupServers(); - assertNull(factory.createAuthConfig(isPush,false,null,settings,"roland","another.repo.org")); - } - }); - } - - - private void setupServers() { - new Expectations() {{ - List servers = new ArrayList<>(); - - servers.add(create(ECR_NAME, "roland", "secret", "roland@jolokia.org")); - servers.add(create("test.org", "fabric8io", "secret2", "fabric8io@redhat.com")); - servers.add(create("test.org/roland", "roland", "secret", "roland@jolokia.org")); - servers.add(create("docker.io", "tanja", "doublesecret", "tanja@jolokia.org")); - servers.add(create("another.repo.org/joe", "joe", "3secret", "joe@foobar.com")); - settings.getServers(); - result = servers; - } - - private Server create(String id, String user, String password, String email) { - Server server = new Server(); - server.setId(id); - server.setUsername(user); - server.setPassword(password); - Xpp3Dom dom = new Xpp3Dom("configuration"); - Xpp3Dom emailD = new Xpp3Dom("email"); - emailD.setValue(email); - dom.addChild(emailD); - server.setConfiguration(dom); - return server; - } - }; - } - - private void verifyAuthConfig(AuthConfig config, String username, String password, String email) { - JsonObject params = gson.fromJson(new String(Base64.decodeBase64(config.toHeaderValue().getBytes())), JsonObject.class); - assertEquals(username,params.get("username").getAsString()); - assertEquals(password,params.get("password").getAsString()); - if (email != null) { - assertEquals(email, params.get("email").getAsString()); - } - } - -} diff --git a/src/test/java/io/fabric8/maven/docker/util/ContainerNamingUtilTest.java b/src/test/java/io/fabric8/maven/docker/util/ContainerNamingUtilTest.java index 20eab4b8e..1654fa9f5 100644 --- a/src/test/java/io/fabric8/maven/docker/util/ContainerNamingUtilTest.java +++ b/src/test/java/io/fabric8/maven/docker/util/ContainerNamingUtilTest.java @@ -6,7 +6,7 @@ import java.util.Date; import io.fabric8.maven.docker.config.ImageConfiguration; -import io.fabric8.maven.docker.config.RunImageConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; import io.fabric8.maven.docker.model.Container; import mockit.Expectations; import mockit.Mocked; @@ -120,7 +120,7 @@ public void testContainersToStop() { private ImageConfiguration imageConfiguration(String name, String alias, String containerNamePattern) { ImageConfiguration.Builder builder = new ImageConfiguration.Builder().name(name).alias(alias); if (containerNamePattern != null) { - RunImageConfiguration runConfig = new RunImageConfiguration.Builder().containerNamePattern(containerNamePattern).build(); + RunConfiguration runConfig = new RunConfiguration.Builder().containerNamePattern(containerNamePattern).build(); builder.runConfig(runConfig); } return builder.build(); diff --git a/src/test/java/io/fabric8/maven/docker/util/DockerFileUtilTest.java b/src/test/java/io/fabric8/maven/docker/util/DockerFileUtilTest.java index ff245c641..03aea7766 100644 --- a/src/test/java/io/fabric8/maven/docker/util/DockerFileUtilTest.java +++ b/src/test/java/io/fabric8/maven/docker/util/DockerFileUtilTest.java @@ -16,6 +16,7 @@ */ import java.io.*; +import java.nio.charset.Charset; import java.nio.file.Files; import java.util.Collections; import java.util.Date; @@ -23,6 +24,7 @@ import java.util.Map; import java.util.Properties; +import io.fabric8.maven.docker.build.maven.MavenBuildContext; import org.apache.commons.io.FileUtils; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.MavenArtifactRepository; @@ -33,9 +35,6 @@ import org.codehaus.plexus.util.IOUtil; import org.junit.Test; -import mockit.Mock; -import mockit.MockUp; - import static io.fabric8.maven.docker.util.PathTestUtil.createTmpFile; import static org.junit.Assert.assertEquals; @@ -49,7 +48,7 @@ public class DockerFileUtilTest { public void testSimple() throws Exception { File toTest = copyToTempDir("Dockerfile_from_simple"); assertEquals("fabric8/s2i-java", DockerFileUtil.extractBaseImage( - toTest, FixedStringSearchInterpolator.create())); + toTest, s -> FixedStringSearchInterpolator.create().interpolate(s))); } private File copyToTempDir(String resource) throws IOException { @@ -63,7 +62,8 @@ private File copyToTempDir(String resource) throws IOException { @Test public void interpolate() throws Exception { - MojoParameters params = mockMojoParams(); + MavenBuildContext buildContext = mockMavenBuildContext(); + Map filterMapping = new HashMap<>(); filterMapping.put("none", "false"); filterMapping.put("var", "${*}"); @@ -74,10 +74,11 @@ public void interpolate() throws Exception { File dockerFile = getDockerfilePath(i, entry.getKey()); File expectedDockerFile = new File(dockerFile.getParent(), dockerFile.getName() + ".expected"); File actualDockerFile = createTmpFile(dockerFile.getName()); - FixedStringSearchInterpolator interpolator = DockerFileUtil.createInterpolator(params, entry.getValue()); + FixedStringSearchInterpolator interpolator = DockerFileUtil.createInterpolator(buildContext, entry.getValue()); FileUtils.write(actualDockerFile, DockerFileUtil.interpolate(dockerFile, interpolator), "UTF-8"); // Compare text lines without regard to EOL delimiters - assertEquals(FileUtils.readLines(expectedDockerFile), FileUtils.readLines(actualDockerFile)); + assertEquals(FileUtils.readLines(expectedDockerFile, Charset.defaultCharset()), + FileUtils.readLines(actualDockerFile, Charset.defaultCharset())); } } } @@ -88,7 +89,7 @@ private File getDockerfilePath(int i, String dir) { String.format("interpolate/%s/Dockerfile_%d", dir, i)).getFile()); } - private MojoParameters mockMojoParams() { + private MavenBuildContext mockMavenBuildContext() { MavenProject project = new MavenProject(); project.setArtifactId("docker-maven-plugin"); @@ -105,9 +106,17 @@ public String getBasedir() { } }; @SuppressWarnings("deprecation") - MavenSession session = new MavenSession(null, settings, localRepository, null, null, Collections.emptyList(), ".", null, null, new Date(System.currentTimeMillis())); + MavenSession session = new MavenSession(null, settings, localRepository, null, null, Collections.emptyList(), ".", null, null, new Date(System.currentTimeMillis())); session.getUserProperties().setProperty("cliOverride", "cliValue"); // Maven CLI override: -DcliOverride=cliValue session.getSystemProperties().put("user.name", "somebody"); // Java system property: -Duser.name=somebody - return new MojoParameters(session, project, null, null, null, settings, "src", "target", Collections.singletonList(project)); + + return new MavenBuildContext.Builder() + .project(project) + .settings(settings) + .session(session) + .sourceDirectory("src") + .outputDirectory("target") + .reactorProjects(Collections.singletonList(project)) + .build(); } } diff --git a/src/test/java/io/fabric8/maven/docker/util/EnvUtilTest.java b/src/test/java/io/fabric8/maven/docker/util/EnvUtilTest.java index 1aa8d93c4..efe4c1050 100644 --- a/src/test/java/io/fabric8/maven/docker/util/EnvUtilTest.java +++ b/src/test/java/io/fabric8/maven/docker/util/EnvUtilTest.java @@ -38,42 +38,7 @@ public void splitPath() { assertFalse(it.hasNext()); } - @Test - public void removeEmptyEntries() { - assertEquals(ImmutableList.of("ein"), EnvUtil.removeEmptyEntries(Arrays.asList(null, "", " ein", " "))); - assertEquals(ImmutableList.of(), EnvUtil.removeEmptyEntries(null)); - } - - @Test - public void splitAtCommas() { - Iterable it = EnvUtil.splitAtCommasAndTrim(Arrays.asList("db,postgres:9:db", "postgres:db")); - Iterable expected = ImmutableList.of ("db", "postgres:9:db","postgres:db"); - assertTrue(Iterables.elementsEqual(it, expected)); - } - public void assertEmptyList(Iterable actual) { - assertTrue(Iterables.elementsEqual(Collections.emptyList(), actual)); - } - @Test - public void splitAtCommasEmpty() { - assertEmptyList(EnvUtil.splitAtCommasAndTrim(Collections.emptyList())); - } - - @Test - public void splitAtCommasSingleEmpty() { - assertEmptyList(EnvUtil.splitAtCommasAndTrim(Arrays.asList(""))); - } - - @Test - public void splitAtCommasNullList() { - assertEmptyList(EnvUtil.splitAtCommasAndTrim(null)); - } - - // null occurs when - @Test - public void splitAtCommasNullInList() { - assertEmptyList(EnvUtil.splitAtCommasAndTrim(Collections.singletonList(null))); - } @Test @TestCaseName("{method}: input \"{0}\" splits to {1}") @@ -175,14 +140,6 @@ public void fixupPath() throws Exception { } - @Test - public void isValidWindowsFileName() { - - assertFalse(EnvUtil.isValidWindowsFileName("/Dockerfile")); - assertTrue(EnvUtil.isValidWindowsFileName("Dockerfile")); - assertFalse(EnvUtil.isValidWindowsFileName("Dockerfile/")); - } - private Properties getTestProperties(String ... vals) { Properties ret = new Properties(); for (int i = 0; i < vals.length; i+=2) { diff --git a/src/test/java/io/fabric8/maven/docker/util/StartOrderResolverTest.java b/src/test/java/io/fabric8/maven/docker/util/StartOrderResolverTest.java index b38e50274..16776d6b2 100644 --- a/src/test/java/io/fabric8/maven/docker/util/StartOrderResolverTest.java +++ b/src/test/java/io/fabric8/maven/docker/util/StartOrderResolverTest.java @@ -2,13 +2,16 @@ import java.util.*; +import io.fabric8.maven.docker.config.ImageConfiguration; +import io.fabric8.maven.docker.config.run.RunConfiguration; import io.fabric8.maven.docker.service.QueryService; import mockit.Expectations; import mockit.Mocked; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; /** * @author roland @@ -18,7 +21,7 @@ public class StartOrderResolverTest { @Mocked private QueryService queryService; - + @Before @SuppressWarnings("unused") public void setup() throws Exception { @@ -28,7 +31,7 @@ public void setup() throws Exception { minTimes = 1; }}; } - + @Test public void simple() { checkData(new Object[][]{ @@ -48,17 +51,22 @@ public void circularDep() { private void checkData(Object[][] data) { for (Object[] aData : data) { - StartOrderResolver.Resolvable[] input = (StartOrderResolver.Resolvable[]) aData[0]; - StartOrderResolver.Resolvable[] expected = (StartOrderResolver.Resolvable[]) aData[1]; - List result = StartOrderResolver.resolve(queryService, Arrays.asList(input)); - assertArrayEquals(expected, new ArrayList(result).toArray()); + ImageConfiguration[] input = (ImageConfiguration[]) aData[0]; + ImageConfiguration[] expected = (ImageConfiguration[]) aData[1]; + List result = new StartOrderResolver(queryService).resolve(Arrays.asList(input)); + assertThat(result.size()).isEqualTo(expected.length); + for (int i = 0; i < expected.length; i++) { + assertThat(result.get(i).getName()).isEqualTo(expected[i].getName()); + assertThat(result.get(i).getRunConfiguration().getLinks()).containsExactly( + expected[i].getRunConfiguration().getLinks().toArray(new String[0])); + } } } // ============================================================================ - private static class T implements StartOrderResolver.Resolvable { + private static class T extends ImageConfiguration { private String id; private List deps; @@ -66,9 +74,7 @@ private static class T implements StartOrderResolver.Resolvable { private T(String id,String ... dep) { this.id = id; deps = new ArrayList<>(); - for (String d : dep) { - deps.add(d); - } + Collections.addAll(deps, dep); } @Override @@ -77,37 +83,13 @@ public String getName() { } @Override - public String getAlias() { - return null; - } - - @Override - public List getDependencies() { - return deps; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - T t = (T) o; - - if (id != null ? !id.equals(t.id) : t.id != null) return false; - - return true; - } - - @Override - public int hashCode() { - return id != null ? id.hashCode() : 0; - } - - @Override - public String toString() { - return "T{" + - "id='" + id + '\'' + - '}'; + public RunConfiguration getRunConfiguration() { + return new RunConfiguration() { + @Override + public List getLinks() { + return deps; + } + }; } } } diff --git a/src/test/java/io/fabric8/maven/docker/util/VolumeBindingUtilTest.java b/src/test/java/io/fabric8/maven/docker/util/VolumeBindingUtilTest.java index e19299a35..10f55f981 100644 --- a/src/test/java/io/fabric8/maven/docker/util/VolumeBindingUtilTest.java +++ b/src/test/java/io/fabric8/maven/docker/util/VolumeBindingUtilTest.java @@ -1,6 +1,6 @@ package io.fabric8.maven.docker.util; -import io.fabric8.maven.docker.config.RunVolumeConfiguration; +import io.fabric8.maven.docker.config.run.RunVolumeConfiguration; import org.junit.Ignore; import org.junit.Test; diff --git a/src/test/java/io/fabric8/maven/docker/util/WaitUtilTest.java b/src/test/java/io/fabric8/maven/docker/util/WaitUtilTest.java index d384e1bd1..f41b2ea79 100644 --- a/src/test/java/io/fabric8/maven/docker/util/WaitUtilTest.java +++ b/src/test/java/io/fabric8/maven/docker/util/WaitUtilTest.java @@ -10,7 +10,7 @@ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; -import io.fabric8.maven.docker.config.WaitConfiguration; +import io.fabric8.maven.docker.config.run.WaitConfiguration; import io.fabric8.maven.docker.wait.*; import org.junit.AfterClass; import org.junit.BeforeClass; diff --git a/src/test/resources/io/fabric8/maven/docker/util/openshift_nologin_config.yaml b/src/test/resources/io/fabric8/maven/docker/build/auth/openshift_nologin_config.yaml similarity index 100% rename from src/test/resources/io/fabric8/maven/docker/util/openshift_nologin_config.yaml rename to src/test/resources/io/fabric8/maven/docker/build/auth/openshift_nologin_config.yaml diff --git a/src/test/resources/io/fabric8/maven/docker/util/openshift_simple_config.yaml b/src/test/resources/io/fabric8/maven/docker/build/auth/openshift_simple_config.yaml similarity index 100% rename from src/test/resources/io/fabric8/maven/docker/util/openshift_simple_config.yaml rename to src/test/resources/io/fabric8/maven/docker/build/auth/openshift_simple_config.yaml