blob: 0c5a0875245250b82d8759447fe94e686032afed [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The ASF licenses this file to you 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.
*/
package org.apache.storm.container.docker;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Encapsulates the docker run command and its command line arguments.
*/
public class DockerRunCommand extends DockerCommand {
private static final Logger LOG = LoggerFactory.getLogger(DockerRunCommand.class);
private static final String RUN_COMMAND = "run";
private final String image;
private List<String> overrideCommandWithArgs;
/**
* The Construction function.
* @param containerName the container name
* @param userInfo the info of the user, e.g. "uid:gid"
* @param image the container image
*/
public DockerRunCommand(String containerName, String userInfo, String image) {
super(RUN_COMMAND);
super.addCommandArguments("--name=" + containerName, "--user=" + userInfo);
this.image = image;
}
/**
* Add --rm option.
* @return the self
*/
public DockerRunCommand removeContainerOnExit() {
super.addCommandArguments("--rm");
return this;
}
/**
* Add -d option.
* @return the self
*/
public DockerRunCommand detachOnRun() {
super.addCommandArguments("-d");
return this;
}
/**
* Set --workdir option.
* @param workdir the working directory
* @return the self
*/
public DockerRunCommand setContainerWorkDir(String workdir) {
super.addCommandArguments("--workdir=" + workdir);
return this;
}
/**
* Set --net option.
* @param type the network type
* @return the self
*/
public DockerRunCommand setNetworkType(String type) {
super.addCommandArguments("--net=" + type);
return this;
}
/**
* Add bind mount locations.
* @param sourcePath the source path
* @param destinationPath the destination path
* @param createSource if createSource is false and the source path doesn't exist, do nothing
* @return the self
*/
public DockerRunCommand addReadWriteMountLocation(String sourcePath, String
destinationPath, boolean createSource) throws IOException {
if (!createSource) {
boolean sourceExists = new File(sourcePath).exists();
if (!sourceExists) {
throw new IOException("SourcePath " + sourcePath + " doesn't exit.");
}
}
super.addCommandArguments("-v", sourcePath + ":" + destinationPath);
return this;
}
public DockerRunCommand addReadWriteMountLocation(String sourcePath, String
destinationPath) throws IOException {
return addReadWriteMountLocation(sourcePath, destinationPath, true);
}
/**
* Add all the rw bind mount locations.
* @param paths the locations
* @return the self
*/
public DockerRunCommand addAllReadWriteMountLocations(List<String> paths) throws IOException {
return addAllReadWriteMountLocations(paths, true);
}
/**
* Add all the rw bind mount locations.
* @param paths the locations
* @param createSource if createSource is false and the source path doesn't exist, do nothing
* @return the self
*/
public DockerRunCommand addAllReadWriteMountLocations(List<String> paths,
boolean createSource) throws IOException {
for (String dir: paths) {
this.addReadWriteMountLocation(dir, dir, createSource);
}
return this;
}
/**
* Add readonly bind mount location.
* @param sourcePath the source path
* @param destinationPath the destination path
* @param createSource if createSource is false and the source path doesn't exist, do nothing
* @return the self
*/
public DockerRunCommand addReadOnlyMountLocation(String sourcePath, String destinationPath,
boolean createSource) throws IOException {
if (!createSource) {
boolean sourceExists = new File(sourcePath).exists();
if (!sourceExists) {
throw new IOException("SourcePath " + sourcePath + " doesn't exit.");
}
}
super.addCommandArguments("-v", sourcePath + ":" + destinationPath + ":ro");
return this;
}
/**
* Add readonly bind mout location.
* @param sourcePath the source path
* @param destinationPath the destination path
* @return the self
*/
public DockerRunCommand addReadOnlyMountLocation(String sourcePath,
String destinationPath) throws IOException {
return addReadOnlyMountLocation(sourcePath, destinationPath, true);
}
/**
* Add all readonly locations.
* @param paths the locations
* @return the self
*/
public DockerRunCommand addAllReadOnlyMountLocations(List<String> paths) throws IOException {
return addAllReadOnlyMountLocations(paths, true);
}
/**
* Add all readonly locations.
* @param paths the locations
* @param createSource if createSource is false and the source path doesn't exist, do nothing
* @return the self
*/
public DockerRunCommand addAllReadOnlyMountLocations(List<String> paths,
boolean createSource) throws IOException {
for (String dir: paths) {
this.addReadOnlyMountLocation(dir, dir, createSource);
}
return this;
}
public DockerRunCommand addCpuSetBindings(List<String> cores, String memoryNode) {
if (!cores.isEmpty()) {
super.addCommandArguments("--cpuset-cpus=" + StringUtils.join(cores, ","));
}
if (memoryNode != null) {
super.addCommandArguments("--cpuset-mems=" + memoryNode);
}
return this;
}
/**
* Set --cgroup-parent option.
* @param parentPath the cgroup parent path
* @return the self
*/
public DockerRunCommand setCGroupParent(String parentPath) {
super.addCommandArguments("--cgroup-parent=" + parentPath);
return this;
}
/**
* Set --privileged option to run a privileged container. Use with extreme care.
* @return the self.
*/
public DockerRunCommand setPrivileged() {
super.addCommandArguments("--privileged");
return this;
}
/**
* Set capabilities of the container.
* @param capabilities the capabilities to be added
* @return the self
*/
public DockerRunCommand setCapabilities(Set<String> capabilities) {
//first, drop all capabilities
super.addCommandArguments("--cap-drop=ALL");
//now, add the capabilities supplied
for (String capability : capabilities) {
super.addCommandArguments("--cap-add=" + capability);
}
return this;
}
/**
* Set --device option.
* @param sourceDevice the source device
* @param destinationDevice the destination device
* @return the self
*/
public DockerRunCommand addDevice(String sourceDevice, String destinationDevice) {
super.addCommandArguments("--device=" + sourceDevice + ":" + destinationDevice);
return this;
}
/**
* Enable detach.
* @return the self
*/
public DockerRunCommand enableDetach() {
super.addCommandArguments("--detach=true");
return this;
}
/**
* Disable detach.
* @return the self
*/
public DockerRunCommand disableDetach() {
super.addCommandArguments("--detach=false");
return this;
}
/**
* Set --group-add option.
* @param groups the groups to be added
* @return the self
*/
public DockerRunCommand groupAdd(String[] groups) {
for (int i = 0; i < groups.length; i++) {
super.addCommandArguments("--group-add " + groups[i]);
}
return this;
}
/**
* Set extra commands and args. It can override the existing commands.
* @param overrideCommandWithArgs the extra commands and args
* @return the self
*/
public DockerRunCommand setOverrideCommandWithArgs(
List<String> overrideCommandWithArgs) {
this.overrideCommandWithArgs = overrideCommandWithArgs;
return this;
}
/**
* Add --read-only option.
* @return the self
*/
public DockerRunCommand setReadonly() {
super.addCommandArguments("--read-only");
return this;
}
/**
* Set --security-opt option.
* @param jsonPath the path to the json file
* @return the self
*/
public DockerRunCommand setSeccompProfile(String jsonPath) {
super.addCommandArguments("--security-opt seccomp=" + jsonPath);
return this;
}
/**
* Set no-new-privileges option.
* @return the self
*/
public DockerRunCommand setNoNewPrivileges() {
super.addCommandArguments("--security-opt no-new-privileges");
return this;
}
/**
* Set cpuShares.
* @param cpuShares the cpu shares
* @return the self
*/
public DockerRunCommand setCpuShares(int cpuShares) {
// Zero sets to default of 1024. 2 is the minimum value otherwise
if (cpuShares > 0 && cpuShares < 2) {
cpuShares = 2;
}
super.addCommandArguments("--cpu-shares=" + String.valueOf(cpuShares));
return this;
}
/**
* Set the number of cpus to use.
* @param cpus the number of cpus
* @return the self
*/
public DockerRunCommand setCpus(double cpus) {
super.addCommandArguments("--cpus=" + cpus);
return this;
}
/**
* Set the number of memory in MB to use.
* @param memoryMb the number of memory in MB
* @return the self
*/
public DockerRunCommand setMemoryMb(int memoryMb) {
super.addCommandArguments("--memory=" + memoryMb + "m");
return this;
}
/**
* Set the output container id file location.
* @param cidFile the container id file
* @return the self
*/
public DockerRunCommand setCidFile(String cidFile) {
super.addCommandArguments("--cidfile=" + cidFile);
return this;
}
/**
* Get the full command.
* @return the full command
*/
@Override
public String getCommandWithArguments() {
List<String> argList = new ArrayList<>();
argList.add(super.getCommandWithArguments());
argList.add(image);
if (overrideCommandWithArgs != null) {
argList.addAll(overrideCommandWithArgs);
}
return StringUtils.join(argList, " ");
}
}