blob: 8c8ae1000a63c849880bb71c95bc46fc3c80f1ad [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.ambari.server.controller;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AGENT_STACK_RETRY_COUNT;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.AGENT_STACK_RETRY_ON_UNAVAILABILITY;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.CLIENTS_TO_UPDATE_CONFIGS;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMMAND_TIMEOUT;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.COMPONENT_CATEGORY;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.CUSTOM_COMMAND;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_DRIVER_FILENAME;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_NAME;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.GROUP_LIST;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOOKS_FOLDER;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOST_SYS_PREPPED;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JAVA_HOME;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JAVA_VERSION;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JCE_NAME;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_LOCATION;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JDK_NAME;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.MYSQL_JDBC_URL;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.NOT_MANAGED_HDFS_PATH_LIST;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.ORACLE_JDBC_URL;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.REPO_INFO;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SCRIPT_TYPE;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.SERVICE_PACKAGE_FOLDER;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAME;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.USER_LIST;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.Role;
import org.apache.ambari.server.RoleCommand;
import org.apache.ambari.server.actionmanager.HostRoleCommand;
import org.apache.ambari.server.actionmanager.Stage;
import org.apache.ambari.server.agent.AgentCommand.AgentCommandType;
import org.apache.ambari.server.agent.ExecutionCommand;
import org.apache.ambari.server.agent.ExecutionCommand.KeyNames;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.internal.RequestOperationLevel;
import org.apache.ambari.server.controller.internal.RequestResourceFilter;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.metadata.ActionMetadata;
import org.apache.ambari.server.orm.dao.ClusterVersionDAO;
import org.apache.ambari.server.orm.entities.ClusterVersionEntity;
import org.apache.ambari.server.orm.entities.OperatingSystemEntity;
import org.apache.ambari.server.orm.entities.RepositoryEntity;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.CommandScriptDefinition;
import org.apache.ambari.server.state.ComponentInfo;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.CustomCommandDefinition;
import org.apache.ambari.server.state.DesiredConfig;
import org.apache.ambari.server.state.Host;
import org.apache.ambari.server.state.HostComponentAdminState;
import org.apache.ambari.server.state.HostState;
import org.apache.ambari.server.state.MaintenanceState;
import org.apache.ambari.server.state.PropertyInfo.PropertyType;
import org.apache.ambari.server.state.RepositoryInfo;
import org.apache.ambari.server.state.RepositoryVersionState;
import org.apache.ambari.server.state.Service;
import org.apache.ambari.server.state.ServiceComponent;
import org.apache.ambari.server.state.ServiceComponentHost;
import org.apache.ambari.server.state.ServiceInfo;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.State;
import org.apache.ambari.server.state.stack.OsFamily;
import org.apache.ambari.server.state.svccomphost.ServiceComponentHostOpInProgressEvent;
import org.apache.ambari.server.utils.StageUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
* Helper class containing logic to process custom command execution requests .
* This class has special support needed for SERVICE_CHECK and DECOMMISSION.
* These commands are not pass through as Ambari has specific persistence requirements.
*/
@Singleton
public class AmbariCustomCommandExecutionHelper {
private final static Logger LOG = LoggerFactory.getLogger(
AmbariCustomCommandExecutionHelper.class);
// TODO: Remove the hard-coded mapping when stack definition indicates which slave types can be decommissioned
public static final Map<String, String> masterToSlaveMappingForDecom = new HashMap<String, String>();
static {
masterToSlaveMappingForDecom.put("NAMENODE", "DATANODE");
masterToSlaveMappingForDecom.put("RESOURCEMANAGER", "NODEMANAGER");
masterToSlaveMappingForDecom.put("HBASE_MASTER", "HBASE_REGIONSERVER");
masterToSlaveMappingForDecom.put("JOBTRACKER", "TASKTRACKER");
}
public final static String DECOM_INCLUDED_HOSTS = "included_hosts";
public final static String DECOM_EXCLUDED_HOSTS = "excluded_hosts";
public final static String DECOM_SLAVE_COMPONENT = "slave_type";
public final static String HBASE_MARK_DRAINING_ONLY = "mark_draining_only";
public final static String UPDATE_EXCLUDE_FILE_ONLY = "update_exclude_file_only";
private final static String ALIGN_MAINTENANCE_STATE = "align_maintenance_state";
@Inject
private ActionMetadata actionMetadata;
@Inject
private Clusters clusters;
@Inject
private AmbariManagementController managementController;
@Inject
private Gson gson;
@Inject
private Configuration configs;
@Inject
private AmbariMetaInfo ambariMetaInfo;
@Inject
private ConfigHelper configHelper;
@Inject
private MaintenanceStateHelper maintenanceStateHelper;
@Inject
private OsFamily os_family;
@Inject
private ClusterVersionDAO clusterVersionDAO;
protected static final String SERVICE_CHECK_COMMAND_NAME = "SERVICE_CHECK";
protected static final String START_COMMAND_NAME = "START";
protected static final String RESTART_COMMAND_NAME = "RESTART";
protected static final String INSTALL_COMMAND_NAME = "INSTALL";
public static final String DECOMMISSION_COMMAND_NAME = "DECOMMISSION";
private Boolean isServiceCheckCommand(String command, String service) {
List<String> actions = actionMetadata.getActions(service);
return !(actions == null || actions.size() == 0) && actions.contains(command);
}
private Boolean isValidCustomCommand(String clusterName,
String serviceName, String componentName, String commandName)
throws AmbariException {
Cluster cluster = clusters.getCluster(clusterName);
StackId stackId = cluster.getDesiredStackVersion();
if (componentName == null) {
return false;
}
ComponentInfo componentInfo = ambariMetaInfo.getComponent(
stackId.getStackName(), stackId.getStackVersion(),
serviceName, componentName);
return !(!componentInfo.isCustomCommand(commandName) &&
!actionMetadata.isDefaultHostComponentCommand(commandName));
}
private Boolean isValidCustomCommand(ActionExecutionContext
actionExecutionContext, RequestResourceFilter resourceFilter)
throws AmbariException {
String clusterName = actionExecutionContext.getClusterName();
String serviceName = resourceFilter.getServiceName();
String componentName = resourceFilter.getComponentName();
String commandName = actionExecutionContext.getActionName();
if (componentName == null) {
return false;
}
return isValidCustomCommand(clusterName, serviceName, componentName, commandName);
}
private Boolean isValidCustomCommand(ExecuteActionRequest actionRequest,
RequestResourceFilter resourceFilter) throws AmbariException {
String clusterName = actionRequest.getClusterName();
String serviceName = resourceFilter.getServiceName();
String componentName = resourceFilter.getComponentName();
String commandName = actionRequest.getCommandName();
if (componentName == null) {
return false;
}
return isValidCustomCommand(clusterName, serviceName, componentName, commandName);
}
private String getReadableCustomCommandDetail(ActionExecutionContext
actionRequest, RequestResourceFilter resourceFilter) {
StringBuilder sb = new StringBuilder();
sb.append(actionRequest.getActionName());
if (resourceFilter.getServiceName() != null
&& !resourceFilter.getServiceName().equals("")) {
sb.append(" ");
sb.append(resourceFilter.getServiceName());
}
if (resourceFilter.getComponentName() != null
&& !resourceFilter.getComponentName().equals("")) {
sb.append("/");
sb.append(resourceFilter.getComponentName());
}
return sb.toString();
}
/**
* Called during the start/stop/restart of services, plus custom commands during Stack Upgrade.
* @param actionExecutionContext Execution Context
* @param resourceFilter Resource Filter
* @param stage Command stage
* @param additionalCommandParams Additional command params to add the the stage
* @param commandDetail String for the command detail
* @throws AmbariException
*/
private void addCustomCommandAction(final ActionExecutionContext actionExecutionContext,
final RequestResourceFilter resourceFilter, Stage stage,
Map<String, String> additionalCommandParams, String commandDetail) 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<String>(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 {
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);
}
StackId stackId = cluster.getDesiredStackVersion();
AmbariMetaInfo ambariMetaInfo = managementController.getAmbariMetaInfo();
ServiceInfo serviceInfo = ambariMetaInfo.getService(
stackId.getStackName(), stackId.getStackVersion(), serviceName);
StackInfo stackInfo = ambariMetaInfo.getStack
(stackId.getStackName(), stackId.getStackVersion());
CustomCommandDefinition customCommandDefinition = null;
ComponentInfo ci = serviceInfo.getComponentByName(componentName);
if(ci != null){
customCommandDefinition = ci.getCustomCommandByName(commandName);
}
long nowTimestamp = System.currentTimeMillis();
for (String hostName : candidateHosts) {
Host host = clusters.getHost(hostName);
stage.addHostRoleExecutionCommand(hostName, Role.valueOf(componentName),
RoleCommand.CUSTOM_COMMAND,
new ServiceComponentHostOpInProgressEvent(componentName, hostName, nowTimestamp),
cluster.getClusterName(), serviceName, retryAllowed, autoSkipFailure);
Map<String, Map<String, String>> configurations =
new TreeMap<String, Map<String, String>>();
Map<String, Map<String, Map<String, String>>> configurationAttributes =
new TreeMap<String, Map<String, Map<String, String>>>();
Map<String, Map<String, String>> configTags = new TreeMap<String, Map<String, String>>();
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.REFRESH_CONFIG_TAGS_BEFORE_EXECUTION)){
execCmd.setForceRefreshConfigTagsBeforeExecution(true);
}
// when building complex orchestration ahead of time (such as when
// performing ugprades), fetching configuration tags can take a very long
// time - if it's not needed, then don't do it
if (!execCmd.getForceRefreshConfigTagsBeforeExecution()) {
configTags = managementController.findConfigurationTagsWithOverrides(cluster, hostName);
}
HostRoleCommand cmd = stage.getHostRoleCommand(hostName, componentName);
if (cmd != null) {
cmd.setCommandDetail(commandDetail);
cmd.setCustomCommandName(commandName);
}
//set type background
if(customCommandDefinition != null && customCommandDefinition.isBackground()){
execCmd.setCommandType(AgentCommandType.BACKGROUND_EXECUTION_COMMAND);
}
execCmd.setConfigurations(configurations);
execCmd.setConfigurationAttributes(configurationAttributes);
execCmd.setConfigurationTags(configTags);
execCmd.setAvailableServicesFromServiceInfoMap(ambariMetaInfo.getServices(stackId.getStackName(), stackId.getStackVersion()));
Map<String, String> hostLevelParams = new TreeMap<String, String>();
hostLevelParams.put(CUSTOM_COMMAND, commandName);
// Set parameters required for re-installing clients on restart
hostLevelParams.put(REPO_INFO, getRepoInfo(cluster, host));
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);
Set<String> groupSet = configHelper.getPropertyValuesWithPropertyType(stackId, PropertyType.GROUP, cluster, desiredConfigs);
String groupList = gson.toJson(groupSet);
hostLevelParams.put(GROUP_LIST, groupList);
Set<String> notManagedHdfsPathSet = configHelper.getPropertyValuesWithPropertyType(stackId, PropertyType.NOT_MANAGED_HDFS_PATH, cluster, desiredConfigs);
String notManagedHdfsPathList = gson.toJson(notManagedHdfsPathSet);
hostLevelParams.put(NOT_MANAGED_HDFS_PATH_LIST, notManagedHdfsPathList);
execCmd.setHostLevelParams(hostLevelParams);
Map<String, String> commandParams = new TreeMap<String, String>();
if (additionalCommandParams != null) {
for (String key : additionalCommandParams.keySet()) {
commandParams.put(key, additionalCommandParams.get(key));
}
}
boolean isInstallCommand = commandName.equals(RoleCommand.INSTALL.toString());
String commandTimeout = 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 = String.valueOf(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
}
commandParams.put(COMMAND_TIMEOUT, commandTimeout);
commandParams.put(SERVICE_PACKAGE_FOLDER, serviceInfo.getServicePackageFolder());
commandParams.put(HOOKS_FOLDER, stackInfo.getStackHooksFolder());
ClusterVersionEntity effectiveClusterVersion = cluster.getEffectiveClusterVersion();
if (effectiveClusterVersion != null) {
commandParams.put(KeyNames.VERSION, effectiveClusterVersion.getRepositoryVersion().getVersion());
}
execCmd.setCommandParams(commandParams);
Map<String, String> roleParams = execCmd.getRoleParams();
if (roleParams == null) {
roleParams = new TreeMap<String, String>();
}
// 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
if (cluster.isUpgradeSuspended()) {
roleParams.put(KeyNames.UPGRADE_SUSPENDED, Boolean.TRUE.toString().toLowerCase());
}
roleParams.put(COMPONENT_CATEGORY, componentInfo.getCategory());
execCmd.setRoleParams(roleParams);
// perform any server side command related logic - eg - set desired states on restart
applyCustomCommandBackendLogic(cluster, serviceName, componentName, commandName, hostName);
}
}
private void applyCustomCommandBackendLogic(Cluster cluster, String serviceName, String componentName, String commandName, String hostname) throws AmbariException {
switch (commandName) {
case "RESTART":
ServiceComponentHost serviceComponentHost = cluster.getService(
serviceName).getServiceComponent(componentName).getServiceComponentHost(hostname);
State currentDesiredState = serviceComponentHost.getDesiredState();
if (currentDesiredState != State.STARTED) {
LOG.info("Updating desired state to {} on RESTART for {}/{} because it was {}",
State.STARTED, serviceName, componentName, currentDesiredState);
serviceComponentHost.setDesiredState(State.STARTED);
}
break;
default:
LOG.debug("No backend operations needed for the custom command: {}", commandName);
break;
}
}
private void findHostAndAddServiceCheckAction(final ActionExecutionContext actionExecutionContext,
final RequestResourceFilter resourceFilter, Stage stage) throws AmbariException {
String clusterName = actionExecutionContext.getClusterName();
final Cluster cluster = clusters.getCluster(clusterName);
final String componentName = actionMetadata.getClient(resourceFilter.getServiceName());
final String serviceName = resourceFilter.getServiceName();
String smokeTestRole = actionMetadata.getServiceCheckAction(serviceName);
if (null == smokeTestRole) {
smokeTestRole = actionExecutionContext.getActionName();
}
long nowTimestamp = System.currentTimeMillis();
Map<String, String> actionParameters = actionExecutionContext.getParameters();
final Set<String> candidateHosts;
final Map<String, ServiceComponentHost> serviceHostComponents;
if (componentName != null) {
serviceHostComponents = cluster.getService(serviceName).getServiceComponent(
componentName).getServiceComponentHosts();
if (serviceHostComponents.isEmpty()) {
throw new AmbariException("Hosts not found, component="
+ componentName + ", service = " + serviceName
+ ", cluster = " + clusterName);
}
List<String> candidateHostsList = resourceFilter.getHostNames();
if (candidateHostsList != null && !candidateHostsList.isEmpty()) {
candidateHosts = new HashSet<String>(candidateHostsList);
} else {
candidateHosts = serviceHostComponents.keySet();
}
} else {
// TODO: this code branch looks unreliable(taking random component)
Map<String, ServiceComponent> serviceComponents =
cluster.getService(serviceName).getServiceComponents();
// Filter components without any HOST
Iterator<String> serviceComponentNameIterator = serviceComponents.keySet().iterator();
while (serviceComponentNameIterator.hasNext()){
String componentToCheck = serviceComponentNameIterator.next();
if (serviceComponents.get(componentToCheck).getServiceComponentHosts().isEmpty()){
serviceComponentNameIterator.remove();
}
}
if (serviceComponents.isEmpty()) {
throw new AmbariException("Components not found, service = "
+ serviceName + ", cluster = " + clusterName);
}
ServiceComponent serviceComponent = serviceComponents.values().iterator().next();
serviceHostComponents = serviceComponent.getServiceComponentHosts();
candidateHosts = serviceHostComponents.keySet();
}
// filter out hosts that are in maintenance mode - they should never be
// included in service checks
Set<String> hostsInMaintenanceMode = new HashSet<String>();
if (actionExecutionContext.isMaintenanceModeHostExcluded()) {
Iterator<String> iterator = candidateHosts.iterator();
while (iterator.hasNext()) {
String candidateHostName = iterator.next();
ServiceComponentHost serviceComponentHost = serviceHostComponents.get(candidateHostName);
Host host = serviceComponentHost.getHost();
if (host.getMaintenanceState(cluster.getClusterId()) == MaintenanceState.ON) {
hostsInMaintenanceMode.add(candidateHostName);
iterator.remove();
}
}
}
// pick a random healthy host from the remaining set, throwing an exception
// if there are none to choose from
String hostName = managementController.getHealthyHost(candidateHosts);
if (hostName == null) {
String message = MessageFormat.format(
"While building a service check command for {0}, there were no healthy eligible hosts: unhealthy[{1}], maintenance[{2}]",
serviceName, StringUtils.join(candidateHosts, ','),
StringUtils.join(hostsInMaintenanceMode, ','));
throw new AmbariException(message);
}
addServiceCheckAction(stage, hostName, smokeTestRole, nowTimestamp, serviceName, componentName,
actionParameters, actionExecutionContext.isRetryAllowed(),
actionExecutionContext.isFailureAutoSkipped());
}
/**
* Creates and populates service check EXECUTION_COMMAND for host. Not all
* EXECUTION_COMMAND parameters are populated here because they are not needed
* by service check.
*/
public void addServiceCheckAction(Stage stage, String hostname, String smokeTestRole,
long nowTimestamp, String serviceName, String componentName,
Map<String, String> actionParameters, boolean retryAllowed, boolean autoSkipFailure)
throws AmbariException {
String clusterName = stage.getClusterName();
Cluster cluster = clusters.getCluster(clusterName);
StackId stackId = cluster.getDesiredStackVersion();
AmbariMetaInfo ambariMetaInfo = managementController.getAmbariMetaInfo();
ServiceInfo serviceInfo = ambariMetaInfo.getService(stackId.getStackName(),
stackId.getStackVersion(), serviceName);
StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(),
stackId.getStackVersion());
stage.addHostRoleExecutionCommand(hostname, Role.valueOf(smokeTestRole),
RoleCommand.SERVICE_CHECK,
new ServiceComponentHostOpInProgressEvent(componentName, hostname, nowTimestamp),
cluster.getClusterName(), serviceName, retryAllowed, autoSkipFailure);
HostRoleCommand hrc = stage.getHostRoleCommand(hostname, smokeTestRole);
if (hrc != null) {
hrc.setCommandDetail(String.format("%s %s", RoleCommand.SERVICE_CHECK.toString(), serviceName));
}
// [ type -> [ key, value ] ]
Map<String, Map<String, String>> configurations =
new TreeMap<String, Map<String, String>>();
Map<String, Map<String, Map<String, String>>> configurationAttributes =
new TreeMap<String, Map<String, Map<String, String>>>();
Map<String, Map<String, String>> configTags = new TreeMap<String, Map<String, String>>();
ExecutionCommand execCmd = stage.getExecutionCommandWrapper(hostname,
smokeTestRole).getExecutionCommand();
// if the command should fetch brand new configuration tags before
// execution, then we don't need to fetch them now
if(actionParameters != null && actionParameters.containsKey(KeyNames.REFRESH_CONFIG_TAGS_BEFORE_EXECUTION)){
execCmd.setForceRefreshConfigTagsBeforeExecution(true);
}
// when building complex orchestration ahead of time (such as when
// performing ugprades), fetching configuration tags can take a very long
// time - if it's not needed, then don't do it
if (!execCmd.getForceRefreshConfigTagsBeforeExecution()) {
configTags = managementController.findConfigurationTagsWithOverrides(cluster, hostname);
}
execCmd.setConfigurations(configurations);
execCmd.setConfigurationAttributes(configurationAttributes);
execCmd.setConfigurationTags(configTags);
// Generate cluster host info
execCmd.setClusterHostInfo(
StageUtils.getClusterHostInfo(cluster));
// Generate localComponents
for (ServiceComponentHost sch : cluster.getServiceComponentHosts(hostname)) {
execCmd.getLocalComponents().add(sch.getServiceComponentName());
}
Map<String, String> commandParams = new TreeMap<String, String>();
//Propagate HCFS service type info
Map<String, ServiceInfo> serviceInfos = ambariMetaInfo.getServices(stackId.getStackName(), stackId.getStackVersion());
for (ServiceInfo serviceInfoInstance : serviceInfos.values()) {
if (serviceInfoInstance.getServiceType() != null) {
LOG.debug("Adding {} to command parameters for {}", serviceInfoInstance.getServiceType(),
serviceInfoInstance.getName());
commandParams.put("dfs_type", serviceInfoInstance.getServiceType());
break;
}
}
String commandTimeout = configs.getDefaultAgentTaskTimeout(false);
if (serviceInfo.getSchemaVersion().equals(AmbariMetaInfo.SCHEMA_VERSION_2)) {
// Service check command is not custom command
CommandScriptDefinition script = serviceInfo.getCommandScript();
if (script != null) {
commandParams.put(SCRIPT, script.getScript());
commandParams.put(SCRIPT_TYPE, script.getScriptType().toString());
if (script.getTimeout() > 0) {
commandTimeout = String.valueOf(script.getTimeout());
}
} else {
String message = String.format("Service %s has no command script " +
"defined. It is not possible to run service check" +
" for this service", serviceName);
throw new AmbariException(message);
}
// We don't need package/repo information to perform service check
}
commandParams.put(COMMAND_TIMEOUT, commandTimeout);
commandParams.put(SERVICE_PACKAGE_FOLDER, serviceInfo.getServicePackageFolder());
commandParams.put(HOOKS_FOLDER, stackInfo.getStackHooksFolder());
execCmd.setCommandParams(commandParams);
if (actionParameters != null) { // If defined
execCmd.setRoleParams(actionParameters);
}
}
private Set<String> getHostList(Map<String, String> cmdParameters, String key) {
Set<String> hosts = new HashSet<String>();
if (cmdParameters.containsKey(key)) {
String allHosts = cmdParameters.get(key);
if (allHosts != null) {
for (String hostName : allHosts.trim().split(",")) {
hosts.add(hostName.trim());
}
}
}
return hosts;
}
/**
* Processes decommission command. Modifies the host components as needed and then
* calls into the implementation of a custom command
*/
private void addDecommissionAction(final ActionExecutionContext actionExecutionContext,
final RequestResourceFilter resourceFilter, Stage stage) throws AmbariException {
String clusterName = actionExecutionContext.getClusterName();
final Cluster cluster = clusters.getCluster(clusterName);
final String serviceName = resourceFilter.getServiceName();
String masterCompType = resourceFilter.getComponentName();
List<String> hosts = resourceFilter.getHostNames();
if (hosts != null && !hosts.isEmpty()) {
throw new AmbariException("Decommission command cannot be issued with " +
"target host(s) specified.");
}
//Get all hosts to be added and removed
Set<String> excludedHosts = getHostList(actionExecutionContext.getParameters(),
DECOM_EXCLUDED_HOSTS);
Set<String> includedHosts = getHostList(actionExecutionContext.getParameters(),
DECOM_INCLUDED_HOSTS);
Set<String> cloneSet = new HashSet<String>(excludedHosts);
cloneSet.retainAll(includedHosts);
if (cloneSet.size() > 0) {
throw new AmbariException("Same host cannot be specified for inclusion " +
"as well as exclusion. Hosts: " + cloneSet.toString());
}
Service service = cluster.getService(serviceName);
if (service == null) {
throw new AmbariException("Specified service " + serviceName +
" is not a valid/deployed service.");
}
Map<String, ServiceComponent> svcComponents = service.getServiceComponents();
if (!svcComponents.containsKey(masterCompType)) {
throw new AmbariException("Specified component " + masterCompType +
" does not belong to service " + serviceName + ".");
}
ServiceComponent masterComponent = svcComponents.get(masterCompType);
if (!masterComponent.isMasterComponent()) {
throw new AmbariException("Specified component " + masterCompType +
" is not a MASTER for service " + serviceName + ".");
}
if (!masterToSlaveMappingForDecom.containsKey(masterCompType)) {
throw new AmbariException("Decommissioning is not supported for " + masterCompType);
}
// Find the slave component
String slaveCompStr = actionExecutionContext.getParameters().get(DECOM_SLAVE_COMPONENT);
final String slaveCompType;
if (slaveCompStr == null || slaveCompStr.equals("")) {
slaveCompType = masterToSlaveMappingForDecom.get(masterCompType);
} else {
slaveCompType = slaveCompStr;
if (!masterToSlaveMappingForDecom.get(masterCompType).equals(slaveCompType)) {
throw new AmbariException("Component " + slaveCompType + " is not supported for decommissioning.");
}
}
String isDrainOnlyRequest = actionExecutionContext.getParameters().get(HBASE_MARK_DRAINING_ONLY);
if (isDrainOnlyRequest != null && !slaveCompType.equals(Role.HBASE_REGIONSERVER.name())) {
throw new AmbariException(HBASE_MARK_DRAINING_ONLY + " is not a valid parameter for " + masterCompType);
}
// Filtering hosts based on Maintenance State
MaintenanceStateHelper.HostPredicate hostPredicate
= new MaintenanceStateHelper.HostPredicate() {
@Override
public boolean shouldHostBeRemoved(final String hostname)
throws AmbariException {
//Get UPDATE_EXCLUDE_FILE_ONLY parameter as string
String upd_excl_file_only_str = actionExecutionContext.getParameters()
.get(UPDATE_EXCLUDE_FILE_ONLY);
String decom_incl_hosts_str = actionExecutionContext.getParameters()
.get(DECOM_INCLUDED_HOSTS);
if ((upd_excl_file_only_str != null &&
!upd_excl_file_only_str.trim().equals(""))){
upd_excl_file_only_str = upd_excl_file_only_str.trim();
}
boolean upd_excl_file_only = false;
//Parse of possible forms of value
if (upd_excl_file_only_str != null &&
!upd_excl_file_only_str.equals("") &&
(upd_excl_file_only_str.equals("\"true\"")
|| upd_excl_file_only_str.equals("'true'")
|| upd_excl_file_only_str.equals("true"))){
upd_excl_file_only = true;
}
// If we just clear *.exclude and component have been already removed we will skip check
if (upd_excl_file_only && decom_incl_hosts_str != null
&& !decom_incl_hosts_str.trim().equals("")) {
return upd_excl_file_only;
} else {
return !maintenanceStateHelper.isOperationAllowed(
cluster, actionExecutionContext.getOperationLevel(),
resourceFilter, serviceName, slaveCompType, hostname);
}
}
};
// Filter excluded hosts
Set<String> filteredExcludedHosts = new HashSet<String>(excludedHosts);
Set<String> ignoredHosts = maintenanceStateHelper.filterHostsInMaintenanceState(
filteredExcludedHosts, hostPredicate);
if (! ignoredHosts.isEmpty()) {
String message = String.format("Some hosts (%s) from host exclude list " +
"have been ignored " +
"because components on them are in Maintenance state.",
ignoredHosts);
LOG.debug(message);
}
// Filter included hosts
Set<String> filteredIncludedHosts = new HashSet<String>(includedHosts);
ignoredHosts = maintenanceStateHelper.filterHostsInMaintenanceState(
filteredIncludedHosts, hostPredicate);
if (! ignoredHosts.isEmpty()) {
String message = String.format("Some hosts (%s) from host include list " +
"have been ignored " +
"because components on them are in Maintenance state.",
ignoredHosts);
LOG.debug(message);
}
// Decommission only if the sch is in state STARTED or INSTALLED
for (ServiceComponentHost sch : svcComponents.get(slaveCompType).getServiceComponentHosts().values()) {
if (filteredExcludedHosts.contains(sch.getHostName())
&& !"true".equals(isDrainOnlyRequest)
&& sch.getState() != State.STARTED) {
throw new AmbariException("Component " + slaveCompType + " on host " + sch.getHostName() + " cannot be " +
"decommissioned as its not in STARTED state. Aborting the whole request.");
}
}
String alignMtnStateStr = actionExecutionContext.getParameters().get(ALIGN_MAINTENANCE_STATE);
boolean alignMtnState = "true".equals(alignMtnStateStr);
// Set/reset decommissioned flag on all components
List<String> listOfExcludedHosts = new ArrayList<String>();
for (ServiceComponentHost sch : svcComponents.get(slaveCompType).getServiceComponentHosts().values()) {
if (filteredExcludedHosts.contains(sch.getHostName())) {
sch.setComponentAdminState(HostComponentAdminState.DECOMMISSIONED);
listOfExcludedHosts.add(sch.getHostName());
if (alignMtnState) {
sch.setMaintenanceState(MaintenanceState.ON);
}
LOG.info("Decommissioning " + slaveCompType + " and marking Maintenance=ON on " + sch.getHostName());
}
if (filteredIncludedHosts.contains(sch.getHostName())) {
sch.setComponentAdminState(HostComponentAdminState.INSERVICE);
if (alignMtnState) {
sch.setMaintenanceState(MaintenanceState.OFF);
}
LOG.info("Recommissioning " + slaveCompType + " and marking Maintenance=OFF on " + sch.getHostName());
}
}
// In the event there are more than one master host the following logic is applied
// -- HDFS/DN, MR1/TT, YARN/NM call refresh node on both
// -- HBASE/RS call only on one host
// Ensure host is active
Map<String, ServiceComponentHost> masterSchs = masterComponent.getServiceComponentHosts();
String primaryCandidate = null;
for (String hostName : masterSchs.keySet()) {
if (primaryCandidate == null) {
primaryCandidate = hostName;
} else {
ServiceComponentHost sch = masterSchs.get(hostName);
if (sch.getState() == State.STARTED) {
primaryCandidate = hostName;
}
}
}
StringBuilder commandDetail = getReadableDecommissionCommandDetail
(actionExecutionContext, filteredIncludedHosts, listOfExcludedHosts);
for (String hostName : masterSchs.keySet()) {
RequestResourceFilter commandFilter = new RequestResourceFilter(serviceName,
masterComponent.getName(), Collections.singletonList(hostName));
List<RequestResourceFilter> resourceFilters = new ArrayList<RequestResourceFilter>();
resourceFilters.add(commandFilter);
ActionExecutionContext commandContext = new ActionExecutionContext(
clusterName, actionExecutionContext.getActionName(), resourceFilters
);
String clusterHostInfoJson = StageUtils.getGson().toJson(
StageUtils.getClusterHostInfo(cluster));
// Reset cluster host info as it has changed
stage.setClusterHostInfo(clusterHostInfoJson);
Map<String, String> commandParams = new HashMap<String, String>();
if (serviceName.equals(Service.Type.HBASE.name())) {
commandParams.put(DECOM_EXCLUDED_HOSTS, StringUtils.join(listOfExcludedHosts, ','));
if ((isDrainOnlyRequest != null) && isDrainOnlyRequest.equals("true")) {
commandParams.put(HBASE_MARK_DRAINING_ONLY, isDrainOnlyRequest);
} else {
commandParams.put(HBASE_MARK_DRAINING_ONLY, "false");
}
}
if (!serviceName.equals(Service.Type.HBASE.name()) || hostName.equals(primaryCandidate)) {
commandParams.put(UPDATE_EXCLUDE_FILE_ONLY, "false");
addCustomCommandAction(commandContext, commandFilter, stage, commandParams, commandDetail.toString());
}
}
}
private StringBuilder getReadableDecommissionCommandDetail(
ActionExecutionContext actionExecutionContext, Set<String> includedHosts,
List<String> listOfExcludedHosts) {
StringBuilder commandDetail = new StringBuilder();
commandDetail.append(actionExecutionContext.getActionName());
if (listOfExcludedHosts.size() > 0) {
commandDetail.append(", Excluded: ").append(StringUtils.join(listOfExcludedHosts, ','));
}
if (includedHosts.size() > 0) {
commandDetail.append(", Included: ").append(StringUtils.join(includedHosts, ','));
}
return commandDetail;
}
/**
* Validate custom command and throw exception is invalid request.
*
* @param actionRequest the action request
*
* @throws AmbariException if the action can not be validated
*/
public void validateAction(ExecuteActionRequest actionRequest) throws AmbariException {
List<RequestResourceFilter> resourceFilters = actionRequest.getResourceFilters();
if (resourceFilters == null || resourceFilters.isEmpty()) {
throw new AmbariException("Command execution cannot proceed without a " +
"resource filter.");
}
for (RequestResourceFilter resourceFilter : resourceFilters) {
if (resourceFilter.getServiceName() == null
|| resourceFilter.getServiceName().isEmpty()
|| actionRequest.getCommandName() == null
|| actionRequest.getCommandName().isEmpty()) {
throw new AmbariException("Invalid resource filter : " + "cluster = "
+ actionRequest.getClusterName() + ", service = "
+ resourceFilter.getServiceName() + ", command = "
+ actionRequest.getCommandName());
}
if (!isServiceCheckCommand(actionRequest.getCommandName(), resourceFilter.getServiceName())
&& !isValidCustomCommand(actionRequest, resourceFilter)) {
throw new AmbariException(
"Unsupported action " + actionRequest.getCommandName() +
" for Service: " + resourceFilter.getServiceName()
+ " and Component: " + resourceFilter.getComponentName());
}
}
}
/**
* Other than Service_Check and Decommission all other commands are pass-through
*
* @param actionExecutionContext received request to execute a command
* @param stage the initial stage for task creation
* @param requestParams the request params
*
* @throws AmbariException if the commands can not be added
*/
public void addExecutionCommandsToStage(ActionExecutionContext actionExecutionContext,
Stage stage, Map<String, String> requestParams) throws AmbariException {
List<RequestResourceFilter> resourceFilters = actionExecutionContext.getResourceFilters();
for (RequestResourceFilter resourceFilter : resourceFilters) {
LOG.debug("Received a command execution request"
+ ", clusterName=" + actionExecutionContext.getClusterName()
+ ", serviceName=" + resourceFilter.getServiceName()
+ ", request=" + actionExecutionContext.toString());
String actionName = actionExecutionContext.getActionName();
if (actionName.contains(SERVICE_CHECK_COMMAND_NAME)) {
findHostAndAddServiceCheckAction(actionExecutionContext, resourceFilter, stage);
} else if (actionName.equals(DECOMMISSION_COMMAND_NAME)) {
addDecommissionAction(actionExecutionContext, resourceFilter, stage);
} else if (isValidCustomCommand(actionExecutionContext, resourceFilter)) {
String commandDetail = getReadableCustomCommandDetail(actionExecutionContext, resourceFilter);
Map<String, String> extraParams = new HashMap<String, String>();
String componentName = (null == resourceFilter.getComponentName()) ? null :
resourceFilter.getComponentName().toLowerCase();
if (null != componentName && requestParams.containsKey(componentName)) {
extraParams.put(componentName, requestParams.get(componentName));
}
// If command should be retried upon failure then add the option and also the default duration for retry
if (requestParams.containsKey(KeyNames.COMMAND_RETRY_ENABLED)) {
extraParams.put(KeyNames.COMMAND_RETRY_ENABLED, requestParams.get(KeyNames.COMMAND_RETRY_ENABLED));
String commandRetryDuration = ConfigHelper.COMMAND_RETRY_MAX_TIME_IN_SEC_DEFAULT;
if (requestParams.containsKey(KeyNames.MAX_DURATION_OF_RETRIES)) {
String commandRetryDurationStr = requestParams.get(KeyNames.MAX_DURATION_OF_RETRIES);
Integer commandRetryDurationInt = NumberUtils.toInt(commandRetryDurationStr, 0);
if (commandRetryDurationInt > 0) {
commandRetryDuration = Integer.toString(commandRetryDurationInt);
}
}
extraParams.put(KeyNames.MAX_DURATION_OF_RETRIES, commandRetryDuration);
}
// If command needs to explicitly disable STDOUT/STDERR logging
if (requestParams.containsKey(KeyNames.LOG_OUTPUT)) {
extraParams.put(KeyNames.LOG_OUTPUT, requestParams.get(KeyNames.LOG_OUTPUT));
}
if(requestParams.containsKey(KeyNames.REFRESH_CONFIG_TAGS_BEFORE_EXECUTION)){
actionExecutionContext.getParameters().put(KeyNames.REFRESH_CONFIG_TAGS_BEFORE_EXECUTION, requestParams.get(KeyNames.REFRESH_CONFIG_TAGS_BEFORE_EXECUTION));
}
RequestOperationLevel operationLevel = actionExecutionContext.getOperationLevel();
if (operationLevel != null) {
String clusterName = operationLevel.getClusterName();
String serviceName = operationLevel.getServiceName();
if (isTopologyRefreshRequired(actionName, clusterName, serviceName)) {
extraParams.put(KeyNames.REFRESH_TOPOLOGY, "True");
}
}
addCustomCommandAction(actionExecutionContext, resourceFilter, stage, extraParams, commandDetail);
} else {
throw new AmbariException("Unsupported action " + actionName);
}
}
}
/**
* Get repository info given a cluster and host.
*
* @param cluster the cluster
* @param host the host
*
* @return the repo info
*
* @throws AmbariException if the repository information can not be obtained
*/
public String getRepoInfo(Cluster cluster, Host host) throws AmbariException {
StackId stackId = cluster.getDesiredStackVersion();
Map<String, List<RepositoryInfo>> repos = ambariMetaInfo.getRepository(
stackId.getStackName(), stackId.getStackVersion());
String family = os_family.find(host.getOsType());
if (null == family) {
family = host.getOsFamily();
}
JsonElement gsonList = null;
// !!! check for the most specific first
if (repos.containsKey(host.getOsType())) {
gsonList = gson.toJsonTree(repos.get(host.getOsType()));
} else if (null != family && repos.containsKey(family)) {
gsonList = gson.toJsonTree(repos.get(family));
} else {
LOG.warn("Could not retrieve repo information for host"
+ ", hostname=" + host.getHostName()
+ ", clusterName=" + cluster.getClusterName()
+ ", stackInfo=" + stackId.getStackId());
}
if (null != gsonList) {
gsonList = updateBaseUrls(cluster, JsonArray.class.cast(gsonList));
return gsonList.toString();
} else {
return "";
}
}
/**
* Checks repo URLs against the current version for the cluster and makes
* adjustments to the Base URL when the current is different.
* @param cluster the cluster to load the current version
* @param jsonArray the array containing stack repo data
*/
private JsonArray updateBaseUrls(Cluster cluster, JsonArray jsonArray) throws AmbariException {
ClusterVersionEntity cve = cluster.getCurrentClusterVersion();
if (null == cve) {
List<ClusterVersionEntity> list = clusterVersionDAO.findByClusterAndState(cluster.getClusterName(),
RepositoryVersionState.INIT);
if (!list.isEmpty()) {
if (list.size() > 1) {
throw new AmbariException(String.format("The cluster can only be initialized by one version: %s found",
list.size()));
} else {
cve = list.get(0);
}
}
}
if (null == cve || null == cve.getRepositoryVersion()) {
LOG.info("Cluster {} has no specific Repository Versions. Using stack-defined values", cluster.getClusterName());
return jsonArray;
}
RepositoryVersionEntity rve = cve.getRepositoryVersion();
JsonArray result = new JsonArray();
for (JsonElement e : jsonArray) {
JsonObject obj = e.getAsJsonObject();
String repoId = obj.has("repoId") ? obj.get("repoId").getAsString() : null;
String repoName = obj.has("repoName") ? obj.get("repoName").getAsString() : null;
String baseUrl = obj.has("baseUrl") ? obj.get("baseUrl").getAsString() : null;
String osType = obj.has("osType") ? obj.get("osType").getAsString() : null;
if (null == repoId || null == baseUrl || null == osType || null == repoName) {
continue;
}
for (OperatingSystemEntity ose : rve.getOperatingSystems()) {
if (ose.getOsType().equals(osType) && ose.isAmbariManagedRepos()) {
for (RepositoryEntity re : ose.getRepositories()) {
if (re.getName().equals(repoName) &&
re.getRepositoryId().equals(repoId) &&
!re.getBaseUrl().equals(baseUrl)) {
obj.addProperty("baseUrl", re.getBaseUrl());
}
}
result.add(e);
}
}
}
return result;
}
/**
* Helper method to fill execution command information.
*
* @param actionExecContext the context
* @param cluster the cluster for the command
* @param stackId the effective stack id to use.
*
* @return a wrapper of the imporant JSON structures to add to a stage
*/
public ExecuteCommandJson getCommandJson(ActionExecutionContext actionExecContext,
Cluster cluster, StackId stackId) throws AmbariException {
Map<String, String> commandParamsStage = StageUtils.getCommandParamsStage(actionExecContext);
Map<String, String> hostParamsStage = new HashMap<String, String>();
Map<String, Set<String>> clusterHostInfo;
String clusterHostInfoJson = "{}";
if (null != cluster) {
clusterHostInfo = StageUtils.getClusterHostInfo(
cluster);
// Important, because this runs during Stack Uprade, it needs to use the effective Stack Id.
hostParamsStage = createDefaultHostParams(cluster, stackId);
String componentName = null;
String serviceName = null;
if (actionExecContext.getOperationLevel() != null) {
componentName = actionExecContext.getOperationLevel().getHostComponentName();
serviceName = actionExecContext.getOperationLevel().getServiceName();
}
if (serviceName != null && componentName != null) {
ComponentInfo componentInfo = ambariMetaInfo.getComponent(
stackId.getStackName(), stackId.getStackVersion(),
serviceName, componentName);
List<String> clientsToUpdateConfigsList = componentInfo.getClientsToUpdateConfigs();
if (clientsToUpdateConfigsList == null) {
clientsToUpdateConfigsList = new ArrayList<String>();
clientsToUpdateConfigsList.add("*");
}
String clientsToUpdateConfigs = gson.toJson(clientsToUpdateConfigsList);
hostParamsStage.put(CLIENTS_TO_UPDATE_CONFIGS, clientsToUpdateConfigs);
}
clusterHostInfoJson = StageUtils.getGson().toJson(clusterHostInfo);
//Propogate HCFS service type info to command params
Map<String, ServiceInfo> serviceInfos = ambariMetaInfo.getServices(stackId.getStackName(), stackId.getStackVersion());
for (ServiceInfo serviceInfoInstance : serviceInfos.values()) {
if (serviceInfoInstance.getServiceType() != null) {
LOG.debug("Adding {} to command parameters for {}", serviceInfoInstance.getServiceType(),
serviceInfoInstance.getName());
commandParamsStage.put("dfs_type", serviceInfoInstance.getServiceType());
break;
}
}
}
String hostParamsStageJson = StageUtils.getGson().toJson(hostParamsStage);
String commandParamsStageJson = StageUtils.getGson().toJson(commandParamsStage);
return new ExecuteCommandJson(clusterHostInfoJson, commandParamsStageJson,
hostParamsStageJson);
}
Map<String, String> createDefaultHostParams(Cluster cluster) throws AmbariException {
StackId stackId = cluster.getDesiredStackVersion();
return createDefaultHostParams(cluster, stackId);
}
Map<String, String> createDefaultHostParams(Cluster cluster, StackId stackId) throws AmbariException{
TreeMap<String, String> hostLevelParams = new TreeMap<String, String>();
hostLevelParams.put(JDK_LOCATION, managementController.getJdkResourceUrl());
hostLevelParams.put(JAVA_HOME, managementController.getJavaHome());
hostLevelParams.put(JAVA_VERSION, String.valueOf(configs.getJavaVersion()));
hostLevelParams.put(JDK_NAME, managementController.getJDKName());
hostLevelParams.put(JCE_NAME, managementController.getJCEName());
hostLevelParams.put(STACK_NAME, stackId.getStackName());
hostLevelParams.put(STACK_VERSION, stackId.getStackVersion());
hostLevelParams.put(DB_NAME, managementController.getServerDB());
hostLevelParams.put(MYSQL_JDBC_URL, managementController.getMysqljdbcUrl());
hostLevelParams.put(ORACLE_JDBC_URL, managementController.getOjdbcUrl());
hostLevelParams.put(DB_DRIVER_FILENAME, configs.getMySQLJarName());
hostLevelParams.putAll(managementController.getRcaParameters());
hostLevelParams.put(HOST_SYS_PREPPED, configs.areHostsSysPrepped());
hostLevelParams.put(AGENT_STACK_RETRY_ON_UNAVAILABILITY, configs.isAgentStackRetryOnInstallEnabled());
hostLevelParams.put(AGENT_STACK_RETRY_COUNT, configs.getAgentStackRetryOnInstallCount());
Map<String, DesiredConfig> desiredConfigs = cluster.getDesiredConfigs();
Set<String> notManagedHdfsPathSet = configHelper.getPropertyValuesWithPropertyType(stackId, PropertyType.NOT_MANAGED_HDFS_PATH, cluster, desiredConfigs);
String notManagedHdfsPathList = gson.toJson(notManagedHdfsPathSet);
hostLevelParams.put(NOT_MANAGED_HDFS_PATH_LIST, notManagedHdfsPathList);
ClusterVersionEntity clusterVersionEntity = clusterVersionDAO.findByClusterAndStateCurrent(cluster.getClusterName());
if (clusterVersionEntity == null) {
List<ClusterVersionEntity> clusterVersionEntityList = clusterVersionDAO
.findByClusterAndState(cluster.getClusterName(), RepositoryVersionState.INSTALLING);
if (!clusterVersionEntityList.isEmpty()) {
clusterVersionEntity = clusterVersionEntityList.iterator().next();
}
}
for (Map.Entry<String, String> dbConnectorName : configs.getDatabaseConnectorNames().entrySet()) {
hostLevelParams.put(dbConnectorName.getKey(), dbConnectorName.getValue());
}
for (Map.Entry<String, String> previousDBConnectorName : configs.getPreviousDatabaseConnectorNames().entrySet()) {
hostLevelParams.put(previousDBConnectorName.getKey(), previousDBConnectorName.getValue());
}
if (clusterVersionEntity != null) {
hostLevelParams.put("current_version", clusterVersionEntity.getRepositoryVersion().getVersion());
}
return hostLevelParams;
}
/**
* Determine whether or not the action should trigger a topology refresh.
*
* @param actionName the action name (i.e. START, RESTART)
* @param clusterName the cluster name
* @param serviceName the service name
*
* @return true if a topology refresh is required for the action
*/
public boolean isTopologyRefreshRequired(String actionName, String clusterName, String serviceName)
throws AmbariException {
if (actionName.equals(START_COMMAND_NAME) || actionName.equals(RESTART_COMMAND_NAME)) {
Cluster cluster = clusters.getCluster(clusterName);
StackId stackId = cluster.getDesiredStackVersion();
AmbariMetaInfo ambariMetaInfo = managementController.getAmbariMetaInfo();
StackInfo stack = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
if (stack != null) {
ServiceInfo serviceInfo = stack.getService(serviceName);
if (serviceInfo != null) {
// if there is a chance that this action was triggered by a change in rack info then we want to
// force a topology refresh
// TODO : we may be able to be smarter about this and only refresh when the rack info has definitely changed
Boolean restartRequiredAfterRackChange = serviceInfo.isRestartRequiredAfterRackChange();
if (restartRequiredAfterRackChange != null && restartRequiredAfterRackChange) {
return true;
}
}
}
}
return false;
}
private ServiceComponent getServiceComponent ( ActionExecutionContext actionExecutionContext,
RequestResourceFilter resourceFilter){
try {
Cluster cluster = clusters.getCluster(actionExecutionContext.getClusterName());
Service service = cluster.getService(resourceFilter.getServiceName());
return service.getServiceComponent(resourceFilter.getComponentName());
} catch (Exception e) {
LOG.debug(String.format( "Unknown error appears during getting service component: %s", e.getMessage()));
}
return null;
}
/**
* Filter host according to status of host/host components
* @param hostname Host name to check
* @param actionExecutionContext Received request to execute a command
* @param resourceFilter Resource filter
* @return True if host need to be filtered, False if Not
* @throws AmbariException
*/
private boolean filterUnhealthHostItem(String hostname,
ActionExecutionContext actionExecutionContext,
RequestResourceFilter resourceFilter) throws AmbariException {
RequestOperationLevel operationLevel = actionExecutionContext.getOperationLevel();
ServiceComponent serviceComponent = getServiceComponent(actionExecutionContext, resourceFilter);
if (serviceComponent != null && operationLevel != null
&& operationLevel.getLevel() == Resource.Type.Service // compare operation is allowed only for Service operation level
&& actionExecutionContext.getResourceFilters().size() > 1 // Check if operation was started in a chain
&& !serviceComponent.isMasterComponent()
){
return !(clusters.getHost(hostname).getState() == HostState.HEALTHY);
} else if (serviceComponent != null && operationLevel != null
&& operationLevel.getLevel() == Resource.Type.Host // compare operation is allowed only for host component operation level
&& actionExecutionContext.getResourceFilters().size() > 1 // Check if operation was started in a chain
&& serviceComponent.getServiceComponentHosts().containsKey(hostname) // Check if host is assigned to host component
&& !serviceComponent.isMasterComponent()
){
State hostState = serviceComponent.getServiceComponentHosts().get(hostname).getState();
return hostState == State.UNKNOWN;
}
return false;
}
/**
* Filter hosts according to status of host/host components
* @param hosts Host name set to filter
* @param actionExecutionContext Received request to execute a command
* @param resourceFilter Resource filter
* @return Set of excluded hosts
* @throws AmbariException
*/
private Set<String> getUnhealthyHosts(Set<String> hosts,
ActionExecutionContext actionExecutionContext,
RequestResourceFilter resourceFilter) throws AmbariException {
Set<String> removedHosts = new HashSet<String>();
for (String hostname : hosts) {
if (filterUnhealthHostItem(hostname, actionExecutionContext, resourceFilter)){
removedHosts.add(hostname);
}
}
hosts.removeAll(removedHosts);
return removedHosts;
}
}