You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@slider.apache.org by go...@apache.org on 2015/05/05 05:25:54 UTC
incubator-slider git commit: SLIDER-780 Support for Docker based
application packaging in Slider (Thomas Liu via gourksaha)
Repository: incubator-slider
Updated Branches:
refs/heads/develop f61dc2be5 -> 5a3a64392
SLIDER-780 Support for Docker based application packaging in Slider (Thomas Liu via gourksaha)
Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/5a3a6439
Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/5a3a6439
Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/5a3a6439
Branch: refs/heads/develop
Commit: 5a3a64392c51d34c4a4c95bb6047295bc3a6e213
Parents: f61dc2b
Author: Gour Saha <go...@apache.org>
Authored: Mon May 4 20:14:30 2015 -0700
Committer: Gour Saha <go...@apache.org>
Committed: Mon May 4 20:14:30 2015 -0700
----------------------------------------------------------------------
.../src/main/python/agent/ActionQueue.py | 24 +-
.../src/main/python/agent/DockerManager.py | 190 ++++++++
slider-agent/src/main/python/agent/main.py | 5 +-
.../apache/slider/common/tools/SliderUtils.java | 5 +
.../providers/agent/AgentProviderService.java | 448 ++++++++++++++++++-
.../application/metadata/AbstractComponent.java | 1 +
.../agent/application/metadata/Component.java | 12 +-
.../application/metadata/DockerContainer.java | 132 ++++++
.../metadata/DockerContainerInputFile.java | 32 ++
.../metadata/DockerContainerMount.java | 60 +++
.../metadata/DockerContainerPort.java | 66 +++
.../web/rest/agent/ExecutionCommand.java | 57 +++
12 files changed, 1003 insertions(+), 29 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-agent/src/main/python/agent/ActionQueue.py
----------------------------------------------------------------------
diff --git a/slider-agent/src/main/python/agent/ActionQueue.py b/slider-agent/src/main/python/agent/ActionQueue.py
index e5e2d1a..ca68d5d 100644
--- a/slider-agent/src/main/python/agent/ActionQueue.py
+++ b/slider-agent/src/main/python/agent/ActionQueue.py
@@ -30,6 +30,7 @@ from AgentConfig import AgentConfig
from AgentToggleLogger import AgentToggleLogger
from CommandStatusDict import CommandStatusDict
from CustomServiceOrchestrator import CustomServiceOrchestrator
+from DockerManager import DockerManager
import Constants
@@ -51,6 +52,8 @@ class ActionQueue(threading.Thread):
STORE_APPLIED_CONFIG = 'record_config'
AUTO_RESTART = 'auto_restart'
+
+ docker_mode = False
def __init__(self, config, controller, agentToggleLogger):
super(ActionQueue, self).__init__()
@@ -67,7 +70,8 @@ class ActionQueue(threading.Thread):
self.customServiceOrchestrator = CustomServiceOrchestrator(config,
controller,
self.queueOutAgentToggleLogger)
-
+ self.dockerManager = DockerManager(self.tmpdir, config.getWorkRootPath(), self.customServiceOrchestrator)
+
def stop(self):
self._stop.set()
@@ -123,9 +127,9 @@ class ActionQueue(threading.Thread):
clusterName = command['clusterName']
commandId = command['commandId']
if 'package' in command:
- self.componentPackage = command['package']
+ self.componentPackage = command['package']
else:
- self.componentPackage = ''
+ self.componentPackage = ''
logger.info("Package received: " + self.componentPackage)
@@ -165,8 +169,12 @@ class ActionQueue(threading.Thread):
logger.info("Running command: " + str(command))
- # running command
- commandresult = self.customServiceOrchestrator.runCommand(command,
+ if 'configurations' in command and 'docker' in command['configurations']:
+ self.docker_mode = True
+ commandresult = self.dockerManager.execute_command(command, store_config or store_command)
+ else:
+ # running command
+ commandresult = self.customServiceOrchestrator.runCommand(command,
in_progress_status[
'tmpout'],
in_progress_status[
@@ -223,7 +231,11 @@ class ActionQueue(threading.Thread):
service = command['serviceName']
component = command['componentName']
reportResult = CommandStatusDict.shouldReportResult(command)
- component_status = self.customServiceOrchestrator.requestComponentStatus(command)
+ component_status = None
+ if self.docker_mode:
+ component_status = self.dockerManager.query_status(command)
+ else:
+ component_status = self.customServiceOrchestrator.requestComponentStatus(command)
result = {"componentName": component,
"msg": "",
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-agent/src/main/python/agent/DockerManager.py
----------------------------------------------------------------------
diff --git a/slider-agent/src/main/python/agent/DockerManager.py b/slider-agent/src/main/python/agent/DockerManager.py
new file mode 100644
index 0000000..7cab24c
--- /dev/null
+++ b/slider-agent/src/main/python/agent/DockerManager.py
@@ -0,0 +1,190 @@
+import logging
+import os
+import subprocess
+from AgentConfig import AgentConfig
+import Constants
+
+logger = logging.getLogger()
+
+class DockerManager():
+ stored_status_command = ''
+ stored_command = ''
+
+ def __init__(self, tmpdir, workroot, customServiceOrchestrator):
+ self.tmpdir = tmpdir
+ self.workroot = workroot
+ self.customServiceOrchestrator = customServiceOrchestrator
+
+ def execute_command(self, command, store_command=False):
+ returncode = ''
+ out = ''
+ err = ''
+
+ if store_command:
+ logger.info("Storing applied config: " + str(command['configurations']))
+ self.stored_command = command
+ status_command_str = self.extract_config_from_command(command, 'docker.status_command')
+ if status_command_str:
+ self.stored_status_command = status_command_str.split(" ")
+ logger.info("status command" + str(self.stored_status_command))
+
+ if command['roleCommand'] == 'INSTALL':
+ returncode, out, err = self.pull_image(command)
+ logger.info("docker pull result: " + str(returncode) + ";")
+ if command['roleCommand'] == 'START':
+ returncode, out, err = self.start_container(command)
+ # need check
+ return {Constants.EXIT_CODE:returncode, 'stdout':out, 'stderr':err}
+
+ def pull_image(self, command):
+ logger.info(str( command['configurations']))
+ command_path = self.extract_config_from_command(command, 'docker.command_path')
+ imageName = self.extract_config_from_command(command, 'docker.image_name')
+
+ docker_command = [command_path, 'pull', imageName]
+ logger.info("docker pull command: " + str(docker_command))
+ return self.execute_command_on_linux(docker_command)
+
+
+ def extract_config_from_command(self, command, field):
+ value = ''
+ if 'configurations' in command:
+ if 'docker' in command['configurations']:
+ if field in command['configurations']['docker']:
+ logger.info(field + ': ' + str( command['configurations']['docker'][field]))
+ value = command['configurations']['docker'][field]
+ return value
+
+
+ # will evolve into a class hierarch, linux and windows
+ def execute_command_on_linux(self, docker_command):
+ proc = subprocess.Popen(docker_command, stdout = subprocess.PIPE)
+ out, err = proc.communicate()
+ logger.info("docker command output: " + str(out) + " err: " + str(err))
+ return proc.returncode, out, err
+
+
+ def start_container(self, command):
+ #extracting param needed by docker run from the command passed from AM
+ command_path = self.extract_config_from_command(command, 'docker.command_path')
+ imageName = self.extract_config_from_command(command, 'docker.image_name')
+ options = self.extract_config_from_command(command, 'docker.options')
+ containerPort = self.extract_config_from_command(command, 'docker.containerPort')
+ mounting_directory = self.extract_config_from_command(command, 'docker.mounting_directory')
+ memory_usage = self.extract_config_from_command(command, "docker.memory_usage")
+ additional_param = self.extract_config_from_command(command, 'docker.additional_param')
+ input_file_local_path = self.extract_config_from_command(command, 'docker.input_file.local_path')
+ input_file_mount_path = self.extract_config_from_command(command, 'docker.input_file.mount_path')
+
+ docker_command = [command_path, "run"]
+
+ #docker_command.append("--net=host")
+
+ if options:
+ docker_command = self.add_docker_run_options_to_command(docker_command, options)
+ if containerPort:
+ logger.info("container port is not null")
+ self.add_port_binding_to_command(docker_command, command, containerPort)
+ if mounting_directory:
+ self.add_mnted_dir_to_command(docker_command, "/docker_use", mounting_directory)
+ if input_file_local_path:
+ self.add_mnted_dir_to_command(docker_command, "/inputDir", input_file_mount_path)
+ if memory_usage:
+ self.add_resource_restriction(docker_command, memory_usage)
+ self.add_container_name_to_command(docker_command, command)
+ docker_command.append(imageName)
+ if additional_param:
+ docker_command = self.add_additional_param_to_command(docker_command, additional_param)
+ logger.info("docker run command: " + str(docker_command))
+ return self.execute_command_on_linux(docker_command)
+
+ def add_docker_run_options_to_command(self, docker_command, options):
+ return docker_command + options.split(" ")
+
+ def add_port_binding_to_command(self, docker_command, command, containerPort):
+ docker_command.append("-p")
+ hostPort = self.extract_config_from_command(command, 'docker.hostPort')
+
+ if not hostPort:
+ #this is the list of allowed port range specified in appConfig
+ allowedPorts = self.customServiceOrchestrator.get_allowed_ports(command)
+ #if the user specify hostPort in appConfig, then we use it, otherwise allocate it
+ allocated_for_this_component_format = "${{{0}.ALLOCATED_PORT}}"
+ component = command['componentName']
+ port_allocation_req = allocated_for_this_component_format.format(component)
+ hostPort = self.customServiceOrchestrator.allocate_ports(port_allocation_req, port_allocation_req, allowedPorts)
+ docker_command.append(hostPort+":"+containerPort)
+
+ def add_mnted_dir_to_command(self, docker_command, host_dir, container_dir):
+ docker_command.append("-v")
+ tmp_mount_dir = self.workroot + host_dir
+ docker_command.append(tmp_mount_dir+":"+container_dir)
+
+ def add_container_name_to_command(self, docker_command, command):
+ docker_command.append("--name")
+ docker_command.append(self.get_container_id(command))
+
+ def add_additional_param_to_command(self, docker_command, additional_param):
+ return docker_command + additional_param.split(" ")
+
+ def get_container_id(self, command):
+ # will make this more resilient to changes
+ return self.tmpdir[-30:-2]
+
+ def add_resource_restriction(self, docker_command, memory_usage):
+ docker_command.append("-m")
+ docker_command.append(memory_usage)
+
+ def query_status(self, command):
+ if command['roleCommand'] == "GET_CONFIG":
+ return self.getConfig(command)
+ else:
+ returncode = ''
+ out = ''
+ err = ''
+ status_command_str = self.extract_config_from_command(command, 'docker.status_command')
+ if status_command_str:
+ self.stored_status_command = status_command_str.split(" ")
+ logger.info("in query_status, got stored status command" + str(self.stored_status_command))
+ if self.stored_status_command:
+ logger.info("stored status command to run: " + str(self.stored_status_command))
+ returncode, out, err = self.execute_command_on_linux(self.stored_status_command)
+ logger.info("status of the app in docker container: " + str(returncode) + ";" + str(out) + ";" + str(err))
+ return {Constants.EXIT_CODE:returncode, 'stdout':out, 'stderr':err}
+
+ def getConfig(self, command):
+ logger.info("get config command: " + str(command))
+ if 'configurations' in self.stored_command:
+ if 'commandParams' in command and 'config_type' in command['commandParams']:
+ config_type = command['commandParams']['config_type']
+ logger.info("Requesting applied config for type {0}".format(config_type))
+ if config_type in self.stored_command['configurations']:
+ logger.info("get config result: " + self.stored_command['configurations'][config_type])
+ return {
+ 'configurations': {config_type: self.stored_command['configurations'][config_type]}
+ }
+ else:
+ return {
+ 'configurations': {}
+ }
+ pass
+ else:
+ logger.info("Requesting all applied config." + str(self.stored_command['configurations']))
+ return {
+ 'configurations': self.stored_command['configurations']
+ }
+ pass
+ else:
+ return {
+ 'configurations': {}
+ }
+ pass
+
+ def stop_container(self):
+ docker_command = ["/usr/bin/docker", "stop"]
+ docker_command.append(self.get_container_id(docker_command))
+ logger.info("docker stop: " + str(docker_command))
+ code, out, err = self.execute_command_on_linux(docker_command)
+ logger.info("output: " + str(out))
+
+
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-agent/src/main/python/agent/main.py
----------------------------------------------------------------------
diff --git a/slider-agent/src/main/python/agent/main.py b/slider-agent/src/main/python/agent/main.py
index f592d08..127ba9d 100644
--- a/slider-agent/src/main/python/agent/main.py
+++ b/slider-agent/src/main/python/agent/main.py
@@ -41,7 +41,7 @@ logger = logging.getLogger()
IS_WINDOWS = platform.system() == "Windows"
formatstr = "%(levelname)s %(asctime)s %(filename)s:%(lineno)d - %(message)s"
agentPid = os.getpid()
-
+controller = None
configFileRelPath = "infra/conf/agent.ini"
logFileName = "slider-agent.log"
@@ -54,6 +54,8 @@ def signal_handler(signum, frame):
if os.getpid() != agentPid:
os._exit(0)
logger.info('signal received, exiting.')
+ if controller is not None:
+ tmpdir = controller.actionQueue.dockerManager.stop_container()
ProcessHelper.stopAgent()
@@ -287,6 +289,7 @@ def main():
# Launch Controller communication
controller = Controller(agentConfig)
controller.start()
+
try:
while controller.is_alive():
controller.join(timeout=1.0)
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java b/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
index 4fcfed1..c06aa4a 100644
--- a/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
+++ b/slider-core/src/main/java/org/apache/slider/common/tools/SliderUtils.java
@@ -145,6 +145,11 @@ public final class SliderUtils {
*/
public static final String PYTHON = "python";
+ /**
+ * name of docker program
+ */
+ public static final String DOCKER = "docker";
+
private SliderUtils() {
}
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
index f806157..b3c513a 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/agent/AgentProviderService.java
@@ -20,6 +20,7 @@ package org.apache.slider.providers.agent;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
+
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
@@ -64,6 +65,7 @@ import org.apache.slider.providers.AbstractProviderService;
import org.apache.slider.providers.ProviderCore;
import org.apache.slider.providers.ProviderRole;
import org.apache.slider.providers.ProviderUtils;
+import org.apache.slider.providers.agent.application.metadata.AbstractComponent;
import org.apache.slider.providers.agent.application.metadata.Application;
import org.apache.slider.providers.agent.application.metadata.CommandScript;
import org.apache.slider.providers.agent.application.metadata.Component;
@@ -72,6 +74,7 @@ import org.apache.slider.providers.agent.application.metadata.ComponentExport;
import org.apache.slider.providers.agent.application.metadata.ComponentsInAddonPackage;
import org.apache.slider.providers.agent.application.metadata.ConfigFile;
import org.apache.slider.providers.agent.application.metadata.DefaultConfig;
+import org.apache.slider.providers.agent.application.metadata.DockerContainer;
import org.apache.slider.providers.agent.application.metadata.Export;
import org.apache.slider.providers.agent.application.metadata.ExportGroup;
import org.apache.slider.providers.agent.application.metadata.Metainfo;
@@ -117,6 +120,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeMap;
@@ -124,6 +128,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
import static org.apache.slider.server.appmaster.web.rest.RestPaths.SLIDER_PATH_AGENTS;
@@ -476,7 +481,8 @@ public class AgentProviderService extends AbstractProviderService implements
operation.add(debugCmd);
}
- operation.add("> " + ApplicationConstants.LOG_DIR_EXPANSION_VAR + "/" + AgentKeys.AGENT_OUT_FILE + " 2>&1");
+ operation.add("> " + ApplicationConstants.LOG_DIR_EXPANSION_VAR + "/"
+ + AgentKeys.AGENT_OUT_FILE + " 2>&1");
launcher.addCommand(operation.build());
@@ -823,15 +829,18 @@ public class AgentProviderService extends AbstractProviderService implements
CommandScript cmdScript = getScriptPathForMasterPackage(roleName);
List<ComponentCommand> commands = getMetaInfo().getApplicationComponent(roleName).getCommands();
- if ((cmdScript == null || cmdScript.getScript() == null) && commands.size() == 0) {
- log.error("role.script is unavailable for {}. Commands will not be sent.",
+ if (!isDockerContainer(roleName)
+ && (cmdScript == null || cmdScript.getScript() == null)
+ && commands.size() == 0) {
+ log.error(
+ "role.script is unavailable for {}. Commands will not be sent.",
roleName);
return response;
}
String scriptPath = null;
long timeout = 600L;
- if(cmdScript != null) {
+ if (cmdScript != null) {
scriptPath = cmdScript.getScript();
timeout = cmdScript.getTimeout();
}
@@ -907,7 +916,9 @@ public class AgentProviderService extends AbstractProviderService implements
componentStatus.getNextPkgToInstall(), command.toString());
if (command == Command.INSTALL) {
log.info("Installing {} on {}.", roleName, containerId);
- if (scriptPath != null) {
+ if (isDockerContainer(roleName)){
+ addInstallDockerCommand(roleName, containerId, response, null, timeout);
+ } else if (scriptPath != null) {
addInstallCommand(roleName, containerId, response, scriptPath,
null, timeout, null);
} else {
@@ -955,7 +966,9 @@ public class AgentProviderService extends AbstractProviderService implements
boolean canExecute = commandOrder.canExecute(roleName, command, getComponentStatuses().values());
if (canExecute) {
log.info("Starting {} on {}.", roleName, containerId);
- if (scriptPath != null) {
+ if (isDockerContainer(roleName)){
+ addStartDockerCommand(roleName, containerId, response, null, timeout, false);
+ } else if (scriptPath != null) {
addStartCommand(roleName,
containerId,
response,
@@ -1004,10 +1017,14 @@ public class AgentProviderService extends AbstractProviderService implements
&& command == Command.NOP) {
if (!componentStatus.getConfigReported()) {
log.info("Requesting applied config for {} on {}.", roleName, containerId);
- addGetConfigCommand(roleName, containerId, response);
+ if (isDockerContainer(roleName)){
+ addGetConfigDockerCommand(roleName, containerId, response);
+ } else {
+ addGetConfigCommand(roleName, containerId, response);
+ }
}
}
-
+
// if restart is required then signal
response.setRestartEnabled(false);
if (componentStatus.getState() == State.STARTED
@@ -1016,7 +1033,7 @@ public class AgentProviderService extends AbstractProviderService implements
}
//If INSTALL_FAILED and no INSTALL is scheduled let the agent fail
- if(componentStatus.getState() == State.INSTALL_FAILED
+ if (componentStatus.getState() == State.INSTALL_FAILED
&& command == Command.NOP) {
log.warn("Sending terminate signal to container that failed installation: {}", label);
response.setTerminateAgent(true);
@@ -1031,6 +1048,14 @@ public class AgentProviderService extends AbstractProviderService implements
return response;
}
+ private boolean isDockerContainer(String roleName) {
+ String type = getMetaInfo().getApplicationComponent(roleName).getType();
+ if (SliderUtils.isSet(type)) {
+ return type.toLowerCase().equals(SliderUtils.DOCKER);
+ }
+ return false;
+ }
+
protected void processAllocatedPorts(String fqdn,
String roleName,
String containerId,
@@ -1422,7 +1447,7 @@ public class AgentProviderService extends AbstractProviderService implements
for(Map.Entry<String, ExportEntry> logEntry : folderExports.entrySet())
{
String componentName = logEntry.getValue().getTag();
- if(!perComponentList.containsKey(componentName)) {
+ if (!perComponentList.containsKey(componentName)) {
perComponentList.put(componentName, new ArrayList<ExportEntry>());
}
perComponentList.get(componentName).add(logEntry.getValue());
@@ -1567,7 +1592,7 @@ public class AgentProviderService extends AbstractProviderService implements
Map<String, String> simpleEntries = new HashMap<String, String>();
for (Map.Entry<String, List<ExportEntry>> entry : entries.entrySet()) {
List<ExportEntry> exports = entry.getValue();
- if(SliderUtils.isNotEmpty(exports)) {
+ if (SliderUtils.isNotEmpty(exports)) {
// there is no support for multiple exports per name - so extract only the first one
simpleEntries.put(entry.getKey(), entry.getValue().get(0).getValue());
}
@@ -1884,12 +1909,12 @@ public class AgentProviderService extends AbstractProviderService implements
Map<String, Map<String, String>> configurations = buildCommandConfigurations(appConf, containerId, componentName);
cmd.setConfigurations(configurations);
- if(SliderUtils.isSet(scriptPath)) {
+ if (SliderUtils.isSet(scriptPath)) {
cmd.setCommandParams(commandParametersSet(scriptPath, timeout, false));
} else {
// assume it to be default shell command
ComponentCommand effectiveCommand = compCmd;
- if(effectiveCommand == null) {
+ if (effectiveCommand == null) {
effectiveCommand = ComponentCommand.getDefaultComponentCommand("INSTALL");
}
cmd.setCommandParams(commandParametersSet(effectiveCommand, timeout, false));
@@ -1903,6 +1928,85 @@ public class AgentProviderService extends AbstractProviderService implements
log.debug("command looks like: {} ", cmd);
}
+ @VisibleForTesting
+ protected void addInstallDockerCommand(String componentName,
+ String containerId,
+ HeartBeatResponse response,
+ ComponentCommand compCmd,
+ long timeout)
+ throws SliderException {
+ assert getAmState().isApplicationLive();
+ ConfTreeOperations appConf = getAmState().getAppConfSnapshot();
+
+ ExecutionCommand cmd = new ExecutionCommand(AgentCommandType.EXECUTION_COMMAND);
+ prepareExecutionCommand(cmd);
+ String clusterName = getClusterName();
+ cmd.setClusterName(clusterName);
+ cmd.setRoleCommand(Command.INSTALL.toString());
+ cmd.setServiceName(clusterName);
+ cmd.setComponentName(componentName);
+ cmd.setRole(componentName);
+ Map<String, String> hostLevelParams = new TreeMap<String, String>();
+ hostLevelParams.put(PACKAGE_LIST, getPackageList());
+ hostLevelParams.put(CONTAINER_ID, containerId);
+ cmd.setHostLevelParams(hostLevelParams);
+
+ Map<String, Map<String, String>> configurations = buildCommandConfigurations(
+ appConf, containerId, componentName);
+ cmd.setConfigurations(configurations);
+
+ ComponentCommand effectiveCommand = compCmd;
+ if (compCmd == null) {
+ effectiveCommand = new ComponentCommand();
+ effectiveCommand.setName("INSTALL");
+ effectiveCommand.setExec("DEFAULT");
+ }
+ cmd.setCommandParams(setCommandParameters(effectiveCommand, timeout, false));
+ configurations.get("global").put("exec_cmd", effectiveCommand.getExec());
+
+ cmd.setHostname(getClusterInfoPropertyValue(StatusKeys.INFO_AM_HOSTNAME));
+ cmd.addContainerDetails(componentName, getMetaInfo());
+
+ Map<String, String> dockerConfig = new HashMap<String, String>();
+ dockerConfig.put(
+ "docker.command_path",
+ getConfigFromMetaInfoWithAppConfigOverriding(componentName,
+ "commandPath"));
+ dockerConfig.put("docker.image_name",
+ getConfigFromMetaInfo(componentName, "image"));
+ configurations.put("docker", dockerConfig);
+
+ log.debug("Docker- command: {}", cmd.toString());
+
+ response.addExecutionCommand(cmd);
+ }
+
+ private Map<String, String> setCommandParameters(String scriptPath,
+ long timeout, boolean recordConfig) {
+ Map<String, String> cmdParams = new TreeMap<String, String>();
+ cmdParams.put("service_package_folder",
+ "${AGENT_WORK_ROOT}/work/app/definition/package");
+ cmdParams.put("script", scriptPath);
+ cmdParams.put("schema_version", "2.0");
+ cmdParams.put("command_timeout", Long.toString(timeout));
+ cmdParams.put("script_type", AbstractComponent.TYPE_PYTHON);
+ cmdParams.put("record_config", Boolean.toString(recordConfig));
+ return cmdParams;
+ }
+
+ private Map<String, String> setCommandParameters(ComponentCommand compCmd,
+ long timeout, boolean recordConfig) {
+ Map<String, String> cmdParams = new TreeMap<String, String>();
+ cmdParams.put("service_package_folder",
+ "${AGENT_WORK_ROOT}/work/app/definition/package");
+ cmdParams.put("command", compCmd.getExec());
+ cmdParams.put("schema_version", "2.0");
+ cmdParams.put("command_timeout", Long.toString(timeout));
+ cmdParams.put("script_type", compCmd.getType());
+ cmdParams.put("record_config", Boolean.toString(recordConfig));
+ return cmdParams;
+ }
+
private Map<String, Map<String, String>> buildComponentConfigurations(
ConfTreeOperations appConf) {
return appConf.getComponents();
@@ -1981,6 +2085,11 @@ public class AgentProviderService extends AbstractProviderService implements
throws SliderException {
assert getAmState().isApplicationLive();
ConfTreeOperations appConf = getAmState().getAppConfSnapshot();
+ if (isDockerContainer(componentName)) {
+ addStatusDockerCommand(componentName, containerId, response, scriptPath,
+ timeout);
+ return;
+ }
StatusCommand cmd = new StatusCommand();
String clusterName = getClusterName();
@@ -2006,6 +2115,307 @@ public class AgentProviderService extends AbstractProviderService implements
}
@VisibleForTesting
+ protected void addStatusDockerCommand(String componentName,
+ String containerId,
+ HeartBeatResponse response,
+ String scriptPath,
+ long timeout)
+ throws SliderException {
+ assert getAmState().isApplicationLive();
+ ConfTreeOperations appConf = getAmState().getAppConfSnapshot();
+
+ StatusCommand cmd = new StatusCommand();
+ String clusterName = getClusterName();
+
+ cmd.setCommandType(AgentCommandType.STATUS_COMMAND);
+ cmd.setComponentName(componentName);
+ cmd.setServiceName(clusterName);
+ cmd.setClusterName(clusterName);
+ cmd.setRoleCommand(StatusCommand.STATUS_COMMAND);
+
+ Map<String, String> hostLevelParams = new TreeMap<String, String>();
+ hostLevelParams.put(JAVA_HOME, appConf.getGlobalOptions().getMandatoryOption(JAVA_HOME));
+ hostLevelParams.put(CONTAINER_ID, containerId);
+ cmd.setHostLevelParams(hostLevelParams);
+
+ cmd.setCommandParams(setCommandParameters(scriptPath, timeout, false));
+
+ Map<String, Map<String, String>> configurations = buildCommandConfigurations(
+ appConf, containerId, componentName);
+ Map<String, String> dockerConfig = new HashMap<String, String>();
+ String statusCommand = getConfigFromMetaInfoWithAppConfigOverriding(componentName, "statusCommand");
+ if (statusCommand == null) {
+ statusCommand = "docker top "
+ + containerId.substring(containerId.indexOf("_") + 1)
+ + " | grep \"\"";// default value
+ }
+ dockerConfig.put("docker.status_command",statusCommand);
+ configurations.put("docker", dockerConfig);
+ cmd.setConfigurations(configurations);
+ log.debug("Docker- status {}", cmd);
+ response.addStatusCommand(cmd);
+ }
+
+ @VisibleForTesting
+ protected void addGetConfigDockerCommand(String componentName,
+ String containerId, HeartBeatResponse response) throws SliderException {
+ assert getAmState().isApplicationLive();
+
+ StatusCommand cmd = new StatusCommand();
+ String clusterName = getClusterName();
+
+ cmd.setCommandType(AgentCommandType.STATUS_COMMAND);
+ cmd.setComponentName(componentName);
+ cmd.setServiceName(clusterName);
+ cmd.setClusterName(clusterName);
+ cmd.setRoleCommand(StatusCommand.GET_CONFIG_COMMAND);
+ Map<String, String> hostLevelParams = new TreeMap<String, String>();
+ hostLevelParams.put(CONTAINER_ID, containerId);
+ cmd.setHostLevelParams(hostLevelParams);
+
+ hostLevelParams.put(CONTAINER_ID, containerId);
+
+ ConfTreeOperations appConf = getAmState().getAppConfSnapshot();
+ Map<String, Map<String, String>> configurations = buildCommandConfigurations(
+ appConf, containerId, componentName);
+ Map<String, String> dockerConfig = new HashMap<String, String>();
+ String statusCommand = getConfigFromMetaInfoWithAppConfigOverriding(componentName, "statusCommand");
+ if (statusCommand == null) {
+ statusCommand = "docker top "
+ + containerId.substring(containerId.indexOf("_") + 1)
+ + " | grep \"\"";// default value
+ }
+ dockerConfig.put("docker.status_command",statusCommand);
+ configurations.put("docker", dockerConfig);
+
+ cmd.setConfigurations(configurations);
+ log.debug("Docker- getconfig command {}", cmd);
+
+ response.addStatusCommand(cmd);
+ }
+
+ private String getConfigFromMetaInfoWithAppConfigOverriding(String componentName, String configName){
+ ConfTreeOperations appConf = getAmState().getAppConfSnapshot();
+ String containerName = getMetaInfo().getApplicationComponent(componentName)
+ .getDockerContainers().get(0).getName();
+ String composedConfigName = null;
+ String appConfigValue = null;
+ //if the configName is about port , mount, inputfile, then check differently
+ if (configName.equals("containerPort") || configName.equals("hostPort")){
+ composedConfigName = containerName + ".ports." + configName;
+ } else
+ if (configName.equals("containerMount")
+ || configName.equals("hostMount")){
+ composedConfigName = containerName + ".mounts." + configName;
+ } else
+ if (configName.equals("containerPath")
+ || configName.equals("fileLocalPath")) {
+ composedConfigName = containerName + ".inputFiles." + configName;
+ } else {
+ composedConfigName = containerName + "." + configName;
+ }
+ appConfigValue = appConf.getComponentOpt(componentName, composedConfigName,
+ null);
+ log.debug(
+ "Docker- value from appconfig component: {} configName: {} value: {}",
+ componentName, composedConfigName, appConfigValue);
+ if (appConfigValue == null) {
+ appConfigValue = getConfigFromMetaInfo(componentName, configName);
+ log.debug(
+ "Docker- value from metainfo component: {} configName: {} value: {}",
+ componentName, configName, appConfigValue);
+
+ }
+ return appConfigValue;
+ }
+
+ @VisibleForTesting
+ protected void addStartDockerCommand(String componentName,
+ String containerId, HeartBeatResponse response,
+ ComponentCommand startCommand, long timeout, boolean isMarkedAutoRestart)
+ throws
+ SliderException {
+ assert getAmState().isApplicationLive();
+ ConfTreeOperations appConf = getAmState().getAppConfSnapshot();
+ ConfTreeOperations internalsConf = getAmState().getInternalsSnapshot();
+
+ ExecutionCommand cmd = new ExecutionCommand(AgentCommandType.EXECUTION_COMMAND);
+ prepareExecutionCommand(cmd);
+ String clusterName = internalsConf.get(OptionKeys.APPLICATION_NAME);
+ String hostName = getClusterInfoPropertyValue(StatusKeys.INFO_AM_HOSTNAME);
+ cmd.setHostname(hostName);
+ cmd.setClusterName(clusterName);
+ cmd.setRoleCommand(Command.START.toString());
+ cmd.setServiceName(clusterName);
+ cmd.setComponentName(componentName);
+ cmd.setRole(componentName);
+ Map<String, String> hostLevelParams = new TreeMap<>();
+ hostLevelParams.put(CONTAINER_ID, containerId);
+ cmd.setHostLevelParams(hostLevelParams);
+
+ Map<String, String> roleParams = new TreeMap<>();
+ cmd.setRoleParams(roleParams);
+ cmd.getRoleParams().put("auto_restart", Boolean.toString(isMarkedAutoRestart));
+ startCommand = new ComponentCommand();
+ startCommand.setName("START");
+ startCommand.setType("docker");
+ startCommand.setExec("exec");
+ cmd.setCommandParams(setCommandParameters(startCommand, timeout, true));
+
+ Map<String, Map<String, String>> configurations = buildCommandConfigurations(
+ appConf, containerId, componentName);
+
+ log.info("before resolution: " + appConf.toString());
+ resolveVariablesForComponentAppConfigs(appConf, componentName, containerId);
+ log.info("after resolution: " + appConf.toString());
+
+ Map<String, String> dockerConfig = new HashMap<String, String>();
+ dockerConfig.put(
+ "docker.command_path",
+ getConfigFromMetaInfoWithAppConfigOverriding(componentName,
+ "commandPath"));
+ dockerConfig.put("docker.image_name",
+ getConfigFromMetaInfo(componentName, "image"));
+ // options should always have -d
+ String options = getConfigFromMetaInfoWithAppConfigOverriding(
+ componentName, "options");
+ options = options + " -d";
+ dockerConfig.put("docker.options", options);
+ // options should always have -d
+ dockerConfig.put(
+ "docker.containerPort",
+ getConfigFromMetaInfoWithAppConfigOverriding(componentName,
+ "containerPort"));
+ dockerConfig
+ .put(
+ "docker.hostPort",
+ getConfigFromMetaInfoWithAppConfigOverriding(componentName,
+ "hostPort"));
+
+ dockerConfig.put(
+ "docker.mounting_directory",
+ getConfigFromMetaInfoWithAppConfigOverriding(componentName,
+ "containerMount"));
+ dockerConfig
+ .put(
+ "docker.host_mounting_directory",
+ getConfigFromMetaInfoWithAppConfigOverriding(componentName,
+ "hostMount"));
+
+ dockerConfig.put("docker.additional_param",
+ getConfigFromMetaInfoWithAppConfigOverriding(componentName, "additionalParam"));
+
+ dockerConfig.put("docker.input_file.mount_path", getConfigFromMetaInfo(
+ componentName, "containerPath"));
+ configurations.put("docker", dockerConfig);
+ String statusCommand = getConfigFromMetaInfoWithAppConfigOverriding(
+ componentName, "statusCommand");
+ if (statusCommand == null) {
+ statusCommand = "docker top "
+ + containerId.substring(containerId.indexOf("_") + 1)
+ + " | grep \"\"";// default value
+ }
+ dockerConfig.put("docker.status_command",statusCommand);
+
+ cmd.setConfigurations(configurations);
+ // configurations.get("global").put("exec_cmd", startCommand.getExec());
+ cmd.addContainerDetails(componentName, getMetaInfo());
+
+ log.debug("Docker- command: {}", cmd.toString());
+
+ response.addExecutionCommand(cmd);
+ }
+
+ private void resolveVariablesForComponentAppConfigs(
+ ConfTreeOperations appConf, String componentName, String containerId)
+ throws SliderException {
+ Map<String, String> tokens = getStandardTokenMap(appConf, componentName);
+ addRoleRelatedTokens(tokens);
+ log.debug("docker- tokens: {}", tokens);
+
+ MapOperations compConf = appConf.getComponent(componentName);
+ for(Entry<String, String> element: compConf.entrySet()){
+
+ log.debug("docker- key: {} value: {}", element.getKey(), element.getValue());
+
+ Object value = element.getValue();
+ if (value instanceof String){
+ String valueStr = (String)value;
+
+ //resolving host names
+ for (Map.Entry<String,String> token : tokens.entrySet()) {
+ valueStr = valueStr.replaceAll(Pattern.quote(token.getKey()),
+ token.getValue());
+ compConf.put(element.getKey(), valueStr);
+ }
+
+ // resolving container ids
+ if (valueStr.contains("${CONTAINER_ID}")) {
+ valueStr = valueStr.replace("${CONTAINER_ID}",
+ containerId.substring(containerId.indexOf("_") + 1));
+ compConf.put(element.getKey(), valueStr);
+ }
+ }
+ }
+ }
+
+ private String getConfigFromMetaInfo(String componentName, String configName) {
+ String result = null;
+
+ List<DockerContainer> containers = getMetaInfo().getApplicationComponent(
+ componentName).getDockerContainers();// to support multi container per
+ // component later
+ log.debug("Docker- containers metainfo: {}", containers.toString());
+ if (containers.size() > 0) {
+ DockerContainer container = containers.get(0);
+
+ switch (configName) {
+ case "image":
+ result = container.getImage();
+ break;
+ case "statusCommand":
+ result = container.getStatusCommand();
+ break;
+ case "commandPath":
+ result = container.getCommandPath();
+ break;
+ case "options":
+ result = container.getOptions();
+ break;
+ case "containerPort":
+ result = container.getPorts().size() > 0 ? container.getPorts().get(0)
+ .getContainerPort() : null;// to support
+ // multi port
+ // later
+ break;
+ case "hostPort":
+ result = container.getPorts().size() > 0 ? container.getPorts().get(0)
+ .getHostPort() : null;// to support multi
+ // port later
+ break;
+ case "containerMount":
+ result = container.getMounts().size() > 0 ? container.getMounts()
+ .get(0).getContainerMount() : null;// to support
+ // multi port
+ // later
+ break;
+ case "hostMount":
+ result = container.getMounts().size() > 0 ? container.getMounts()
+ .get(0).getHostMount() : null;// to support multi
+ // port later
+ break;
+ case "additionalParam":
+ result = container.getAdditionalParam();// to support multi port later
+ break;
+ default:
+ break;
+ }
+ }
+ log.debug("Docker- component: {} configName: {} value: {}", componentName, configName, result);
+ return result;
+ }
+
+ @VisibleForTesting
protected void addGetConfigCommand(String componentName, String containerId, HeartBeatResponse response)
throws SliderException {
assert getAmState().isApplicationLive();
@@ -2060,10 +2470,10 @@ public class AgentProviderService extends AbstractProviderService implements
Map<String, Map<String, String>> configurations = buildCommandConfigurations(appConf, containerId, componentName);
cmd.setConfigurations(configurations);
- if(SliderUtils.isSet(scriptPath)) {
+ if (SliderUtils.isSet(scriptPath)) {
cmd.setCommandParams(commandParametersSet(scriptPath, timeout, true));
} else {
- if(startCommand == null) {
+ if (startCommand == null) {
throw new SliderException("Expected START command not found for component " + componentName);
}
cmd.setCommandParams(commandParametersSet(startCommand, timeout, true));
@@ -2097,10 +2507,10 @@ public class AgentProviderService extends AbstractProviderService implements
cmdStop.getRoleParams().put("auto_restart",
Boolean.toString(isMarkedAutoRestart));
- if(SliderUtils.isSet(scriptPath)) {
+ if (SliderUtils.isSet(scriptPath)) {
cmdStop.setCommandParams(commandParametersSet(scriptPath, timeout, true));
} else {
- if(stopCommand == null) {
+ if (stopCommand == null) {
stopCommand = ComponentCommand.getDefaultComponentCommand("STOP");
}
cmd.setCommandParams(commandParametersSet(stopCommand, timeout, true));
@@ -2384,10 +2794,10 @@ public class AgentProviderService extends AbstractProviderService implements
config.put("app_container_tag", tags.getTag(roleName, containerId));
// add optional parameters only if they are not already provided
- if(!config.containsKey("pid_file")) {
+ if (!config.containsKey("pid_file")) {
config.put("pid_file", "${AGENT_WORK_ROOT}/app/run/component.pid");
}
- if(!config.containsKey("app_root")) {
+ if (!config.containsKey("app_root")) {
config.put("app_root", "${AGENT_WORK_ROOT}/app/install");
}
}
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractComponent.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractComponent.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractComponent.java
index be3a26c..1b63b58 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractComponent.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/AbstractComponent.java
@@ -27,6 +27,7 @@ import org.codehaus.jackson.annotate.JsonProperty;
public abstract class AbstractComponent implements Validate {
public static final String TYPE_STANDARD = "STANDARD";
public static final String TYPE_DOCKER = "DOCKER";
+ public static final String TYPE_PYTHON = "PYTHON";
public static final String CATEGORY_MASTER = "MASTER";
public static final String CATEGORY_SLAVE = "SLAVE";
public static final String CATEGORY_CLIENT = "CLIENT";
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Component.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Component.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Component.java
index 609ffa1..7099448 100644
--- a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Component.java
+++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/Component.java
@@ -19,7 +19,7 @@ package org.apache.slider.providers.agent.application.metadata;
import org.apache.slider.common.tools.SliderUtils;
import org.apache.slider.core.exceptions.BadConfigException;
import org.apache.slider.core.exceptions.SliderException;
-
+import org.codehaus.jackson.annotate.JsonProperty;
import java.util.ArrayList;
import java.util.List;
@@ -37,7 +37,8 @@ public class Component extends AbstractComponent {
String compExports;
String type = TYPE_STANDARD;
List<ComponentExport> componentExports = new ArrayList<>();
-
+ List<DockerContainer> dockerContainers = new ArrayList<>();
+
public Component() {
}
@@ -92,7 +93,12 @@ public class Component extends AbstractComponent {
public String getMinInstanceCount() {
return minInstanceCount;
}
-
+
+ @JsonProperty("dockerContainers")
+ public List<DockerContainer> getDockerContainers() {
+ return this.dockerContainers;
+ }
+
public Boolean getAutoStartOnFailureBoolean() {
if (SliderUtils.isUnset(getAutoStartOnFailure())) {
return Boolean.FALSE;
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainer.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainer.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainer.java
new file mode 100644
index 0000000..ecd0166
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainer.java
@@ -0,0 +1,132 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import org.apache.slider.core.exceptions.SliderException;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a docker container
+ */
+public class DockerContainer implements Validate {
+ protected static final Logger
+ log = LoggerFactory.getLogger(DockerContainer.class);
+
+ private String name;
+ private String image;
+ private String options;
+ private List<DockerContainerMount> mounts = new ArrayList<>();
+ private List<DockerContainerPort> ports = new ArrayList<>();
+ private String statusCommand;
+ private String commandPath;
+ private String additionalParam;
+ private List<DockerContainerInputFile> inputFiles = new ArrayList<>();
+
+ public DockerContainer() {
+ }
+
+ @JsonProperty("mounts")
+ public List<DockerContainerMount> getMounts() { return this.mounts; }
+
+ @JsonProperty("ports")
+ public List<DockerContainerPort> getPorts() {
+ return this.ports;
+ }
+
+ @JsonProperty("inputFiles")
+ public List<DockerContainerInputFile> getInputFiles() {
+ return this.inputFiles;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getImage() {
+ return image;
+ }
+
+ public void setImage(String image) {
+ this.image = image;
+ }
+
+ public String getOptions() {
+ return options;
+ }
+
+ public void setOptions(String options) {
+ this.options = options;
+ }
+
+ @Override
+ public void validate(String version) throws SliderException {
+ Metainfo.checkNonNull(getName(), "name", "dockerContainer");
+ Metainfo.checkNonNull(getImage(), "image", "dockerContainer");
+ for (DockerContainerMount dcm : getMounts()) {
+ dcm.validate(version);
+ }
+ for (DockerContainerPort dcp : getPorts()) {
+ dcp.validate(version);
+ }
+ }
+
+ public String getStatusCommand() {
+ return statusCommand;
+ }
+
+ public void setStatusCommand(String statusCommand) {
+ this.statusCommand = statusCommand;
+ }
+
+ public String getCommandPath() {
+ return commandPath;
+ }
+
+ public void setCommandPath(String commandPath) {
+ this.commandPath = commandPath;
+ }
+
+ public String getAdditionalParam() {
+ return additionalParam;
+ }
+
+ public void setAdditionalParam(String additionalParam) {
+ this.additionalParam = additionalParam;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder("DockerContainer [name=")
+ .append(name).append(", image=").append(image).append(", options=")
+ .append(options).append(", mounts=").append(mounts).append(", ports=")
+ .append(ports).append(", statusCommand=").append(statusCommand)
+ .append(", commandPath=").append(commandPath).append(", additionalParam=")
+ .append(additionalParam).append(", inputFiles=").append(inputFiles).append("]");
+ return result.toString();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerInputFile.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerInputFile.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerInputFile.java
new file mode 100644
index 0000000..fa6eacb
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerInputFile.java
@@ -0,0 +1,32 @@
+package org.apache.slider.providers.agent.application.metadata;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DockerContainerInputFile {
+ protected static final Logger log = LoggerFactory
+ .getLogger(DockerContainerInputFile.class);
+
+ private String containerPath;
+ private String fileLocalPath;
+
+ public DockerContainerInputFile() {
+ }
+
+ public String getContainerMount() {
+ return containerPath;
+ }
+
+ public void setContainerMount(String containerMount) {
+ this.containerPath = containerMount;
+ }
+
+ public String getFileLocalPath() {
+ return fileLocalPath;
+ }
+
+ public void setFileLocalPath(String fileLocalPath) {
+ this.fileLocalPath = fileLocalPath;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerMount.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerMount.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerMount.java
new file mode 100644
index 0000000..61f07f4
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerMount.java
@@ -0,0 +1,60 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import org.apache.slider.core.exceptions.SliderException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents a docker container mount
+ */
+public class DockerContainerMount implements Validate {
+ protected static final Logger
+ log = LoggerFactory.getLogger(DockerContainerMount.class);
+
+
+ private String containerMount;
+ private String hostMount;
+
+ public DockerContainerMount() {
+ }
+
+ public String getContainerMount() {
+ return containerMount;
+ }
+
+ public void setContainerMount(String containerMount) {
+ this.containerMount = containerMount;
+ }
+
+ public String getHostMount() {
+ return hostMount;
+ }
+
+ public void setHostMount(String hostMount) {
+ this.hostMount = hostMount;
+ }
+
+ @Override
+ public void validate(String version) throws SliderException {
+ Metainfo.checkNonNull(getContainerMount(), "containerMount", "dockerContainerMount");
+ Metainfo.checkNonNull(getHostMount(), "hostMount", "dockerContainerMount");
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerPort.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerPort.java b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerPort.java
new file mode 100644
index 0000000..0629d9d
--- /dev/null
+++ b/slider-core/src/main/java/org/apache/slider/providers/agent/application/metadata/DockerContainerPort.java
@@ -0,0 +1,66 @@
+/*
+ * 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.slider.providers.agent.application.metadata;
+
+import org.apache.slider.core.exceptions.SliderException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents a docker container port
+ */
+public class DockerContainerPort implements Validate {
+ protected static final Logger
+ log = LoggerFactory.getLogger(DockerContainerPort.class);
+
+
+ private String containerPort;
+ private String hostPort;
+
+ public DockerContainerPort() {
+ }
+
+ public String getContainerPort() {
+ return containerPort;
+ }
+
+ public void setContainerPort(String containerPort) {
+ this.containerPort = containerPort;
+ }
+
+ public String getHostPort() {
+ return hostPort;
+ }
+
+ public void setHostPort(String hostPort) {
+ this.hostPort = hostPort;
+ }
+
+ @Override
+ public void validate(String version) throws SliderException {
+ Metainfo.checkNonNull(getContainerPort(), "containerPort", "dockerContainerPort");
+ Metainfo.checkNonNull(getHostPort(), "hostPort", "dockerContainerPort");
+ }
+
+ @Override
+ public String toString() {
+ return "DockerContainerPort [containerPort=" + containerPort
+ + ", hostPort=" + hostPort + "]";
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/5a3a6439/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ExecutionCommand.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ExecutionCommand.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ExecutionCommand.java
index d8a4dbc..e852902 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ExecutionCommand.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/ExecutionCommand.java
@@ -16,13 +16,21 @@
*/
package org.apache.slider.server.appmaster.web.rest.agent;
+import org.apache.slider.providers.agent.application.metadata.Component;
+import org.apache.slider.providers.agent.application.metadata.DockerContainer;
+import org.apache.slider.providers.agent.application.metadata.DockerContainerInputFile;
+import org.apache.slider.providers.agent.application.metadata.DockerContainerMount;
+import org.apache.slider.providers.agent.application.metadata.DockerContainerPort;
+import org.apache.slider.providers.agent.application.metadata.Metainfo;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -49,6 +57,7 @@ public class ExecutionCommand {
private String serviceName;
private String componentName;
private String componentType;
+ private List<DockerContainer> containers = new ArrayList<>();
private String pkg;
public ExecutionCommand(AgentCommandType commandType) {
@@ -214,6 +223,11 @@ public class ExecutionCommand {
this.componentConfigurations = componentConfigurations;
}
+ @JsonProperty("containers")
+ public List<DockerContainer> getContainers() {
+ return containers;
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
@@ -231,4 +245,47 @@ public class ExecutionCommand {
.append(pkg).append("]");
return builder.toString();
}
+
+ public void addContainerDetails(String componentName, Metainfo metaInfo) {
+ Component component = metaInfo.getApplicationComponent(componentName);
+ this.setComponentType(component.getType());
+ log.info("Adding container details for {}", componentName, " from ",
+ metaInfo.toString());
+ for (DockerContainer metaContainer : component.getDockerContainers()) {
+ DockerContainer container = new DockerContainer();
+ container.setImage(metaContainer.getImage());
+ container.setName(metaContainer.getName());
+ container.setOptions(metaContainer.getOptions());
+ container.setAdditionalParam(metaContainer.getAdditionalParam());
+ container.setCommandPath(metaContainer.getAdditionalParam());
+ container.setStatusCommand(metaContainer.getStatusCommand());
+ if (metaContainer.getMounts().size() > 0) {
+ for (DockerContainerMount metaContMount : metaContainer.getMounts()) {
+ DockerContainerMount contMnt = new DockerContainerMount();
+ contMnt.setContainerMount(metaContMount.getContainerMount());
+ contMnt.setHostMount(metaContMount.getHostMount());
+ container.getMounts().add(contMnt);
+ }
+ }
+ if (metaContainer.getPorts().size() > 0) {
+ for (DockerContainerPort metaCntPort : metaContainer.getPorts()) {
+ DockerContainerPort cntPort = new DockerContainerPort();
+ cntPort.setContainerPort(metaCntPort.getContainerPort());
+ cntPort.setHostPort(metaCntPort.getHostPort());
+ container.getPorts().add(cntPort);
+ }
+ }
+ if (metaContainer.getInputFiles().size() > 0) {
+ for (DockerContainerInputFile metaInpFile : metaContainer
+ .getInputFiles()) {
+ DockerContainerInputFile inpFile = new DockerContainerInputFile();
+ inpFile.setContainerMount(metaInpFile.getContainerMount());
+ inpFile.setFileLocalPath(metaInpFile.getFileLocalPath());
+ container.getInputFiles().add(inpFile);
+ }
+ }
+ log.info("Docker container meta info ready: " + container.toString());
+ this.getContainers().add(container);
+ }
+ }
}