Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.fabric8.maven.docker.service.WatchService Maven / Gradle / Ivy
package io.fabric8.maven.docker.service;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import io.fabric8.maven.docker.access.DockerAccess;
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.config.ImageConfiguration;
import io.fabric8.maven.docker.config.WatchImageConfiguration;
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.StartOrderResolver;
import io.fabric8.maven.docker.util.Task;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.codehaus.plexus.util.StringUtils;
/**
* Watch service for monitoring changes and restarting containers
*/
public class WatchService {
private final ArchiveService archiveService;
private final BuildService 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
runService, Logger log) {
this.archiveService = archiveService;
this.buildService = buildService;
this.dockerAccess = dockerAccess;
this.mojoExecutionService = mojoExecutionService;
this.queryService = queryService;
this.runService = runService;
this.log = log;
}
public synchronized void watch(WatchContext context, BuildService.BuildContext buildContext, List images) throws DockerAccessException,
MojoExecutionException {
// 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;
String imageId = queryService.getImageId(imageConfig.getName());
String containerId = runService.lookupContainer(imageConfig.getName());
ImageWatcher watcher = new ImageWatcher(imageConfig, context, imageId, containerId);
long interval = watcher.getInterval();
WatchMode watchMode = watcher.getWatchMode(imageConfig);
log.info("Watching " + imageConfig.getName() + (watchMode != null ? " using " + watchMode.getDescription() : ""));
ArrayList tasks = new ArrayList<>();
if (imageConfig.getBuildConfiguration() != null &&
imageConfig.getBuildConfiguration().getAssemblyConfiguration() != null) {
if (watcher.isCopy()) {
String containerBaseDir = imageConfig.getBuildConfiguration().getAssemblyConfiguration().getTargetDir();
schedule(executor, createCopyWatchTask(watcher, context.getMojoParameters(), containerBaseDir), interval);
tasks.add("copying artifacts");
}
if (watcher.isBuild()) {
schedule(executor, createBuildWatchTask(watcher, context.getMojoParameters(), watchMode == WatchMode.both, buildContext), interval);
tasks.add("rebuilding");
}
}
if (watcher.isRun() && watcher.getContainerId() != null) {
schedule(executor, createRestartWatchTask(watcher), interval);
tasks.add("restarting");
}
if (tasks.size() > 0) {
log.info("%s: Watch for %s", imageConfig.getDescription(), StringUtils.join(tasks.toArray(), " and "));
}
}
log.info("Waiting ...");
if (!context.isKeepRunning()) {
runService.addShutdownHookForStoppingContainers(context.isKeepContainer(), context.isRemoveVolumes(), context.isAutoCreateCustomNetworks());
}
wait();
} catch (InterruptedException e) {
log.warn("Interrupted");
} finally {
if (executor != null) {
executor.shutdownNow();
}
}
}
private void schedule(ScheduledExecutorService executor, Runnable runnable, long interval) {
executor.scheduleAtFixedRate(runnable, 0, interval, TimeUnit.MILLISECONDS);
}
private Runnable createCopyWatchTask(final ImageWatcher watcher,
final MojoParameters mojoParameters, final String containerBaseDir) throws MojoExecutionException {
final ImageConfiguration imageConfig = watcher.getImageConfiguration();
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("%s: Assembly changed. Copying changed files to container ...", imageConfig.getDescription());
File changedFilesArchive = archiveService.createChangedFilesArchive(entries, files.getAssemblyDirectory(),
imageConfig.getName(), mojoParameters);
dockerAccess.copyArchive(watcher.getContainerId(), changedFilesArchive, containerBaseDir);
callPostExec(watcher);
} catch (MojoExecutionException | IOException | ExecException e) {
log.error("%s: Error when copying files to container %s: %s",
imageConfig.getDescription(), watcher.getContainerId(), e.getMessage());
}
}
}
};
}
private void callPostExec(ImageWatcher watcher) throws DockerAccessException, ExecException {
if (watcher.getPostExec() != null) {
String containerId = watcher.getContainerId();
runService.execInContainer(containerId, watcher.getPostExec(), watcher.getImageConfiguration());
}
}
private Runnable createBuildWatchTask(final ImageWatcher watcher,
final MojoParameters mojoParameters, final boolean doRestart, final BuildService.BuildContext buildContext)
throws MojoExecutionException {
final ImageConfiguration imageConfig = watcher.getImageConfiguration();
final AssemblyFiles files = archiveService.getAssemblyFiles(imageConfig, mojoParameters);
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);
}
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());
if (watcher.getWatchContext().getImageCustomizer() != null) {
log.info("%s: Customizing the image ...", imageConfig.getDescription());
watcher.getWatchContext().getImageCustomizer().execute(imageConfig);
}
buildService.buildImage(imageConfig, null, buildContext);
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 {
final String imageName = watcher.getImageName();
return new Runnable() {
@Override
public void run() {
try {
String currentImageId = queryService.getImageId(imageName);
String oldValue = watcher.getAndSetImageId(currentImageId);
if (!currentImageId.equals(oldValue)) {
restartContainer(watcher);
callPostGoal(watcher);
}
} catch (Exception e) {
log.warn("%s: Error when restarting image - %s", watcher.getImageConfiguration().getDescription(), e);
}
}
};
}
private void restartContainer(ImageWatcher watcher) throws Exception {
Task restarter = watcher.getWatchContext().getContainerRestarter();
if (restarter == null) {
restarter = defaultContainerRestartTask();
}
// Restart
restarter.execute(watcher);
}
private Task defaultContainerRestartTask() {
return watcher -> {
// Stop old one
ImageConfiguration imageConfig = watcher.getImageConfiguration();
PortMapping mappedPorts = runService.createPortMapping(imageConfig.getRunConfiguration(), watcher.getWatchContext().getMojoParameters().getProject().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
StartContainerExecutor helper = new StartContainerExecutor.Builder()
.dispatcher(watcher.watchContext.dispatcher)
.follow(watcher.watchContext.follow)
.log(log)
.portMapping(mappedPorts)
.gavLabel(watcher.watchContext.getGavLabel())
.projectProperties(watcher.watchContext.mojoParameters.getProject().getProperties())
.basedir(watcher.watchContext.mojoParameters.getProject().getBasedir())
.imageConfig(imageConfig)
.serviceHub(watcher.watchContext.hub)
.logOutputSpecFactory(watcher.watchContext.serviceHubFactory.getLogOutputSpecFactory())
.showLogs(watcher.watchContext.showLogs)
.containerNamePattern(watcher.watchContext.containerNamePattern)
.buildTimestamp(watcher.watchContext.buildTimestamp)
.build();
String containerId = helper.startContainers();
watcher.setContainerId(containerId);
};
}
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(ImageWatcher watcher) throws MojoFailureException,
MojoExecutionException {
String postGoal = watcher.getPostGoal();
if (postGoal != null) {
mojoExecutionService.callPluginGoal(postGoal);
}
}
// ===============================================================================================================
// Helper class for holding state and parameter when watching images
public class ImageWatcher {
private final ImageConfiguration imageConfig;
private final WatchContext watchContext;
private final WatchMode mode;
private final AtomicReference imageIdRef, containerIdRef;
private final long interval;
private final String postGoal;
private String postExec;
public ImageWatcher(ImageConfiguration imageConfig, WatchContext watchContext, String imageId, String containerIdRef) {
this.imageConfig = imageConfig;
this.watchContext = watchContext;
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;
}
public WatchContext getWatchContext() {
return watchContext;
}
// =========================================================
private int getWatchInterval(ImageConfiguration imageConfig) {
WatchImageConfiguration 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();
return watchConfig != null && watchConfig.getPostExec() != null ?
watchConfig.getPostExec() : watchContext.getWatchPostExec();
}
private String getPostGoal(ImageConfiguration imageConfig) {
WatchImageConfiguration watchConfig = imageConfig.getWatchConfiguration();
return watchConfig != null && watchConfig.getPostGoal() != null ?
watchConfig.getPostGoal() : watchContext.getWatchPostGoal();
}
private WatchMode getWatchMode(ImageConfiguration imageConfig) {
WatchImageConfiguration watchConfig = imageConfig.getWatchConfiguration();
WatchMode mode = watchConfig != null ? watchConfig.getMode() : null;
return mode != null ? mode : watchContext.getWatchMode();
}
}
// ===========================================================
/**
* Context class to hold the watch configuration
*/
public static class WatchContext implements Serializable {
private MojoParameters mojoParameters;
private WatchMode watchMode;
private int watchInterval;
private boolean keepRunning;
private String watchPostGoal;
private String watchPostExec;
private GavLabel gavLabel;
private boolean keepContainer;
private boolean removeVolumes;
private boolean autoCreateCustomNetworks;
private Task imageCustomizer;
private Task containerRestarter;
private transient ServiceHub hub;
private transient ServiceHubFactory serviceHubFactory;
private transient LogDispatcher dispatcher;
private boolean follow;
private String showLogs;
private Date buildTimestamp;
private String containerNamePattern;
public WatchContext() {
}
public MojoParameters getMojoParameters() {
return mojoParameters;
}
public WatchMode getWatchMode() {
return watchMode;
}
public int getWatchInterval() {
return watchInterval;
}
public boolean isKeepRunning() {
return keepRunning;
}
public String getWatchPostGoal() {
return watchPostGoal;
}
public String getWatchPostExec() {
return watchPostExec;
}
public GavLabel getGavLabel() {
return gavLabel;
}
public boolean isKeepContainer() {
return keepContainer;
}
public boolean isRemoveVolumes() {
return removeVolumes;
}
public boolean isAutoCreateCustomNetworks() {
return autoCreateCustomNetworks;
}
public Task getImageCustomizer() {
return imageCustomizer;
}
public Task getContainerRestarter() {
return containerRestarter;
}
public Date getBuildTimestamp() {
return buildTimestamp;
}
public String getContainerNamePattern() {
return containerNamePattern;
}
public static class Builder {
private WatchContext context;
public Builder() {
this.context = new WatchContext();
}
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;
}
public Builder watchInterval(int watchInterval) {
context.watchInterval = watchInterval;
return this;
}
public Builder keepRunning(boolean keepRunning) {
context.keepRunning = keepRunning;
return this;
}
public Builder watchPostGoal(String watchPostGoal) {
context.watchPostGoal = watchPostGoal;
return this;
}
public Builder watchPostExec(String watchPostExec) {
context.watchPostExec = watchPostExec;
return this;
}
public Builder pomLabel(GavLabel gavLabel) {
context.gavLabel = gavLabel;
return this;
}
public Builder keepContainer(boolean keepContainer) {
context.keepContainer = keepContainer;
return this;
}
public Builder removeVolumes(boolean removeVolumes) {
context.removeVolumes = removeVolumes;
return this;
}
public Builder imageCustomizer(Task imageCustomizer) {
context.imageCustomizer = imageCustomizer;
return this;
}
public Builder containerRestarter(Task containerRestarter) {
context.containerRestarter = containerRestarter;
return this;
}
public Builder autoCreateCustomNetworks(boolean autoCreateCustomNetworks) {
context.autoCreateCustomNetworks = autoCreateCustomNetworks;
return this;
}
public Builder follow(boolean follow) {
context.follow = follow;
return this;
}
public Builder showLogs(String showLogs) {
context.showLogs = showLogs;
return this;
}
public Builder hub(ServiceHub hub){
context.hub = hub;
return this;
}
public Builder serviceHubFactory(ServiceHubFactory serviceHubFactory){
context.serviceHubFactory = serviceHubFactory;
return this;
}
public Builder dispatcher(LogDispatcher dispatcher){
context.dispatcher = dispatcher;
return this;
}
public Builder buildTimestamp(Date buildTimestamp) {
context.buildTimestamp = buildTimestamp;
return this;
}
public Builder containerNamePattern(String containerNamePattern) {
context.containerNamePattern = containerNamePattern;
return this;
}
public WatchContext build() {
return context;
}
}
}
}