in ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariCustomCommandExecutionHelper.java [788:1014]
private void addDecommissionAction(final ActionExecutionContext actionExecutionContext,
final RequestResourceFilter resourceFilter, Stage stage, ExecuteCommandJson executeCommandJson)
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);
if (actionExecutionContext.getParameters().get(IS_ADD_OR_DELETE_SLAVE_REQUEST) != null &&
actionExecutionContext.getParameters().get(IS_ADD_OR_DELETE_SLAVE_REQUEST).equalsIgnoreCase("true")) {
includedHosts = getHostList(actionExecutionContext.getParameters(), masterCompType + "_" + DECOM_INCLUDED_HOSTS);
}
Set<String> cloneSet = new HashSet<>(excludedHosts);
cloneSet.retainAll(includedHosts);
if (cloneSet.size() > 0) {
throw new AmbariException("Same host cannot be specified for inclusion " +
"as well as exclusion. Hosts: " + cloneSet);
}
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_FILES_ONLY parameter as string
String upd_excl_file_only_str = actionExecutionContext.getParameters()
.get(UPDATE_FILES_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<>(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<>(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<>();
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("marking Maintenance=ON on " + sch.getHostName());
}
LOG.info("Decommissioning " + slaveCompType + " on " + sch.getHostName());
}
if (filteredIncludedHosts.contains(sch.getHostName())) {
sch.setComponentAdminState(HostComponentAdminState.INSERVICE);
if (alignMtnState) {
sch.setMaintenanceState(MaintenanceState.OFF);
LOG.info("marking Maintenance=OFF on " + sch.getHostName());
}
LOG.info("Recommissioning " + slaveCompType + " 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<>();
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
if (executeCommandJson != null) {
executeCommandJson.setClusterHostInfo(clusterHostInfoJson);
}
Map<String, String> commandParams = new HashMap<>();
commandParams.put(ALL_DECOMMISSIONED_HOSTS,
StringUtils.join(calculateDecommissionedNodes(service, slaveCompType), ','));
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_FILES_ONLY, "false");
addCustomCommandAction(commandContext, commandFilter, stage, commandParams, commandDetail.toString(), null);
}
}
}