in ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java [262:504]
private void addCustomCommandAction(final ActionExecutionContext actionExecutionContext,
final RequestResourceFilter resourceFilter, Stage stage, Map<String, String> additionalCommandParams,
String commandDetail, Map<String, String> requestParams) throws AmbariException {
final String serviceName = resourceFilter.getServiceName();
final String componentName = resourceFilter.getComponentName();
final String commandName = actionExecutionContext.getActionName();
boolean retryAllowed = actionExecutionContext.isRetryAllowed();
boolean autoSkipFailure = actionExecutionContext.isFailureAutoSkipped();
String clusterName = stage.getClusterName();
final Cluster cluster = clusters.getCluster(clusterName);
// start with all hosts
Set<String> candidateHosts = new HashSet<>(resourceFilter.getHostNames());
// Filter hosts that are in MS
Set<String> ignoredHosts = maintenanceStateHelper.filterHostsInMaintenanceState(
candidateHosts, new MaintenanceStateHelper.HostPredicate() {
@Override
public boolean shouldHostBeRemoved(final String hostname)
throws AmbariException {
if (actionExecutionContext.isFutureCommand()) {
return false;
}
return !maintenanceStateHelper.isOperationAllowed(
cluster, actionExecutionContext.getOperationLevel(),
resourceFilter, serviceName, componentName, hostname);
}
}
);
// Filter unhealthy hosts
Set<String> unhealthyHosts = getUnhealthyHosts(candidateHosts, actionExecutionContext, resourceFilter);
// log excluded hosts
if (!ignoredHosts.isEmpty()) {
if( LOG.isDebugEnabled() ){
LOG.debug(
"While building the {} custom command for {}/{}, the following hosts were excluded: unhealthy[{}], maintenance[{}]",
commandName, serviceName, componentName, StringUtils.join(unhealthyHosts, ','),
StringUtils.join(ignoredHosts, ','));
}
} else if (!unhealthyHosts.isEmpty()) {
if (LOG.isDebugEnabled()) {
LOG.debug(
"While building the {} custom command for {}/{}, the following hosts were excluded: unhealthy[{}], maintenance[{}]",
commandName, serviceName, componentName, StringUtils.join(unhealthyHosts, ','),
StringUtils.join(ignoredHosts, ','));
}
} else if (candidateHosts.isEmpty()) {
String message = MessageFormat.format(
"While building the {0} custom command for {1}/{2}, there were no healthy eligible hosts",
commandName, serviceName, componentName);
throw new AmbariException(message);
}
Service service = cluster.getService(serviceName);
// grab the stack ID from the service first, and use the context's if it's set
StackId stackId = service.getDesiredStackId();
if (null != actionExecutionContext.getStackId()) {
stackId = actionExecutionContext.getStackId();
}
AmbariMetaInfo ambariMetaInfo = managementController.getAmbariMetaInfo();
ServiceInfo serviceInfo = ambariMetaInfo.getService(service);
CustomCommandDefinition customCommandDefinition = null;
ComponentInfo ci = serviceInfo.getComponentByName(componentName);
if(ci != null){
customCommandDefinition = ci.getCustomCommandByName(commandName);
}
long nowTimestamp = System.currentTimeMillis();
for (String hostName : candidateHosts) {
stage.addHostRoleExecutionCommand(hostName, Role.valueOf(componentName),
RoleCommand.CUSTOM_COMMAND,
new ServiceComponentHostOpInProgressEvent(componentName, hostName, nowTimestamp),
cluster.getClusterName(), serviceName, retryAllowed, autoSkipFailure);
ExecutionCommand execCmd = stage.getExecutionCommandWrapper(hostName,
componentName).getExecutionCommand();
// if the command should fetch brand new configuration tags before
// execution, then we don't need to fetch them now
if(actionExecutionContext.getParameters() != null && actionExecutionContext.getParameters().containsKey(KeyNames.OVERRIDE_CONFIGS)){
execCmd.setOverrideConfigs(true);
}
HostRoleCommand cmd = stage.getHostRoleCommand(hostName, componentName);
if (cmd != null) {
cmd.setCommandDetail(commandDetail);
cmd.setCustomCommandName(commandName);
if (customCommandDefinition != null){
cmd.setOpsDisplayName(customCommandDefinition.getOpsDisplayName());
}
}
//set type background
if(customCommandDefinition != null && customCommandDefinition.isBackground()){
cmd.setBackgroundCommand(true);
execCmd.setCommandType(AgentCommandType.BACKGROUND_EXECUTION_COMMAND);
}
execCmd.setComponentVersions(cluster);
execCmd.setConfigurations(new TreeMap<>());
// Get the value of credential store enabled from the DB
Service clusterService = cluster.getService(serviceName);
execCmd.setCredentialStoreEnabled(String.valueOf(clusterService.isCredentialStoreEnabled()));
// Get the map of service config type to password properties for the service
Map<String, Map<String, String>> configCredentials;
configCredentials = configCredentialsForService.get(clusterService.getName());
if (configCredentials == null) {
configCredentials = configHelper.getCredentialStoreEnabledProperties(stackId, clusterService);
configCredentialsForService.put(clusterService.getName(), configCredentials);
}
execCmd.setConfigurationCredentials(configCredentials);
Map<String, String> hostLevelParams = new TreeMap<>();
hostLevelParams.put(STACK_NAME, stackId.getStackName());
hostLevelParams.put(STACK_VERSION, stackId.getStackVersion());
Map<String, DesiredConfig> desiredConfigs = cluster.getDesiredConfigs();
Set<String> userSet = configHelper.getPropertyValuesWithPropertyType(stackId, PropertyType.USER, cluster, desiredConfigs);
String userList = gson.toJson(userSet);
hostLevelParams.put(USER_LIST, userList);
//Create a user_group mapping and send it as part of the hostLevelParams
Map<String, Set<String>> userGroupsMap = configHelper.createUserGroupsMap(
stackId, cluster, desiredConfigs);
String userGroups = gson.toJson(userGroupsMap);
hostLevelParams.put(USER_GROUPS, userGroups);
Set<String> groupSet = configHelper.getPropertyValuesWithPropertyType(stackId, PropertyType.GROUP, cluster, desiredConfigs);
String groupList = gson.toJson(groupSet);
hostLevelParams.put(GROUP_LIST, groupList);
Map<PropertyInfo, String> notManagedHdfsPathMap = configHelper.getPropertiesWithPropertyType(stackId, PropertyType.NOT_MANAGED_HDFS_PATH, cluster, desiredConfigs);
Set<String> notManagedHdfsPathSet = configHelper.filterInvalidPropertyValues(notManagedHdfsPathMap, NOT_MANAGED_HDFS_PATH_LIST);
String notManagedHdfsPathList = gson.toJson(notManagedHdfsPathSet);
hostLevelParams.put(NOT_MANAGED_HDFS_PATH_LIST, notManagedHdfsPathList);
execCmd.setHostLevelParams(hostLevelParams);
Map<String, String> commandParams = new TreeMap<>();
if (additionalCommandParams != null) {
for (String key : additionalCommandParams.keySet()) {
commandParams.put(key, additionalCommandParams.get(key));
}
}
commandParams.put(CUSTOM_COMMAND, commandName);
boolean isInstallCommand = commandName.equals(RoleCommand.INSTALL.toString());
int commandTimeout = Integer.valueOf(configs.getDefaultAgentTaskTimeout(isInstallCommand));
ComponentInfo componentInfo = ambariMetaInfo.getComponent(
stackId.getStackName(), stackId.getStackVersion(),
serviceName, componentName);
if (serviceInfo.getSchemaVersion().equals(AmbariMetaInfo.SCHEMA_VERSION_2)) {
// Service check command is not custom command
CommandScriptDefinition script = componentInfo.getCommandScript();
if (script != null) {
commandParams.put(SCRIPT, script.getScript());
commandParams.put(SCRIPT_TYPE, script.getScriptType().toString());
if (script.getTimeout() > 0) {
commandTimeout = script.getTimeout();
}
} else {
String message = String.format("Component %s has not command script " +
"defined. It is not possible to send command for " +
"this service", componentName);
throw new AmbariException(message);
}
// We don't need package/repo information to perform service check
}
// !!! the action execution context timeout is the final say, but make sure it's at least 60 seconds
if (null != actionExecutionContext.getTimeout()) {
commandTimeout = actionExecutionContext.getTimeout().intValue();
commandTimeout = Math.max(60, commandTimeout);
}
if (requestParams != null && requestParams.containsKey(RequestResourceProvider.CONTEXT)) {
String requestContext = requestParams.get(RequestResourceProvider.CONTEXT);
if (StringUtils.isNotEmpty(requestContext) && requestContext.toLowerCase().contains("rolling-restart")) {
Config clusterEnvConfig = cluster.getDesiredConfigByType("cluster-env");
if (clusterEnvConfig != null) {
String componentRollingRestartTimeout = clusterEnvConfig.getProperties().get("namenode_rolling_restart_timeout");
if (StringUtils.isNotEmpty(componentRollingRestartTimeout)) {
commandTimeout = Integer.parseInt(componentRollingRestartTimeout);
}
}
}
}
commandParams.put(COMMAND_TIMEOUT, "" + commandTimeout);
Map<String, String> roleParams = execCmd.getRoleParams();
if (roleParams == null) {
roleParams = new TreeMap<>();
}
// if there is a stack upgrade which is currently suspended then pass that
// information down with the command as some components may need to know
boolean isUpgradeSuspended = cluster.isUpgradeSuspended();
if (isUpgradeSuspended) {
cluster.addSuspendedUpgradeParameters(commandParams, roleParams);
}
StageUtils.useAmbariJdkInCommandParams(commandParams, configs);
roleParams.put(COMPONENT_CATEGORY, componentInfo.getCategory());
// set reconfigureAction in case of a RECONFIGURE command if there are any
if (commandName.equals("RECONFIGURE")) {
String refreshConfigsCommand = configHelper.getRefreshConfigsCommand(cluster, hostName, serviceName, componentName);
if (refreshConfigsCommand != null && !refreshConfigsCommand.equals(RefreshCommandConfiguration.REFRESH_CONFIGS)) {
LOG.info("Refreshing configs for {}/{} with command: ", componentName, hostName, refreshConfigsCommand);
commandParams.put("reconfigureAction", refreshConfigsCommand);
//execCmd.setForceRefreshConfigTagsBeforeExecution(true);
}
}
execCmd.setCommandParams(commandParams);
execCmd.setRoleParams(roleParams);
// skip anything else
if (actionExecutionContext.isFutureCommand()) {
continue;
}
// perform any server side command related logic - eg - set desired states on restart
applyCustomCommandBackendLogic(cluster, serviceName, componentName, commandName, hostName);
}
}