package org.jenkinsci.plugins.dockerbuildstep.cmd;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.BuildImageCmd;
import com.github.dockerjava.api.exception.DockerException;
import com.github.dockerjava.api.model.BuildResponseItem;
import com.github.dockerjava.core.command.BuildImageResultCallback;
import hudson.Extension;
import hudson.FilePath;
import hudson.model.AbstractBuild;
import org.jenkinsci.plugins.dockerbuildstep.log.ConsoleLogger;
import org.jenkinsci.plugins.dockerbuildstep.util.Resolver;
import org.kohsuke.stapler.DataBoundConstructor;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
/**
* This command creates a new image from specified Dockerfile.
*
* @author marcus
* @see http://docs.docker.com/reference/api/docker_remote_api_v1.13/#build-an-image-from-dockerfile-via-stdin
*/
public class CreateImageCommand extends DockerCommand {
private final String dockerFolder;
private final String imageTag;
private final String dockerFile;
private final boolean noCache;
private final boolean rm;
private final String buildArgs;
@DataBoundConstructor
public CreateImageCommand(String dockerFolder, String imageTag, String dockerFile, boolean noCache, boolean rm, String buildArgs) {
this.dockerFolder = dockerFolder;
this.imageTag = imageTag;
this.dockerFile = dockerFile;
this.noCache = noCache;
this.buildArgs = buildArgs;
this.rm = rm;
}
public String getDockerFolder() {
return dockerFolder;
}
public String getImageTag() {
return imageTag;
}
public String getDockerFile() {
return dockerFile;
}
public boolean isNoCache() {
return noCache;
}
public boolean isRm() {
return rm;
}
public String getBuildArgs() {
return buildArgs;
}
@Override
public void execute(@SuppressWarnings("rawtypes") AbstractBuild build, final ConsoleLogger console)
throws DockerException {
if (dockerFolder == null) {
throw new IllegalArgumentException("dockerFolder is not configured");
}
if (imageTag == null) {
throw new IllegalArgumentException("imageTag is not configured");
}
final Map<String, String> buildArgsMap = new HashMap<String, String>();
if (buildArgs != null) {
console.logInfo("Parsing buildArgs: " + buildArgs);
String[] split = Resolver.buildVar(build, buildArgs).split(",|;");
for (String arg : split) {
String[] pair = arg.split("=");
if (pair.length == 2) {
buildArgsMap.put(pair[0].trim(), pair[1].trim());
} else {
console.logError("Invalid format for " + arg + ". Buildargs should be formatted as key=value");
}
}
}
String dockerFolderRes = Resolver.buildVar(build, dockerFolder);
String imageTagRes = Resolver.buildVar(build, imageTag);
String expandedDockerFolder = Resolver.buildVar(build, dockerFolderRes);
String expandedImageTag = Resolver.buildVar(build, imageTagRes);
FilePath folder = new FilePath(new File(expandedDockerFolder));
if (!exist(folder))
throw new IllegalArgumentException(
"configured dockerFolder '" + expandedDockerFolder + "' does not exist.");
String dockerFileRes = dockerFile == null ? "Dockerfile" : Resolver.buildVar(build, dockerFile);
if (!exist(folder.child(dockerFileRes))) {
throw new IllegalArgumentException(
String.format("Configured Docker file '%s' does not exist.", dockerFileRes));
}
DockerClient client = getClient(build, null);
try {
File docker = new File(expandedDockerFolder, dockerFileRes);
console.logInfo("Creating docker image from " + docker.getAbsolutePath());
BuildImageResultCallback callback = new BuildImageResultCallback() {
@Override
public void onNext(BuildResponseItem item) {
console.logInfo(item.toString());
super.onNext(item);
}
@Override
public void onError(Throwable throwable) {
console.logError("Failed to creating docker image:" + throwable.getMessage());
super.onError(throwable);
}
};
BuildImageCmd buildImageCmd = client
.buildImageCmd(docker)
.withTag(expandedImageTag)
.withNoCache(noCache)
.withRemove(rm);
if (!buildArgsMap.isEmpty()) {
for (final Map.Entry<String, String> entry : buildArgsMap.entrySet()) {
buildImageCmd = buildImageCmd.withBuildArg(entry.getKey(), entry.getValue());
}
}
BuildImageResultCallback result = buildImageCmd.exec(callback);
console.logInfo("Build image id:" + result.awaitImageId());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Extension
public static class CreateImageCommandDescriptor extends DockerCommandDescriptor {
@Override
public String getDisplayName() {
return "Create/build image";
}
}
private boolean exist(FilePath filePath) throws DockerException {
try {
return filePath.exists();
} catch (Exception e) {
throw new DockerException("Could not check file", 0, e);
}
}
}