
io.fabric8.maven.docker.WatchMojo Maven / Gradle / Ivy
The newest version!
package io.fabric8.maven.docker;/*
*
* Copyright 2014 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 java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import io.fabric8.maven.docker.access.DockerAccessException;
import io.fabric8.maven.docker.access.PortMapping;
import io.fabric8.maven.docker.assembly.AssemblyFiles;
import io.fabric8.maven.docker.config.ImageConfiguration;
import io.fabric8.maven.docker.config.WatchImageConfiguration;
import io.fabric8.maven.docker.config.WatchMode;
import io.fabric8.maven.docker.util.MojoParameters;
import io.fabric8.maven.docker.util.StartOrderResolver;
import io.fabric8.maven.docker.service.*;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.util.StringUtils;
/**
* Mojo for watching source code changes.
*
* This Mojo does essentially
* two things when it detects a image content change:
*
*
* - Rebuilding one or more images
* - Restarting restarting one or more containers
*
*
* @author roland
* @since 16/06/15
*/
@Mojo(name = "watch")
public class WatchMojo extends AbstractBuildSupportMojo {
@Parameter(property = "docker.watchMode", defaultValue = "both")
private WatchMode watchMode;
@Parameter(property = "docker.watchInterval", defaultValue = "5000")
private int watchInterval;
@Parameter(property = "docker.keepRunning", defaultValue = "false")
private boolean keepRunning;
@Parameter(property = "docker.watchPostGoal")
private String watchPostGoal;
@Parameter(property = "docker.watchPostExec")
private String watchPostExec;
// Scheduler
private ScheduledExecutorService executor;
@Override
protected synchronized void executeInternal(ServiceHub hub) throws DockerAccessException,
MojoExecutionException {
// Important to be be a single threaded scheduler since watch jobs must run serialized
executor = Executors.newSingleThreadScheduledExecutor();
QueryService queryService = hub.getQueryService();
RunService runService = hub.getRunService();
MojoParameters mojoParameters = createMojoParameters();
try {
for (StartOrderResolver.Resolvable resolvable : runService.getImagesConfigsInOrder(queryService, getImages())) {
final ImageConfiguration imageConfig = (ImageConfiguration) resolvable;
String imageId = queryService.getImageId(imageConfig.getName());
String containerId = runService.lookupContainer(imageConfig.getName());
ImageWatcher watcher = new ImageWatcher(imageConfig, imageId, containerId);
long interval = watcher.getInterval();
ArrayList tasks = new ArrayList<>();
if (imageConfig.getBuildConfiguration() != null &&
imageConfig.getBuildConfiguration().getAssemblyConfiguration() != null) {
if (watcher.isCopy()) {
String containerBaseDir = imageConfig.getBuildConfiguration().getAssemblyConfiguration().getBasedir();
schedule(createCopyWatchTask(hub, watcher, mojoParameters, containerBaseDir),interval);
tasks.add("copying artifacts");
}
if (watcher.isBuild()) {
schedule(createBuildWatchTask(hub, watcher, mojoParameters, watchMode == WatchMode.both), interval);
tasks.add("rebuilding");
}
}
if (watcher.isRun() && watcher.getContainerId() != null) {
schedule(createRestartWatchTask(hub, watcher), interval);
tasks.add("restarting");
}
if (tasks.size() > 0) {
log.info(imageConfig.getDescription() + ": Watch for " + StringUtils.join(tasks.toArray()," and "));
}
}
log.info("Waiting ...");
if (!keepRunning) {
runService.addShutdownHookForStoppingContainers(keepContainer, removeVolumes);
}
wait();
} catch (InterruptedException e) {
log.warn("Interrupted");
} finally {
executor.shutdownNow();
}
}
private void schedule(Runnable runnable, long interval) {
executor.scheduleAtFixedRate(runnable, 0, interval, TimeUnit.MILLISECONDS);
}
private Runnable createCopyWatchTask(final ServiceHub hub, final ImageWatcher watcher,
final MojoParameters mojoParameters, final String containerBaseDir) throws MojoExecutionException {
final ImageConfiguration imageConfig = watcher.getImageConfiguration();
final ArchiveService archiveService = hub.getArchiveService();
final AssemblyFiles files = archiveService.getAssemblyFiles(imageConfig, mojoParameters);
return new Runnable() {
@Override
public void run() {
List entries = files.getUpdatedEntriesAndRefresh();
if (entries != null && entries.size() > 0) {
try {
log.info(imageConfig.getDescription() + ": Assembly changed. Copying changed files to container ...");
File changedFilesArchive = archiveService.createChangedFilesArchive(entries,files.getAssemblyDirectory(),
imageConfig.getName(),mojoParameters);
hub.getDockerAccess().copyArchive(watcher.getContainerId(), changedFilesArchive, containerBaseDir);
callPostExec(hub.getRunService(), watcher);
} catch (MojoExecutionException | IOException e) {
log.error(imageConfig.getDescription() + ": Error when copying files to container " + watcher.getContainerId() + ": " + e);
}
}
}
};
}
private void callPostExec(RunService runService, ImageWatcher watcher) throws DockerAccessException {
if (watcher.getPostExec() != null) {
String containerId = watcher.getContainerId();
runService.execInContainer(containerId, watcher.getPostExec(), watcher.getImageConfiguration());
}
}
private Runnable createBuildWatchTask(final ServiceHub hub, final ImageWatcher watcher,
final MojoParameters mojoParameters, final boolean doRestart)
throws MojoExecutionException {
final ImageConfiguration imageConfig = watcher.getImageConfiguration();
final AssemblyFiles files = hub.getArchiveService().getAssemblyFiles(imageConfig, mojoParameters);
return new Runnable() {
@Override
public void run() {
List entries = files.getUpdatedEntriesAndRefresh();
if (entries != null && entries.size() > 0) {
try {
log.info(imageConfig.getDescription() + ": Assembly changed. Rebuild ...");
buildImage(hub, imageConfig);
String name = imageConfig.getName();
watcher.setImageId(hub.getQueryService().getImageId(name));
if (doRestart) {
restartContainer(hub, watcher);
}
callPostGoal(hub, watcher);
} catch (MojoExecutionException | MojoFailureException | IOException e) {
log.error(imageConfig.getDescription() + ": Error when rebuilding " + e);
}
}
}
};
}
private Runnable createRestartWatchTask(final ServiceHub hub,
final ImageWatcher watcher)
throws DockerAccessException {
final String imageName = watcher.getImageName();
return new Runnable() {
@Override
public void run() {
try {
String currentImageId = hub.getQueryService().getImageId(imageName);
String oldValue = watcher.getAndSetImageId(currentImageId);
if (!currentImageId.equals(oldValue)) {
restartContainer(hub, watcher);
callPostGoal(hub, watcher);
}
} catch (DockerAccessException | MojoFailureException | MojoExecutionException e) {
log.warn(watcher.getImageConfiguration().getDescription() + ": Error when restarting image " + e);
}
}
};
}
private void restartContainer(ServiceHub hub, ImageWatcher watcher) throws DockerAccessException {
// Stop old one
RunService runService = hub.getRunService();
ImageConfiguration imageConfig = watcher.getImageConfiguration();
PortMapping mappedPorts = runService.getPortMapping(imageConfig.getRunConfiguration(), project.getProperties());
String id = watcher.getContainerId();
String optionalPreStop = getPreStopCommand(imageConfig);
if (optionalPreStop != null) {
runService.execInContainer(id, optionalPreStop, watcher.getImageConfiguration());
}
runService.stopPreviouslyStartedContainer(id, false, false);
// Start new one
watcher.setContainerId(runService.createAndStartContainer(imageConfig, mappedPorts, getPomLabel(), project.getProperties()));
}
private String getPreStopCommand(ImageConfiguration imageConfig) {
if (imageConfig.getRunConfiguration() != null &&
imageConfig.getRunConfiguration().getWaitConfiguration() != null &&
imageConfig.getRunConfiguration().getWaitConfiguration().getExec() != null) {
return imageConfig.getRunConfiguration().getWaitConfiguration().getExec().getPreStop();
}
return null;
}
private void callPostGoal(ServiceHub hub, ImageWatcher watcher) throws MojoFailureException,
MojoExecutionException {
String postGoal = watcher.getPostGoal();
if (postGoal != null) {
hub.getMojoExecutionService().callPluginGoal(postGoal);
}
}
// ===============================================================================================================
// Helper class for holding state and parameter when watching images
private class ImageWatcher {
private final WatchMode mode;
private final AtomicReference imageIdRef, containerIdRef;
private final long interval;
private final ImageConfiguration imageConfig;
private final String postGoal;
private String postExec;
public ImageWatcher(ImageConfiguration imageConfig, String imageId, String containerIdRef) {
this.imageConfig = imageConfig;
this.imageIdRef = new AtomicReference<>(imageId);
this.containerIdRef = new AtomicReference<>(containerIdRef);
this.interval = getWatchInterval(imageConfig);
this.mode = getWatchMode(imageConfig);
this.postGoal = getPostGoal(imageConfig);
this.postExec = getPostExec(imageConfig);
}
public String getContainerId() {
return containerIdRef.get();
}
public long getInterval() {
return interval;
}
public String getPostGoal() {
return postGoal;
}
public boolean isCopy() {
return mode.isCopy();
}
public boolean isBuild() {
return mode.isBuild();
}
public boolean isRun() {
return mode.isRun();
}
public ImageConfiguration getImageConfiguration() {
return imageConfig;
}
public void setImageId(String imageId) {
imageIdRef.set(imageId);
}
public void setContainerId(String containerId) {
containerIdRef.set(containerId);
}
public String getImageName() {
return imageConfig.getName();
}
public String getAndSetImageId(String currentImageId) {
return imageIdRef.getAndSet(currentImageId);
}
public String getPostExec() {
return postExec;
}
// =========================================================
private int getWatchInterval(ImageConfiguration imageConfig) {
WatchImageConfiguration watchConfig = imageConfig.getWatchConfiguration();
int interval = watchConfig != null ? watchConfig.getInterval() : WatchMojo.this.watchInterval;
return interval < 100 ? 100 : interval;
}
private String getPostExec(ImageConfiguration imageConfig) {
WatchImageConfiguration watchConfig = imageConfig.getWatchConfiguration();
return watchConfig != null && watchConfig.getPostExec() != null ?
watchConfig.getPostExec() : WatchMojo.this.watchPostExec;
}
private String getPostGoal(ImageConfiguration imageConfig) {
WatchImageConfiguration watchConfig = imageConfig.getWatchConfiguration();
return watchConfig != null && watchConfig.getPostGoal() != null ?
watchConfig.getPostGoal() : WatchMojo.this.watchPostGoal;
}
private WatchMode getWatchMode(ImageConfiguration imageConfig) {
WatchImageConfiguration watchConfig = imageConfig.getWatchConfiguration();
WatchMode mode = watchConfig != null ? watchConfig.getMode() : null;
return mode != null ? mode : WatchMojo.this.watchMode;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy