private void addDecommissionAction()

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);
      }
    }
  }