You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@slider.apache.org by st...@apache.org on 2014/08/19 14:22:37 UTC
[23/50] [abbrv] git commit: SLIDER-262. Slider agent should provide
process supervision such as auto-restart
SLIDER-262. Slider agent should provide process supervision such as auto-restart
Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/506eb79e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/506eb79e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/506eb79e
Branch: refs/heads/feature/SLIDER-306_Slider_list_command_live_and_history_options
Commit: 506eb79e35ff6187648f4d874c22bb3fe3b18e58
Parents: 004fc8d
Author: Sumit Mohanty <sm...@hortonworks.com>
Authored: Tue Aug 12 18:38:15 2014 -0700
Committer: Sumit Mohanty <sm...@hortonworks.com>
Committed: Thu Aug 14 17:56:52 2014 -0700
----------------------------------------------------------------------
.../src/main/python/agent/ActionQueue.py | 22 +++++++---
slider-agent/src/main/python/agent/Constants.py | 1 +
.../src/main/python/agent/Controller.py | 25 ++++++++++-
.../python/agent/CustomServiceOrchestrator.py | 44 +++++++++++---------
slider-agent/src/main/python/agent/Heartbeat.py | 6 ++-
.../src/test/python/agent/TestActionQueue.py | 5 ++-
.../agent/TestCustomServiceOrchestrator.py | 8 ++--
.../src/test/python/agent/TestHeartbeat.py | 25 +++++++++--
.../slider/common/tools/CoreFileSystem.java | 3 ++
.../providers/agent/AgentProviderService.java | 35 +++++++++++++++-
.../web/rest/agent/HeartBeatResponse.java | 11 +++++
.../agent/TestAgentProviderService.java | 21 ++++++----
12 files changed, 162 insertions(+), 44 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/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 d4d8bc2..774d1e6 100644
--- a/slider-agent/src/main/python/agent/ActionQueue.py
+++ b/slider-agent/src/main/python/agent/ActionQueue.py
@@ -49,6 +49,7 @@ class ActionQueue(threading.Thread):
FAILED_STATUS = 'FAILED'
STORE_APPLIED_CONFIG = 'record_config'
+ AUTO_RESTART = 'auto_restart'
def __init__(self, config, controller):
super(ActionQueue, self).__init__()
@@ -120,6 +121,9 @@ class ActionQueue(threading.Thread):
logger.debug(pprint.pformat(command))
taskId = command['taskId']
+
+ reportResult = not command[Constants.AUTO_GENERATED]
+
# Preparing 'IN_PROGRESS' report
in_progress_status = self.commandStatuses.generate_report_template(command)
in_progress_status.update({
@@ -127,12 +131,17 @@ class ActionQueue(threading.Thread):
'tmperr': self.tmpdir + os.sep + 'errors-' + str(taskId) + '.txt',
'structuredOut': self.tmpdir + os.sep + 'structured-out-' + str(
taskId) + '.json',
- 'status': self.IN_PROGRESS_STATUS
+ 'status': self.IN_PROGRESS_STATUS,
+ 'reportResult': reportResult
})
- self.commandStatuses.put_command_status(command, in_progress_status)
+ self.commandStatuses.put_command_status(command, in_progress_status, reportResult)
store_config = False
if ActionQueue.STORE_APPLIED_CONFIG in command['commandParams']:
store_config = 'true' == command['commandParams'][ActionQueue.STORE_APPLIED_CONFIG]
+ store_command = False
+ if ActionQueue.AUTO_RESTART in command['roleParams']:
+ store_command = 'true' == command['roleParams'][ActionQueue.AUTO_RESTART]
+
# running command
commandresult = self.customServiceOrchestrator.runCommand(command,
@@ -141,7 +150,7 @@ class ActionQueue(threading.Thread):
in_progress_status[
'tmperr'],
True,
- store_config)
+ store_config or store_command)
# dumping results
status = self.COMPLETED_STATUS
if commandresult[Constants.EXIT_CODE] != 0:
@@ -152,6 +161,7 @@ class ActionQueue(threading.Thread):
'stderr': commandresult['stderr'],
Constants.EXIT_CODE: commandresult[Constants.EXIT_CODE],
'status': status,
+ 'reportResult': reportResult
})
if roleResult['stdout'] == '':
roleResult['stdout'] = 'None'
@@ -170,7 +180,7 @@ class ActionQueue(threading.Thread):
roleResult['allocatedPorts'] = commandresult[Constants.ALLOCATED_PORTS]
if Constants.FOLDERS in commandresult:
roleResult['folders'] = commandresult[Constants.FOLDERS]
- self.commandStatuses.put_command_status(command, roleResult)
+ self.commandStatuses.put_command_status(command, roleResult, reportResult)
# Store action result to agent response queue
def result(self):
@@ -185,8 +195,8 @@ class ActionQueue(threading.Thread):
service = command['serviceName']
component = command['componentName']
reportResult = True
- if 'auto_generated' in command:
- reportResult = not command['auto_generated']
+ if Constants.AUTO_GENERATED in command:
+ reportResult = not command[Constants.AUTO_GENERATED]
component_status = self.customServiceOrchestrator.requestComponentStatus(command)
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/slider-agent/src/main/python/agent/Constants.py
----------------------------------------------------------------------
diff --git a/slider-agent/src/main/python/agent/Constants.py b/slider-agent/src/main/python/agent/Constants.py
index a120999..2975266 100644
--- a/slider-agent/src/main/python/agent/Constants.py
+++ b/slider-agent/src/main/python/agent/Constants.py
@@ -32,3 +32,4 @@ DO_NOT_HEARTBEAT = "DO_NOT_HEARTBEAT"
DO_NOT_HEARTBEAT_AFTER_ = "DO_NOT_HEARTBEAT_AFTER_"
ZK_QUORUM="zk_quorum"
ZK_REG_PATH="zk_reg_path"
+AUTO_GENERATED="auto_generated"
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/slider-agent/src/main/python/agent/Controller.py
----------------------------------------------------------------------
diff --git a/slider-agent/src/main/python/agent/Controller.py b/slider-agent/src/main/python/agent/Controller.py
index 1a01bf8..77dcafb 100644
--- a/slider-agent/src/main/python/agent/Controller.py
+++ b/slider-agent/src/main/python/agent/Controller.py
@@ -86,6 +86,7 @@ class Controller(threading.Thread):
self.statusCommand = None
self.failureCount = 0
self.heartBeatRetryCount = 0
+ self.autoRestart = False
def __del__(self):
@@ -224,6 +225,9 @@ class Controller(threading.Thread):
serverId = int(response['responseId'])
+ if 'restartEnabled' in response:
+ restartEnabled = 'true' == response['restartEnabled']
+
if 'hasMappedComponents' in response.keys():
self.hasMappedComponents = response['hasMappedComponents'] != False
@@ -257,6 +261,17 @@ class Controller(threading.Thread):
logger.info("No commands sent from the Server.")
pass
+ # Add a start command
+ if self.componentActualState == State.INSTALLED and \
+ self.componentExpectedState == State.STARTED and restartEnabled:
+ stored_command = self.actionQueue.customServiceOrchestrator.stored_command
+ if len(stored_command) > 0:
+ auto_start_command = self.create_start_command(stored_command)
+ if auto_start_command:
+ self.updateStateBasedOnCommand([auto_start_command])
+ self.addToQueue([auto_start_command])
+ pass
+
# Add a status command
if (self.componentActualState != State.STARTING and \
self.componentExpectedState == State.STARTED) and \
@@ -328,6 +343,14 @@ class Controller(threading.Thread):
pass
logger.info("Controller stopped heart-beating.")
+ def create_start_command(self, stored_command):
+ taskId = int(stored_command['taskId'])
+ taskId = taskId + 1
+ stored_command['taskId'] = taskId
+ stored_command['commandId'] = "{0}-1".format(taskId)
+ stored_command[Constants.AUTO_GENERATED] = True
+ pass
+
def updateStateBasedOnCommand(self, commands):
for command in commands:
if command["roleCommand"] == "START":
@@ -388,7 +411,7 @@ class Controller(threading.Thread):
statusCommand["hostLevelParams"] = command["hostLevelParams"]
statusCommand["serviceName"] = command["serviceName"]
statusCommand["taskId"] = "status"
- statusCommand['auto_generated'] = True
+ statusCommand[Constants.AUTO_GENERATED] = True
logger.info("Status command: " + pprint.pformat(statusCommand))
return statusCommand
pass
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/slider-agent/src/main/python/agent/CustomServiceOrchestrator.py
----------------------------------------------------------------------
diff --git a/slider-agent/src/main/python/agent/CustomServiceOrchestrator.py b/slider-agent/src/main/python/agent/CustomServiceOrchestrator.py
index 0078c9c..6b2ace5 100644
--- a/slider-agent/src/main/python/agent/CustomServiceOrchestrator.py
+++ b/slider-agent/src/main/python/agent/CustomServiceOrchestrator.py
@@ -56,7 +56,7 @@ class CustomServiceOrchestrator():
self.status_commands_stderr = os.path.realpath(posixpath.join(self.tmp_dir,
'status_command_stderr.txt'))
self.public_fqdn = hostname.public_hostname()
- self.applied_configs = {}
+ self.stored_command = {}
# Clean up old status command files if any
try:
os.unlink(self.status_commands_stdout)
@@ -68,7 +68,7 @@ class CustomServiceOrchestrator():
def runCommand(self, command, tmpoutfile, tmperrfile,
- override_output_files=True, store_config=False):
+ override_output_files=True, store_command=False):
allocated_port = {}
try:
script_type = command['commandParams']['script_type']
@@ -86,7 +86,7 @@ class CustomServiceOrchestrator():
# We don't support anything else yet
message = "Unknown script type {0}".format(script_type)
raise AgentException(message)
- json_path = self.dump_command_to_json(command, allocated_port, store_config)
+ json_path = self.dump_command_to_json(command, allocated_port, store_command)
py_file_list = [script_tuple]
# filter None values
filtered_py_file_list = [i for i in py_file_list if i]
@@ -154,22 +154,28 @@ class CustomServiceOrchestrator():
return path
def getConfig(self, 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.applied_configs:
- return {
- 'configurations': {config_type: self.applied_configs[config_type]}
- }
+ 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']:
+ return {
+ 'configurations': {config_type: self.stored_command['configurations'][config_type]}
+ }
+ else:
+ return {
+ 'configurations': {}
+ }
+ pass
else:
+ logger.info("Requesting all applied config.")
return {
- 'configurations': {}
+ 'configurations': self.stored_command['configurations']
}
pass
else:
- logger.info("Requesting all applied config.")
return {
- 'configurations': self.applied_configs
+ 'configurations': {}
}
pass
@@ -184,7 +190,7 @@ class CustomServiceOrchestrator():
override_output_files = False
if command['roleCommand'] == "GET_CONFIG":
- return self.getConfig(command)
+ return self.getConfig(command)
else:
res = self.runCommand(command, self.status_commands_stdout,
@@ -198,7 +204,7 @@ class CustomServiceOrchestrator():
return res
pass
- def dump_command_to_json(self, command, allocated_ports, store_config=False):
+ def dump_command_to_json(self, command, allocated_ports, store_command=False):
"""
Converts command to json file and returns file path
"""
@@ -221,7 +227,7 @@ class CustomServiceOrchestrator():
if os.path.isfile(file_path):
os.unlink(file_path)
- self.finalize_command(command, store_config, allocated_ports)
+ self.finalize_command(command, store_command, allocated_ports)
with os.fdopen(os.open(file_path, os.O_WRONLY | os.O_CREAT,
0600), 'w') as f:
@@ -238,7 +244,7 @@ class CustomServiceOrchestrator():
Either a port gets allocated or if not then just set the value to "0"
"""
- def finalize_command(self, command, store_config, allocated_ports):
+ def finalize_command(self, command, store_command, allocated_ports):
component = command['componentName']
allocated_for_this_component_format = "${{{0}.ALLOCATED_PORT}}"
allocated_for_any = ".ALLOCATED_PORT}"
@@ -267,9 +273,9 @@ class CustomServiceOrchestrator():
pass
pass
- if store_config:
+ if store_command:
logger.info("Storing applied config: " + pprint.pformat(command['configurations']))
- self.applied_configs = command['configurations']
+ self.stored_command = command
pass
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/slider-agent/src/main/python/agent/Heartbeat.py
----------------------------------------------------------------------
diff --git a/slider-agent/src/main/python/agent/Heartbeat.py b/slider-agent/src/main/python/agent/Heartbeat.py
index 4f2207c..aa403d4 100644
--- a/slider-agent/src/main/python/agent/Heartbeat.py
+++ b/slider-agent/src/main/python/agent/Heartbeat.py
@@ -57,7 +57,11 @@ class Heartbeat:
if not self.actionQueue.commandQueue.empty():
commandsInProgress = True
if len(queueResult) != 0:
- heartbeat['reports'] = queueResult['reports']
+ heartbeat['reports'] = []
+ for report in queueResult['reports']:
+ if report['reportResult']:
+ del report['reportResult']
+ heartbeat['reports'].append(report)
if len(heartbeat['reports']) > 0:
# There may be IN_PROGRESS tasks
commandsInProgress = True
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/slider-agent/src/test/python/agent/TestActionQueue.py
----------------------------------------------------------------------
diff --git a/slider-agent/src/test/python/agent/TestActionQueue.py b/slider-agent/src/test/python/agent/TestActionQueue.py
index 21cc5dd..f0935a9 100644
--- a/slider-agent/src/test/python/agent/TestActionQueue.py
+++ b/slider-agent/src/test/python/agent/TestActionQueue.py
@@ -61,6 +61,8 @@ class TestActionQueue(TestCase):
'serviceName': u'HBASE',
'configurations': {'global': {}},
'configurationTags': {'global': {'tag': 'v1'}},
+ 'auto_generated': False,
+ 'roleParams': {'auto_restart':'false'},
'commandParams': {'script_type': 'PYTHON',
'script': 'scripts/abc.py',
'command_timeout': '600'}
@@ -365,7 +367,8 @@ class TestActionQueue(TestCase):
'structuredOut': '',
'exitcode': 0,
'allocatedPorts': {},
- 'folders': {'AGENT_LOG_ROOT': tempdir, 'AGENT_WORK_ROOT': tempdir}}
+ 'folders': {'AGENT_LOG_ROOT': tempdir, 'AGENT_WORK_ROOT': tempdir},
+ 'reportResult': True}
self.assertEqual(len(report['reports']), 1)
self.assertEqual(report['reports'][0], expected)
self.assertTrue(os.path.isfile(configname))
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/slider-agent/src/test/python/agent/TestCustomServiceOrchestrator.py
----------------------------------------------------------------------
diff --git a/slider-agent/src/test/python/agent/TestCustomServiceOrchestrator.py b/slider-agent/src/test/python/agent/TestCustomServiceOrchestrator.py
index 48e4df4..6408809 100644
--- a/slider-agent/src/test/python/agent/TestCustomServiceOrchestrator.py
+++ b/slider-agent/src/test/python/agent/TestCustomServiceOrchestrator.py
@@ -38,6 +38,7 @@ from socket import socket
class TestCustomServiceOrchestrator(TestCase):
+
def setUp(self):
# disable stdout
out = StringIO.StringIO()
@@ -415,9 +416,10 @@ class TestCustomServiceOrchestrator(TestCase):
}
ret = orchestrator.runCommand(command, "out.txt", "err.txt", True, True)
+ self.assertEqual.__self__.maxDiff = None
self.assertEqual(ret['exitcode'], 0)
self.assertTrue(run_file_mock.called)
- self.assertEqual(orchestrator.applied_configs, expected)
+ self.assertEqual(orchestrator.stored_command, command)
ret = orchestrator.requestComponentStatus(command_get)
self.assertEqual(ret['configurations'], expected)
@@ -498,7 +500,7 @@ class TestCustomServiceOrchestrator(TestCase):
self.assertEqual(command['configurations']['oozie-site']['ignore_port2'], "[0,0]")
self.assertEqual(command['configurations']['oozie-site']['ignore_port3'], "[0,0,0]")
self.assertEqual(command['configurations']['oozie-site']['ignore_port4'], "${HBASE_RS}{a}{b}{c}")
- self.assertEqual(orchestrator.applied_configs, {})
+ self.assertEqual(orchestrator.stored_command, {})
self.assertEqual(len(allocated_ports), 1)
self.assertTrue('oozie-site.a_port' in allocated_ports)
self.assertEqual(allocated_ports['oozie-site.a_port'], '10023')
@@ -513,7 +515,7 @@ class TestCustomServiceOrchestrator(TestCase):
self.assertEqual(command['configurations']['hbase-site']['log_root'], tempdir + "/log")
self.assertEqual(command['configurations']['hbase-site']['blog_root'], "/b/" + tempdir + "/log")
self.assertEqual(command['configurations']['oozie-site']['b_port'], "0")
- self.assertEqual(orchestrator.applied_configs, command['configurations'])
+ self.assertEqual(orchestrator.stored_command, command)
def test_port_allocation(self):
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/slider-agent/src/test/python/agent/TestHeartbeat.py
----------------------------------------------------------------------
diff --git a/slider-agent/src/test/python/agent/TestHeartbeat.py b/slider-agent/src/test/python/agent/TestHeartbeat.py
index a9da65d..70870ec 100644
--- a/slider-agent/src/test/python/agent/TestHeartbeat.py
+++ b/slider-agent/src/test/python/agent/TestHeartbeat.py
@@ -86,7 +86,8 @@ class TestHeartbeat(TestCase):
'role': u'DATANODE',
'actionId': '1-1',
'taskId': 3,
- 'exitcode': 777},
+ 'exitcode': 777,
+ 'reportResult' : True},
{'status': 'COMPLETED',
'stderr': 'stderr',
@@ -97,7 +98,8 @@ class TestHeartbeat(TestCase):
'role': 'role',
'actionId': 17,
'taskId': 'taskId',
- 'exitcode': 0},
+ 'exitcode': 0,
+ 'reportResult' : True},
{'status': 'FAILED',
'stderr': 'stderr',
@@ -108,7 +110,8 @@ class TestHeartbeat(TestCase):
'role': u'DATANODE',
'actionId': '1-1',
'taskId': 3,
- 'exitcode': 13},
+ 'exitcode': 13,
+ 'reportResult' : True},
{'status': 'COMPLETED',
'stderr': 'stderr',
@@ -120,8 +123,21 @@ class TestHeartbeat(TestCase):
'role': u'DATANODE',
'actionId': '1-1',
'taskId': 3,
- 'exitcode': 0}
+ 'exitcode': 0,
+ 'reportResult' : True},
+ {'status': 'COMPLETED',
+ 'stderr': 'stderr',
+ 'stdout': 'out',
+ 'clusterName': u'cc',
+ 'configurationTags': {'global': {'tag': 'v1'}},
+ 'roleCommand': u'INSTALL',
+ 'serviceName': u'HDFS',
+ 'role': u'DATANODE',
+ 'actionId': '1-1',
+ 'taskId': 3,
+ 'exitcode': 0,
+ 'reportResult' : False}
],
'componentStatus': [
{'status': 'HEALTHY', 'componentName': 'DATANODE', 'reportResult' : True},
@@ -159,6 +175,7 @@ class TestHeartbeat(TestCase):
'stderr': 'stderr'}], 'componentStatus': [
{'status': 'HEALTHY', 'componentName': 'DATANODE'},
{'status': 'UNHEALTHY', 'componentName': 'NAMENODE'}]}
+ self.assertEqual.__self__.maxDiff = None
self.assertEquals(hb, expected)
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/slider-core/src/main/java/org/apache/slider/common/tools/CoreFileSystem.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/common/tools/CoreFileSystem.java b/slider-core/src/main/java/org/apache/slider/common/tools/CoreFileSystem.java
index a145b8f..def252a 100644
--- a/slider-core/src/main/java/org/apache/slider/common/tools/CoreFileSystem.java
+++ b/slider-core/src/main/java/org/apache/slider/common/tools/CoreFileSystem.java
@@ -50,6 +50,9 @@ import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
import static org.apache.slider.common.SliderXmlConfKeys.CLUSTER_DIRECTORY_PERMISSIONS;
import static org.apache.slider.common.SliderXmlConfKeys.DEFAULT_CLUSTER_DIRECTORY_PERMISSIONS;
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/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 559c4e7..a40926a 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
@@ -495,7 +495,7 @@ public class AgentProviderService extends AbstractProviderService implements
boolean canExecute = commandOrder.canExecute(roleName, command, getComponentStatuses().values());
if (canExecute) {
log.info("Starting {} on {}.", roleName, containerId);
- addStartCommand(roleName, containerId, response, scriptPath);
+ addStartCommand(roleName, containerId, response, scriptPath, isMarkedAutoRestart(roleName));
componentStatus.commandIssued(command);
} else {
log.info("Start of {} on {} delayed as dependencies have not started.", roleName, containerId);
@@ -509,6 +509,13 @@ public class AgentProviderService extends AbstractProviderService implements
addGetConfigCommand(roleName, containerId, response);
}
}
+
+ // if restart is required then signal
+ response.setRestartEnabled(false);
+ if (componentStatus.getState() == State.STARTED
+ && command == Command.NOP && isMarkedAutoRestart(roleName)) {
+ response.setRestartEnabled(true);
+ }
} catch (SliderException e) {
componentStatus.applyCommandResult(CommandResult.FAILED, command);
log.warn("Component instance failed operation.", e);
@@ -936,6 +943,25 @@ public class AgentProviderService extends AbstractProviderService implements
}
/**
+ * Checks if the role is marked auto-restart
+ * @param roleName
+ * @return
+ */
+ protected boolean isMarkedAutoRestart(String roleName) {
+ Application application = getMetainfo().getApplication();
+ if (application == null) {
+ log.error("Malformed app definition: Expect application as the top level element for metainfo.xml");
+ } else {
+ for (Component component : application.getComponents()) {
+ if (component.getName().equals(roleName)) {
+ return component.getRequiresAutoRestart();
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
* Can any master publish config explicitly, if not a random master is used
* @return
*/
@@ -1104,7 +1130,8 @@ public class AgentProviderService extends AbstractProviderService implements
}
@VisibleForTesting
- protected void addStartCommand(String roleName, String containerId, HeartBeatResponse response, String scriptPath)
+ protected void addStartCommand(String roleName, String containerId, HeartBeatResponse response,
+ String scriptPath, Boolean isMarkedAutoRestart)
throws
SliderException {
assert getAmState().isApplicationLive();
@@ -1126,6 +1153,10 @@ public class AgentProviderService extends AbstractProviderService implements
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));
+
cmd.setCommandParams(setCommandParameters(scriptPath, true));
Map<String, Map<String, String>> configurations = buildCommandConfigurations(appConf, containerId);
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/HeartBeatResponse.java
----------------------------------------------------------------------
diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/HeartBeatResponse.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/HeartBeatResponse.java
index ca2db32..0545499 100644
--- a/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/HeartBeatResponse.java
+++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/web/rest/agent/HeartBeatResponse.java
@@ -40,6 +40,7 @@ public class HeartBeatResponse {
RegistrationCommand registrationCommand;
boolean restartAgent = false;
+ boolean restartEnabled = true;
boolean hasMappedComponents = false;
@JsonProperty("responseId")
@@ -92,6 +93,16 @@ public class HeartBeatResponse {
this.restartAgent = restartAgent;
}
+ @JsonProperty("restartEnabled")
+ public boolean getRstartEnabled() {
+ return restartEnabled;
+ }
+
+ @JsonProperty("restartEnabled")
+ public void setRestartEnabled(boolean restartEnabled) {
+ this.restartEnabled = restartEnabled;
+ }
+
@JsonProperty("hasMappedComponents")
public boolean hasMappedComponents() {
return hasMappedComponents;
http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/506eb79e/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
----------------------------------------------------------------------
diff --git a/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java b/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
index a68e770..463799c 100644
--- a/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
+++ b/slider-core/src/test/java/org/apache/slider/providers/agent/TestAgentProviderService.java
@@ -78,6 +78,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import static org.easymock.EasyMock.anyBoolean;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
@@ -642,7 +643,8 @@ public class TestAgentProviderService {
anyString(),
anyString(),
any(HeartBeatResponse.class),
- anyString());
+ anyString(),
+ anyBoolean());
doNothing().when(mockAps).addGetConfigCommand(
anyString(),
anyString(),
@@ -744,7 +746,8 @@ public class TestAgentProviderService {
Mockito.verify(mockAps, Mockito.times(0)).addStartCommand(anyString(),
anyString(),
any(HeartBeatResponse.class),
- anyString());
+ anyString(),
+ anyBoolean());
// RS still does not start
hb = new HeartBeat();
hb.setResponseId(3);
@@ -754,7 +757,8 @@ public class TestAgentProviderService {
Mockito.verify(mockAps, Mockito.times(0)).addStartCommand(anyString(),
anyString(),
any(HeartBeatResponse.class),
- anyString());
+ anyString(),
+ anyBoolean());
// MASTER succeeds install and issues start
hb = new HeartBeat();
@@ -773,7 +777,8 @@ public class TestAgentProviderService {
Mockito.verify(mockAps, Mockito.times(1)).addStartCommand(anyString(),
anyString(),
any(HeartBeatResponse.class),
- anyString());
+ anyString(),
+ anyBoolean());
Map<String, String> allocatedPorts = mockAps.getAllocatedPorts();
Assert.assertTrue(allocatedPorts != null);
Assert.assertTrue(allocatedPorts.size() == 1);
@@ -788,7 +793,8 @@ public class TestAgentProviderService {
Mockito.verify(mockAps, Mockito.times(1)).addStartCommand(anyString(),
anyString(),
any(HeartBeatResponse.class),
- anyString());
+ anyString(),
+ anyBoolean());
// MASTER succeeds start
hb = new HeartBeat();
hb.setResponseId(3);
@@ -812,7 +818,8 @@ public class TestAgentProviderService {
Mockito.verify(mockAps, Mockito.times(2)).addStartCommand(anyString(),
anyString(),
any(HeartBeatResponse.class),
- anyString());
+ anyString(),
+ anyBoolean());
// JDK7
} catch (SliderException he) {
log.warn(he.getMessage());
@@ -959,7 +966,7 @@ public class TestAgentProviderService {
replay(access);
- mockAps.addStartCommand("HBASE_MASTER", "cid1", hbr, "");
+ mockAps.addStartCommand("HBASE_MASTER", "cid1", hbr, "", Boolean.FALSE);
Assert.assertTrue(hbr.getExecutionCommands().get(0).getConfigurations().containsKey("hbase-site"));
Map<String, String> hbaseSiteConf = hbr.getExecutionCommands().get(0).getConfigurations().get("hbase-site");
Assert.assertTrue(hbaseSiteConf.containsKey("a.port"));