From 741d545e5dc73bbfeebb6264b990eacbfd858a07 Mon Sep 17 00:00:00 2001 From: Jae Gangemi Date: Mon, 11 Jul 2016 16:17:53 -0400 Subject: [PATCH] - add support for pulling an image once per (reactor) build Signed-off-by: Jae Gangemi --- doc/changelog.md | 113 ++++++------ doc/manual/global-configuration.md | 65 ++++--- .../maven/docker/AbstractDockerMojo.java | 20 ++- .../maven/docker/service/QueryService.java | 40 +++-- .../maven/docker/util/AutoPullMode.java | 21 ++- .../service/QueryServiceAutoPullTest.java | 168 ++++++++++++++++++ 6 files changed, 315 insertions(+), 112 deletions(-) create mode 100644 src/test/java/io/fabric8/maven/docker/service/QueryServiceAutoPullTest.java diff --git a/doc/changelog.md b/doc/changelog.md index 5f5a861bb..84cf498af 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -2,15 +2,16 @@ * **0.15-SNAPSHOT** - Dont do redirect when waiting on an HTTP port (#499) + - Allow images to only be pulled once per build (useful for reactor projects) ([#504](https://github.com/fabric8io/docker-maven-plugin/issues/504)) * **0.15.9** (2016-06-28) - Fixed issue when target directory does not exist yet ([#497](https://github.com/fabric8io/docker-maven-plugin/issues/497)) - + * **0.15.8** (2016-06-27) - Removed image configuration caching ([#495](https://github.com/fabric8io/docker-maven-plugin/issues/495)) - Fix for tcp wait when used with Docker for Mac ([#430](https://github.com/fabric8io/docker-maven-plugin/issues/430)) - Add warning when assembly is empty when watching a Docker image ([#490](https://github.com/fabric8io/docker-maven-plugin/issues/490)) - - Add `docker.skip.build`, `docker.skip.run`, `docker.skip.push` properties and + - Add `docker.skip.build`, `docker.skip.run`, `docker.skip.push` properties and renamed `docker.skipTags` to `docker.skip.tag` ([#483](https://github.com/fabric8io/docker-maven-plugin/issues/483)) - Reverted jansi back to version 1.11 because of [this issue](https://github.com/fusesource/jansi/issues/58) - Add new assembly config options `permissions` for fine tuning permissions in the docker.tar ([#477](https://github.com/fabric8io/docker-maven-plugin/issues/477)). Deprecated `ignorePermissions` @@ -26,16 +27,16 @@ * **0.15.4** (2016-06-03) - Update dependencies: Apache HttpClient 4.5.2, JMockit 1.23, ... - - Fix read-only bindings ([#462](https://github.com/fabric8io/docker-maven-plugin/issues/462)) + - Fix read-only bindings ([#462](https://github.com/fabric8io/docker-maven-plugin/issues/462)) - Add 'shmSize' as option to the build config ([#463](https://github.com/fabric8io/docker-maven-plugin/issues/463)) - Fixed issue with `memory` and ` - + * **0.15.3** (2016-05-27) - Add duration information when pulling, building and pushing images ([#313](https://github.com/fabric8io/docker-maven-plugin/issues/313)) - Fixed logging to always use format strings ([#457](https://github.com/fabric8io/docker-maven-plugin/issues/457)) - Allow extended image names ([#459](https://github.com/fabric8io/docker-maven-plugin/issues/459)) - -* **0.15.2** (2016-05-19) + +* **0.15.2** (2016-05-19) - More robust response stream parsing ([#436](https://github.com/fabric8io/docker-maven-plugin/issues/436)) - Add `docker.dockerFileDir` and `docker.dockerFile` to the properties configuration provider. ([#438](https://github.com/fabric8io/docker-maven-plugin/issues/438)) - Fix splitting of bind volumes for Windows pathes ([#443](https://github.com/fabric8io/docker-maven-plugin/issues/443)) @@ -43,48 +44,48 @@ for the properties configuration provider ([#441](https://github.com/fabric8io/docker-maven-plugin/issues/441)) - Include dot dirs when creating the build tar ([#446](https://github.com/fabric8io/docker-maven-plugin/issues/446)) - Fix property handler with wait config but empty tcp wait connection ([#451](https://github.com/fabric8io/docker-maven-plugin/issues/451)) - + * **0.15.1** (2016-05-03) - Fix push / pull progress bar ([#91](https://github.com/fabric8io/docker-maven-plugin/issues/91)) - Allow empty environment variable ([#434](https://github.com/fabric8io/docker-maven-plugin/issues/434)) - Async log request get now their own HTTP client ([#344](https://github.com/fabric8io/docker-maven-plugin/issues/344)) ([#259](https://github.com/fabric8io/docker-maven-plugin/issues/259)) - + * **0.15.0** (2016-04-27) - Be more conservative when no "warnings" are returned on create ([#407](https://github.com/fabric8io/docker-maven-plugin/issues/407)) - Fix parsing of timestamps with numeric timezone ([#410](https://github.com/fabric8io/docker-maven-plugin/issues/410)) - Validate image names to fit Docker conventions ([#423](https://github.com/fabric8io/docker-maven-plugin/issues/423)) ([#419](https://github.com/fabric8io/docker-maven-plugin/issues/419)) - - Add support for builds args in external Dockerfiles ([#334](https://github.com/fabric8io/docker-maven-plugin/issues/334)) + - Add support for builds args in external Dockerfiles ([#334](https://github.com/fabric8io/docker-maven-plugin/issues/334)) - Move `dockerFileDir` to topLevel `` and introduced `dockerFile` directive `build>assembly>dockerFileDir` is now deprecated and will be removed. - - Add new packaging "docker" (build + run), "docker-build" (build only) and + - Add new packaging "docker" (build + run), "docker-build" (build only) and "docker-tar" (creating source) ([#433](https://github.com/fabric8io/docker-maven-plugin/issues/433)) - Add `docker:run` as an alias to `docker:start` - Expose certain container properties also as Maven properties. By default the format is `docker.container..ip` for the internal IP address of container with alias ``. ([#198](https://github.com/fabric8io/docker-maven-plugin/issues/198)) - + * **0.14.2** - - Introduce a mode `try` for `` so that an image gets removed if not being still used. + - Introduce a mode `try` for `` so that an image gets removed if not being still used. This is the default now, which should be close enough to `true` (except that it won't fail the build when the image couldn't be removed) ([#401](https://github.com/fabric8io/docker-maven-plugin/issues/401)) * **0.14.1** - First (test) release performed with a fabric8 CD pipeline. No new features. - + * **0.14.0** - Add support for Docker network and `host`, `bridge` and `container` network modes ([#335](https://github.com/fabric8io/docker-maven-plugin/issues/335)) - Add support for older Maven versions, minimum required version is now 3.0.5 ([#290](https://github.com/fabric8io/docker-maven-plugin/issues/290)) - Update to maven-assembly-plugin 2.6 which fixes issue with line endings on windows ([#127](https://github.com/fabric8io/docker-maven-plugin/issues/127)) - - Disabled color output on Windows because ANSI emulation can't be enabled in Maven's sl4j logger which + - Disabled color output on Windows because ANSI emulation can't be enabled in Maven's sl4j logger which caches system out/err - Moved to to [fabric8io](https://github.com/orgs/fabric8io/dashboard) as GitHub organization which implies also changes in the maven coordinates (Maven group-id is now **io.fabric8**) - Fix wait section in samples ([#385](https://github.com/fabric8io/docker-maven-plugin/issues/385)) - Add logging configuration to property handler - Add support for a logging driver ([#379](https://github.com/fabric8io/docker-maven-plugin/issues/379)) - + With version `0.14.0` this plugin moved to the [fabric8](http://fabric8.io) community in order to provide -even better services. This include a change in the Maven coordinates. I.e. the Maven group id is now **io.fabric8** +even better services. This include a change in the Maven coordinates. I.e. the Maven group id is now **io.fabric8** (formerly: "org.jolokia"). Please adapt your pom files accordingly. * **0.13.9** @@ -96,26 +97,26 @@ even better services. This include a change in the Maven coordinates. I.e. the M - Add system property `docker.nocache` to disable build caching globally ([#349](https://github.com/fabric8io/docker-maven-plugin/issues/349)) - Add support for '.maven-dockerignore' for excluding certain files in plain Dockerfile build ([#362](https://github.com/fabric8io/docker-maven-plugin/issues/362)) - If naming strategy is "alias" stop only the container with the given alias with `docker:stop` ([#359](https://github.com/fabric8io/docker-maven-plugin/issues/359)) - - Fix that containers without d-m-p label where still stopped + - Fix that containers without d-m-p label where still stopped - Add support for OpenShift login (use `-DuseOpenShiftAuth` for enabling this) ([#350](https://github.com/fabric8io/docker-maven-plugin/issues/350)) - Add support for dedicated pull and push registry configuration respectively ([#351](https://github.com/fabric8io/docker-maven-plugin/issues/351)) - + * **0.13.7** - Fix default for "cleanup" in build configuration to `true` (as documented) ([#338](https://github.com/fabric8io/docker-maven-plugin/issues/338)) - - Fix dynamic host property update in port mapping ([#323](https://github.com/fabric8io/docker-maven-plugin/issues/323)) - - New goal 'docker:source' for attaching a Docker tar archive to the Maven project with an classifier "docker-" ([#311](https://github.com/fabric8io/docker-maven-plugin/issues/311)) + - Fix dynamic host property update in port mapping ([#323](https://github.com/fabric8io/docker-maven-plugin/issues/323)) + - New goal 'docker:source' for attaching a Docker tar archive to the Maven project with an classifier "docker-" ([#311](https://github.com/fabric8io/docker-maven-plugin/issues/311)) - Be more careful with chowning the user when is used in an assembly ([#336](https://github.com/fabric8io/docker-maven-plugin/issues/336)) - Move VOLUME to the end of the Dockerfile to allow initialization via RUN commands ([#341](https://github.com/fabric8io/docker-maven-plugin/issues/341)) - - Allow multiple configurations with different Docker hosts again ([#320](https://github.com/fabric8io/docker-maven-plugin/issues/320)) - - `docker:start` blocks now only when system property docker.follow is given ([#249](https://github.com/fabric8io/docker-maven-plugin/issues/249)) + - Allow multiple configurations with different Docker hosts again ([#320](https://github.com/fabric8io/docker-maven-plugin/issues/320)) + - `docker:start` blocks now only when system property docker.follow is given ([#249](https://github.com/fabric8io/docker-maven-plugin/issues/249)) - `docker:stop` only stops containers started by this plugin by default ([#87](https://github.com/fabric8io/docker-maven-plugin/issues/87)) - Lookup `~/.docker/config.json` for registry credentials as fallback ([#147](https://github.com/fabric8io/docker-maven-plugin/issues/147)) * **0.13.6** - Don't use user from image when pulling base images ([#147](https://github.com/fabric8io/docker-maven-plugin/issues/147)) - - Add a new assembly descriptor reference `hawt-app` for using assemblies created by + - Add a new assembly descriptor reference `hawt-app` for using assemblies created by [hawt-app](https://github.com/fabric8io/fabric8/tree/master/hawt-app-maven-plugin) - + * **0.13.5** - Improvements for `docker:watch` ([#288](https://github.com/fabric8io/docker-maven-plugin/issues/288)) - Add parameter `kill` to `` configuration for waiting before @@ -124,10 +125,10 @@ even better services. This include a change in the Maven coordinates. I.e. the M `docker.logStdout` to show logs nevertheless to stdout ([#287](https://github.com/fabric8io/docker-maven-plugin/issues/287)) - Support `watchMode == copy` for copying changed assembly files into a running container ([#268](https://github.com/fabric8io/docker-maven-plugin/issues/268)) - - Add a `target/classpath` file to the assembly as `classpath` for + - Add a `target/classpath` file to the assembly as `classpath` for `artifact-with-dependencies` predefined assembly descriptor ([#283](https://github.com/fabric8io/docker-maven-plugin/issues/283)) - Disable Apache HTTP Client retry in WaitUtil ([#297](https://github.com/fabric8io/docker-maven-plugin/issues/297)) - + * **0.13.4** - Support explicit exec arguments for `start.cmd` and `start.entrypoint`. ([#253](https://github.com/fabric8io/docker-maven-plugin/issues/253)) @@ -147,7 +148,7 @@ even better services. This include a change in the Maven coordinates. I.e. the M - Add logic to specify exec commands during postStart and preStop ([#272](https://github.com/fabric8io/docker-maven-plugin/issues/272)) - Fixed docker:watch bug when watching on plain files - + * **0.13.3** - Allow dangling images to be cleaned up after build ([#20](https://github.com/fabric8io/docker-maven-plugin/issues/20)) @@ -188,7 +189,7 @@ even better services. This include a change in the Maven coordinates. I.e. the M ([#195](https://github.com/fabric8io/docker-maven-plugin/issues/195)) - Allow volume mounting from external containers ([#73](https://github.com/fabric8io/docker-maven-plugin/issues/73)) - + * **0.13.1** - Allow autoPull to be forced on docker:build and docker:start ([#96](https://github.com/fabric8io/docker-maven-plugin/issues/96)) @@ -196,7 +197,7 @@ even better services. This include a change in the Maven coordinates. I.e. the M ([#174](https://github.com/fabric8io/docker-maven-plugin/issues/174)) - Add "force=1" to push for Fedora/CentOs images allowing to push to docker hub - + Note that the default registry has been changed to `docker.io` as docker hub doesn't use `registry.hub.docker.com` as the default registry and refused to authenticate against this registry. For @@ -223,8 +224,8 @@ registry to Docker hub. ([#201](https://github.com/fabric8io/docker-maven-plugin/issues/201)) - Support for LABEL for build and run. -Note that since version 0.13.0 this plugin requires Docker API version v1.17 or later in order to support labels. - +Note that since version 0.13.0 this plugin requires Docker API version v1.17 or later in order to support labels. + The watch feature has changed: Instead of using paramters like `docker.watch` or `docker.watch.interval` for `docker:start` a dedicated `docker:watch` has been introduced. Also the @@ -232,7 +233,7 @@ dedicated `docker:watch` has been introduced. Also the up so that `` and `` are on the same level. Please refer to the [manual](manual.md#watching-for-image-changes) for an in depth explanation of the much enhanced watch functionality. - + * **0.12.0** - Allow CMD and ENTRYPOINT with shell and exec arguments ([#130](https://github.com/fabric8io/docker-maven-plugin/issues/130)) @@ -244,7 +245,7 @@ explanation of the much enhanced watch functionality. ([#145](https://github.com/fabric8io/docker-maven-plugin/issues/145)) - Break build if log check or URL check runs into a timeout ([#173](https://github.com/fabric8io/docker-maven-plugin/issues/173)) - + Please note that for consistencies sake `` has been renamed to `` which contains inner elements to match better the equivalent Dockerfile argument. The update should be trivial and easy @@ -252,29 +253,29 @@ to spot since a build will croak immediately. The old format -````xml - +````xml + java -jar /server.jar ```` becomes now -````xml - - - - java +````xml + + + + java -jar /server.jar - - - + + + ```` - + or -````xml +````xml java -jar /server.jar @@ -303,7 +304,7 @@ depending on whether you prefer the `exec` or `shell` form. ([#169](https://github.com/fabric8io/docker-maven-plugin/issues/169)) - Fixed registry authentication lookup ([#146](https://github.com/fabric8io/docker-maven-plugin/issues/146)) - + * **0.11.4** - Fixed documentation for available properties - Changed property `docker.assembly.exportBase` to @@ -322,11 +323,11 @@ depending on whether you prefer the `exec` or `shell` form. - Added support for inline assemblies (#157, #158) - Add support for variable substitution is environment declarations ([#137](https://github.com/fabric8io/docker-maven-plugin/issues/137)) - - Use Tar archive as intermediate container when creating image ([#139](https://github.com/fabric8io/docker-maven-plugin/issues/139)) + - Use Tar archive as intermediate container when creating image ([#139](https://github.com/fabric8io/docker-maven-plugin/issues/139)) - Better error handling for Docker errors wrapped in JSON response only ([#167](https://github.com/fabric8io/docker-maven-plugin/issues/167)) - + * **0.11.3** - Add support for removeVolumes in `docker:stop` configuration ([#120](https://github.com/fabric8io/docker-maven-plugin/issues/120)) @@ -342,7 +343,7 @@ depending on whether you prefer the `exec` or `shell` form. ([#128](https://github.com/fabric8io/docker-maven-plugin/issues/128)) - Documentation improvements (#107, #121) - Allow to use a dockerFileDir without any assembly - + * **0.11.2** - Fix maven parse error when specifying restart policy ([#99](https://github.com/fabric8io/docker-maven-plugin/issues/99)) @@ -372,7 +373,7 @@ depending on whether you prefer the `exec` or `shell` form. (#76, #77, #88) - Fix for stopping containers without tag ([#86](https://github.com/fabric8io/docker-maven-plugin/issues/86)) - + * **0.11.0** - Add support for binding/exporting containers during startup ([#55](https://github.com/fabric8io/docker-maven-plugin/issues/55)) @@ -398,7 +399,7 @@ Please note, that the syntax for binding volumes from another container has changed slightly in 0.10.6. See "[Volume binding](manual.md#volume-binding)" for details but in short: -````xml +````xml data @@ -430,20 +431,20 @@ but in short: ... /export - src/main/docker/assembly.xml - + src/main/docker/assembly.xml + ```` becomes ````xml - ... + ... /export - assembly.xml + assembly.xml - + ```` * **0.10.5** diff --git a/doc/manual/global-configuration.md b/doc/manual/global-configuration.md index 13687864a..7b2de4155 100644 --- a/doc/manual/global-configuration.md +++ b/doc/manual/global-configuration.md @@ -3,7 +3,7 @@ Global configuration parameters specify overall behavior like the connection to the Docker host. The corresponding system properties which can be used to set it from the outside are given in -parentheses. +parentheses. The docker-maven-plugin uses the Docker remote API so the URL of your Docker Daemon must somehow be specified. The URL can be specified by @@ -14,24 +14,21 @@ Since 1.3.0, the Docker remote API supports communication via SSL and authentication with certificates. The path to the certificates can be specified by the certPath or machine configuration, or by the `DOCKER_CERT_PATH` environment variable. - + * **apiVersion** (`docker.apiVersion`) Use this variable if you are using - an older version of docker not compatible with the current default + an older version of docker not compatible with the current default use to communicate with the server. * **authConfig** holds the authentication information when pulling from - or pushing to Docker registry. There is a dedicated section + or pushing to Docker registry. There is a dedicated section [Authentication](authentication.md) for how doing security. - * **autoCreateCustomNetworks** (`docker.autoCreateCustomNetworks`) If set to it will create - Docker networks during `docker:start` and remove it during `docker:stop` if you provide +* **autoCreateCustomNetworks** (`docker.autoCreateCustomNetworks`) If set to it will create + Docker networks during `docker:start` and remove it during `docker:stop` if you provide a custom network in the run configuration of an image. The default is `false`. -* **autoPull** (`docker.autoPull`) - By default external images (base image for building or images to - start) are downloaded automatically if they don't exist locally. - With this options this can be switched off by setting this value to `off`. - Checking for a newer version of an image and downloading it if it - exists can be forced by setting this value to `always`. This will force an image - to be always pulled. This is true for any base image during build and for any image - during run which has no `` section. Valid values are `on|off|always`. +* **autoPull** (`docker.autoPull`) Valid values: `on|off|always|once`. By default external images + (base image for building or images to start) are downloaded automatically if they don't exist locally. + This feature can be turned off by setting this value to `off`. If you want to check for a newer version + of an image and download it if it exists, set this value to `always`. If you are running a `reactor` build, + you may set this value to `once` so the image is only checkedn and pulled once for the entire build. * **certPath** (`docker.certPath`) Since 1.3.0 Docker remote API requires communication via SSL and authentication with certificates when used with boot2docker or docker-machine. These @@ -42,38 +39,38 @@ be specified by the certPath or machine configuration, or by the `~/.docker/`. The keys in this are expected with it standard names `ca.pem`, `cert.pem` and `key.pem`. Please refer to the [Docker documentation](https://docs.docker.com/articles/https/) for - more information about SSL security with Docker. + more information about SSL security with Docker. * **dockerHost** (`docker.host`) Use this parameter to directly specify the URL of the Docker Daemon. If this configuration option is not given, then the optional `` - configuration section is consulted. + configuration section is consulted. The scheme of the URL can be either given directly as `http` or `https` depending on whether plain HTTP communication is enabled or SSL should be used. Alternatively the scheme could be `tcp` in which case the protocol is determined via the IANA assigned port: 2375 for `http` and 2376 for `https`. Finally, Unix sockets are supported by using - the scheme `unix` together with the filesystem path to the unix socket. + the scheme `unix` together with the filesystem path to the unix socket. The discovery sequence used by the docker-maven-plugin to determine the URL is: - value of **dockerHost** (`docker.host`) - the `DOCKER_HOST` associated with the docker-machine named in ``. See below for details. - the value of the environment variable `DOCKER_HOST`. - - `unix:///var/run/docker.sock` if it is a readable socket. + - `unix:///var/run/docker.sock` if it is a readable socket. * **image** (`docker.image`) In order to temporarily restrict the operation of plugin goals this configuration option can be used. Typically this will be set via the system property `docker.image` when Maven is called. The value can be a single image name (either its alias or full name) or it can be a comma separated list with multiple image names. Any name which doesn't refer an - image in the configuration will be ignored. + image in the configuration will be ignored. * **logDate** (`docker.logDate`) specifies the date format which is used for printing out container logs. This configuration can be overwritten by individual run configurations and described below. The format is described in - [Log configuration](docker-start.html##log-configuration) below. -* **logStdout** (`docker.logStdout`) if set, do all container logging to standard output, + [Log configuration](docker-start.html##log-configuration) below. +* **logStdout** (`docker.logStdout`) if set, do all container logging to standard output, regardless whether a `file` for log output is specified. See also [Log configuration](docker-start.html##log-configuration) * **maxConnections** (`docker.maxConnections`) specifies how many parallel connections are allowed to be opened - to the Docker Host. For parsing log output, a connection needs to be kept open (as well for the wait features), + to the Docker Host. For parsing log output, a connection needs to be kept open (as well for the wait features), so don't put that number to low. Default is 100 which should be suitable for most of the cases. * **outputDirectory** (`docker.target.dir`) specifies the default output directory to be used by this plugin. The default value is `target/docker` and is only used for the goal `docker:build`. @@ -82,10 +79,10 @@ be specified by the certPath or machine configuration, or by the its purpose are also described in [Port Mapping](docker-start.html#port-mapping). * **registry** (`docker.registry`) Specify globally a registry to use for pulling and pushing - images. See [Registry handling](registry-handling.md) for details. + images. See [Registry handling](registry-handling.md) for details. * **skip** (`docker.skip`) With this parameter the execution of this plugin can be skipped - completely. + completely. * **skipBuild** (`docker.skip.build`) If set not images will be build (which implies also *skip.tag*) with `docker:build` * **skipPush** (`docker.skip.push`) @@ -94,7 +91,7 @@ be specified by the certPath or machine configuration, or by the If set dont create and start any containers with `docker:start` or `docker:run` * **skipTag** (`docker.skip.tag`) If set to `true` this plugin won't add any tags to images that have been built with `docker:build` -* **skipMachine** (`docker.skip.machine`) +* **skipMachine** (`docker.skip.machine`) Skip using docker machine in any case * **sourceDirectory** (`docker.source.dir`) specifies the default directory that contains the assembly descriptor(s) used by the plugin. The default value is `src/main/docker`. This @@ -102,7 +99,7 @@ be specified by the certPath or machine configuration, or by the * **outputDirectory** (`docker.target.dir`) specifies the default output directory to be used by the plugin. The default value is `target/docker` and is only used for the goal `docker:build`. * **maxConnections** (`docker.maxConnections`) specifies how many parallel connections are allowed to be opened - to the Docker Host. For parsing log output, a connection needs to be kept open (as well for the wait features), + to the Docker Host. For parsing log output, a connection needs to be kept open (as well for the wait features), so don't put that number to low. Default is 100 which should be suitable for most of the cases. Example: @@ -116,8 +113,8 @@ Example: ```` -docker-maven-plugin supports also Docker machine (which must be installed locally, of course). -A Docker machine configuration can be provided with a top-level `` configuration section. +docker-maven-plugin supports also Docker machine (which must be installed locally, of course). +A Docker machine configuration can be provided with a top-level `` configuration section. This configuration section knows the following options: * **name** for the Docker machine's name. Default is `default` @@ -125,15 +122,15 @@ This configuration section knows the following options: * **createOptions** is a map with options for Docker machine when auto-creating a machine. See the docker machine documentation for possible options. -When no Docker host is configured or available as environment variable, then the configured Docker machine +When no Docker host is configured or available as environment variable, then the configured Docker machine is used. If the machine exists but is not running, it is started automatically. If it does not exists but `autoCreate` -is true, then the machine is created and started. Otherwise an error is printed. Please note, that a machine -which has been created because of `autoCreate` gets never deleted by docker-maven-plugin. This needs to be done manually -if required. +is true, then the machine is created and started. Otherwise an error is printed. Please note, that a machine +which has been created because of `autoCreate` gets never deleted by docker-maven-plugin. This needs to be done manually +if required. In absent of a `` configuration section the Maven property `docker.machine.name` can be used to provide -the name of a Docker machine. Similarly the property `docker.machine.autoCreate` can be set to true for creating -a Docker machine, too. +the name of a Docker machine. Similarly the property `docker.machine.autoCreate` can be set to true for creating +a Docker machine, too. You can use the property `docker.skip.machine` if you want to override the internal detection mechanism to always disable docker machine support. diff --git a/src/main/java/io/fabric8/maven/docker/AbstractDockerMojo.java b/src/main/java/io/fabric8/maven/docker/AbstractDockerMojo.java index cb0b3e452..18959e4d4 100644 --- a/src/main/java/io/fabric8/maven/docker/AbstractDockerMojo.java +++ b/src/main/java/io/fabric8/maven/docker/AbstractDockerMojo.java @@ -6,6 +6,8 @@ import java.net.URISyntaxException; import java.util.*; +import com.google.common.collect.Sets; + import io.fabric8.maven.docker.access.*; import io.fabric8.maven.docker.access.hc.DockerAccessWithHcClient; import io.fabric8.maven.docker.config.ConfigHelper; @@ -47,6 +49,9 @@ public abstract class AbstractDockerMojo extends AbstractMojo implements Context // Key under which the build timestamp is stored so that other mojos can reuse it public static final String CONTEXT_KEY_BUILD_TIMESTAMP = "CONTEXT_KEY_BUILD_TIMESTAMP"; + // Key for the previously used image cache + public static final String CONTEXT_KEY_PREVIOUSLY_PULLED = "CONTEXT_KEY_PREVIOUSLY_PULLED"; + // Minimal API version, independent of any feature used public static final String API_VERSION = "1.18"; @@ -397,7 +402,7 @@ protected void checkImageWithAutoPull(ServiceHub hub, String image, String regis boolean autoPullAlwaysAllowed) throws DockerAccessException, MojoExecutionException { // TODO: further refactoring could be done to avoid referencing the QueryService here QueryService queryService = hub.getQueryService(); - if (!queryService.imageRequiresAutoPull(autoPull, image, autoPullAlwaysAllowed)) { + if (!queryService.imageRequiresAutoPull(autoPull, image, autoPullAlwaysAllowed, getPreviouslyPulledImageCache())) { return; } @@ -414,6 +419,19 @@ protected void checkImageWithAutoPull(ServiceHub hub, String image, String regis } } + private synchronized Set getPreviouslyPulledImageCache() { + @SuppressWarnings({ "rawtypes", "unchecked" }) + Set cache = (Set) session.getUserProperties().get(CONTEXT_KEY_PREVIOUSLY_PULLED); + if (cache == null) { + System.out.println("creating new context"); + + cache = Sets.newConcurrentHashSet(); + session.getUserProperties().put(CONTEXT_KEY_PREVIOUSLY_PULLED, cache); + } + + return cache; + } + // Fetch only latest if no tag is given private String withLatestIfNoTag(String name) { ImageName imageName = new ImageName(name); diff --git a/src/main/java/io/fabric8/maven/docker/service/QueryService.java b/src/main/java/io/fabric8/maven/docker/service/QueryService.java index ff729d3d3..bb8a8eef1 100644 --- a/src/main/java/io/fabric8/maven/docker/service/QueryService.java +++ b/src/main/java/io/fabric8/maven/docker/service/QueryService.java @@ -118,7 +118,7 @@ public List getContainersForImage(final String image) throws DockerAc /** * Finds the id of an image. - * + * * @param imageName name of the image. * @return the id of the image * @throws DockerAccessException if the request fails @@ -126,7 +126,7 @@ public List getContainersForImage(final String image) throws DockerAc public String getImageId(String imageName) throws DockerAccessException { return docker.getImageId(imageName); } - + /** * Get the id of the latest container started for an image * @@ -162,7 +162,7 @@ public Container getLatestContainerForImage(String image) throws DockerAccessExc public boolean hasContainer(String containerName) throws DockerAccessException { return getContainerByName(containerName) != null; } - + /** * Check whether a network with the given name exists * @@ -196,30 +196,42 @@ public boolean hasImage(String name) throws DockerAccessException { * @throws DockerAccessException * @throws MojoExecutionException */ - public boolean imageRequiresAutoPull(String mode, String imageName, boolean always) + public boolean imageRequiresAutoPull(String mode, String imageName, boolean always, Set previouslyPulled) throws DockerAccessException, MojoExecutionException { // The logic here is like this (see also #96): - // If the image is not available and mode is either ON or ALWAYS --> pull + // If the image is not available and mode is one of: ON, ALWAYS, ONCE --> pull // If mode == ALWAYS and no build config is available (so its a pulled-image anyway) --> pull // otherwise: don't pull AutoPullMode autoPullMode = AutoPullMode.fromString(mode); - if (pullIfNotPresent(autoPullMode, imageName) || - alwaysPull(autoPullMode, always)) { + if (imageRequiresPull(autoPullMode, imageName, always, previouslyPulled)) { return true; - } else { - if (!hasImage(imageName)) { - throw new MojoExecutionException( - String.format("No image '%s' found, Please enable 'autoPull' or pull image '%s' yourself (docker pull %s)", - imageName, imageName, imageName)); - } + } + + if (hasImage(imageName)) { + return false; + } + + throw new MojoExecutionException( + String.format("No image '%s' found, Please enable 'autoPull' or pull image '%s' yourself (docker pull %s)", + imageName, imageName, imageName)); + } + + private boolean imageRequiresPull(AutoPullMode autoPullMode, String imageName, boolean always, Set previouslyPulled) + throws DockerAccessException { + + if (autoPullMode == AutoPullMode.ONCE && previouslyPulled.contains(imageName)) { return false; } + + previouslyPulled.add(imageName); + + return pullIfNotPresent(autoPullMode, imageName) || alwaysPull(autoPullMode, always); } // Check whether ALWAYS is active private boolean alwaysPull(AutoPullMode autoPullMode, boolean always) { - return always && autoPullMode == AutoPullMode.ALWAYS; + return always && autoPullMode.alwaysPull(); } // Check if an image is not loaded but should be pulled diff --git a/src/main/java/io/fabric8/maven/docker/util/AutoPullMode.java b/src/main/java/io/fabric8/maven/docker/util/AutoPullMode.java index d91244142..b30ac33cb 100644 --- a/src/main/java/io/fabric8/maven/docker/util/AutoPullMode.java +++ b/src/main/java/io/fabric8/maven/docker/util/AutoPullMode.java @@ -1,5 +1,6 @@ -package io.fabric8.maven.docker.util;/* - * +package io.fabric8.maven.docker.util; +/*- + * * Copyright 2014 Roland Huss * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,14 +26,15 @@ */ public enum AutoPullMode { - ON(true,"on","true"), - OFF(false, "off","false"), - ALWAYS(true,"always"); + ON(true, "on", "true"), + ONCE(true, "once"), + OFF(false, "off", "false"), + ALWAYS(true, "always"); private Set values = new HashSet<>(); private boolean doPullIfNotPresent; - AutoPullMode(boolean doPullIfNotPresent, String ... vals) { + AutoPullMode(boolean doPullIfNotPresent, String... vals) { this.doPullIfNotPresent = doPullIfNotPresent; Collections.addAll(values, vals); } @@ -41,6 +43,11 @@ public boolean doPullIfNotPresent() { return doPullIfNotPresent; } + public boolean alwaysPull() { + return (this == ONCE || this == ALWAYS); + + } + static public AutoPullMode fromString(String val) { String valNorm = val.toLowerCase(); for (AutoPullMode mode : values()) { @@ -48,6 +55,6 @@ static public AutoPullMode fromString(String val) { return mode; } } - throw new IllegalArgumentException("Invalid auto-pull mode " + val + ". Please use 'on', 'off' or 'always'."); + throw new IllegalArgumentException("Invalid auto-pull mode " + val + ". Please use 'on', 'off', 'once' or 'always'."); } } diff --git a/src/test/java/io/fabric8/maven/docker/service/QueryServiceAutoPullTest.java b/src/test/java/io/fabric8/maven/docker/service/QueryServiceAutoPullTest.java new file mode 100644 index 000000000..a98215647 --- /dev/null +++ b/src/test/java/io/fabric8/maven/docker/service/QueryServiceAutoPullTest.java @@ -0,0 +1,168 @@ +package io.fabric8.maven.docker.service; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.maven.plugin.MojoExecutionException; +import org.junit.Before; +import org.junit.Test; + +import io.fabric8.maven.docker.access.DockerAccess; +import io.fabric8.maven.docker.access.DockerAccessException; +import io.fabric8.maven.docker.util.AutoPullMode; +import io.fabric8.maven.docker.util.Logger; +import mockit.Expectations; +import mockit.Mocked; + +public class QueryServiceAutoPullTest { + + private Exception actualException; + + private boolean alwaysPull; + + private AutoPullMode autoPullMode; + + @Mocked + private DockerAccess docker; + + private String imageName; + + private boolean imageRequiresPull; + + @Mocked + private Logger logger; + + private Set previousImages; + + private QueryService queryService; + + @Before + public void setup() { + previousImages = new HashSet<>(); + queryService = new QueryService(docker, logger); + } + + @Test + public void testPullImageAlways() throws Exception { + givenAnImage(); + givenPullSettings(AutoPullMode.ALWAYS, true); + + whenCheckIfImageRequiredAutoPull(); + thenImageRequiresPull(); + + givenAnImageExists(); + whenCheckIfImageRequiredAutoPull(); + thenImageRequiresPull(); + } + + @Test + public void testPullImageAlways_forceFalse() throws Exception { + givenAnImage(); + givenPullSettings(AutoPullMode.ALWAYS, false); + whenCheckIfImageRequiredAutoPull(); + thenImageRequiresPull(); + } + + @Test + public void testPullImageOff() throws Exception { + givenAnImage(); + givenPullSettings(AutoPullMode.OFF, true); + whenCheckIfImageRequiredAutoPull(); + thenMojoExcecutionExceptionThrown(); + } + + @Test + public void testPullImageOn() throws Exception { + givenAnImageDoesNotExist(); + givenPullSettings(AutoPullMode.ON, true); + whenCheckIfImageRequiredAutoPull(); + thenImageRequiresPull(); + } + + @Test + public void testPullImageOn_forceFalse() throws Exception { + givenAnImageDoesNotExist(); + givenPullSettings(AutoPullMode.ON, false); + whenCheckIfImageRequiredAutoPull(); + thenImageRequiresPull(); + } + + @Test + public void testPullImageOn_imageExists() throws Exception { + givenAnImageExists(); + givenPullSettings(AutoPullMode.ON, true); + whenCheckIfImageRequiredAutoPull(); + thenImageDoesNotRequirePull(); + } + + @Test + public void testPullImageOnce() throws Exception { + givenAnImage(); + givenPullSettings(AutoPullMode.ONCE, true); + + whenCheckIfImageRequiredAutoPull(); + thenImageRequiresPull(); + + givenAnImageExists(); + whenCheckIfImageRequiredAutoPull(); + thenImageDoesNotRequirePull(); + } + + private void givenAnImageDoesNotExist() throws DockerAccessException { + this.imageName = "test"; + + new Expectations() { + { + docker.hasImage(imageName); + returns(false); + } + }; + } + + private void givenAnImageExists() throws DockerAccessException { + this.imageName = "test"; + + new Expectations() { + { + docker.hasImage(imageName); + returns(true); + } + }; + } + + private void givenAnImage() { + this.imageName = "test"; + } + + private void givenPullSettings(AutoPullMode mode, boolean alwaysPull) { + this.autoPullMode = mode; + this.alwaysPull = alwaysPull; + } + + private void thenImageDoesNotRequirePull() { + assertFalse(imageRequiresPull); + } + + private void thenImageRequiresPull() { + assertTrue(imageRequiresPull); + } + + private void thenMojoExcecutionExceptionThrown() { + assertNotNull(actualException); + assertTrue(actualException instanceof MojoExecutionException); + } + + private void whenCheckIfImageRequiredAutoPull() { + try { + imageRequiresPull = + queryService.imageRequiresAutoPull(autoPullMode.name().toLowerCase(), imageName, alwaysPull, previousImages); + } + catch (Exception e) { + actualException = e; + } + } +}