/** * 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.internal; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ambari.server.Role; import org.apache.ambari.server.actionmanager.HostRoleCommand; import org.apache.ambari.server.actionmanager.HostRoleStatus; import org.apache.ambari.server.actionmanager.Request; import org.apache.ambari.server.actionmanager.Stage; import org.apache.ambari.server.events.listeners.tasks.TaskStatusListener; import org.apache.ambari.server.orm.dao.HostRoleCommandStatusSummaryDTO; import org.apache.ambari.server.orm.entities.HostRoleCommandEntity; import org.apache.ambari.server.orm.entities.StageEntity; import org.apache.ambari.server.orm.entities.StageEntityPK; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; /** * Status of a request resource, calculated from a set of tasks or stages. */ public class CalculatedStatus { /** * The calculated overall status. */ private final HostRoleStatus status; /** * The display status. */ private final HostRoleStatus displayStatus; /** * The calculated percent complete. */ private final double percent; /** * A status which represents a COMPLETED state at 0% */ public static final CalculatedStatus COMPLETED = new CalculatedStatus(HostRoleStatus.COMPLETED, HostRoleStatus.COMPLETED, 100.0); /** * A status which represents a PENDING state at 0% */ public static final CalculatedStatus PENDING = new CalculatedStatus(HostRoleStatus.PENDING, HostRoleStatus.PENDING, 0.0); // ----- Constructors ------------------------------------------------------ /** * Constructor. * * @param status the calculated overall status * @param percent the calculated percent complete */ private CalculatedStatus(HostRoleStatus status, double percent) { this(status, null, percent); } /** * Overloaded constructor that allows to set the display status if required. * * @param status the calculated overall status * @param displayStatus the calculated display status * @param percent the calculated percent complete */ private CalculatedStatus(HostRoleStatus status, HostRoleStatus displayStatus, double percent) { this.status = status; this.displayStatus = displayStatus; this.percent = percent; } // ----- CalculatedStatus -------------------------------------------------- /** * Get the calculated status. * * @return the status */ public HostRoleStatus getStatus() { return status; } /** * Get the calculated display status. The display_status field is used as * a hint for UI. It's effective only on UpgradeGroup level. * We should expose it for the following states: * SKIPPED_FAILED * FAILED * * @return the display status */ public HostRoleStatus getDisplayStatus() { return displayStatus; } /** * Get the calculated percent complete. * * @return the percent complete */ public double getPercent() { return percent; } // ----- helper methods ---------------------------------------------------- /** * Factory method to create a calculated status. Calculate request status from the given * collection of task entities. * * @param tasks the collection of task entities * @param skippable true if a single failed status should NOT result in an overall failed status * * @return a calculated status */ public static CalculatedStatus statusFromTaskEntities(Collection<HostRoleCommandEntity> tasks, boolean skippable) { int size = tasks.size(); Map<HostRoleStatus, Integer> taskStatusCounts = CalculatedStatus.calculateTaskEntityStatusCounts(tasks); HostRoleStatus status = calculateSummaryStatus(taskStatusCounts, size, skippable); double progressPercent = calculateProgressPercent(taskStatusCounts, size); return new CalculatedStatus(status, progressPercent); } /** * Factory method to create a calculated status. Calculate request status from the given * collection of stage entities. * * @param stages the collection of stage entities * * @return a calculated status */ public static CalculatedStatus statusFromStageEntities(Collection<StageEntity> stages) { Collection<HostRoleStatus> stageStatuses = new HashSet<>(); Collection<HostRoleCommandEntity> tasks = new HashSet<>(); for (StageEntity stage : stages) { // get all the tasks for the stage Collection<HostRoleCommandEntity> stageTasks = stage.getHostRoleCommands(); // calculate the stage status from the task status counts HostRoleStatus stageStatus = calculateSummaryStatus(calculateTaskEntityStatusCounts(stageTasks), stageTasks.size(), stage.isSkippable()); stageStatuses.add(stageStatus); // keep track of all of the tasks for all stages tasks.addAll(stageTasks); } // calculate the overall status from the stage statuses HostRoleStatus status = calculateSummaryStatusOfUpgrade(calculateStatusCounts(stageStatuses), stageStatuses.size()); // calculate the progress from the task status counts double progressPercent = calculateProgressPercent(calculateTaskEntityStatusCounts(tasks), tasks.size()); return new CalculatedStatus(status, progressPercent); } /** * Factory method to create a calculated status. Calculate request status from the given * collection of stages. * * @param stages the collection of stages * * @return a calculated status */ public static CalculatedStatus statusFromStages(Collection<Stage> stages) { Collection<HostRoleStatus> stageStatuses = new HashSet<>(); Collection<HostRoleCommand> tasks = new HashSet<>(); for (Stage stage : stages) { // get all the tasks for the stage Collection<HostRoleCommand> stageTasks = stage.getOrderedHostRoleCommands(); // calculate the stage status from the task status counts HostRoleStatus stageStatus = calculateSummaryStatus(calculateTaskStatusCounts(stageTasks), stageTasks.size(), stage.isSkippable()); stageStatuses.add(stageStatus); // keep track of all of the tasks for all stages tasks.addAll(stageTasks); } // calculate the overall status from the stage statuses HostRoleStatus status = calculateSummaryStatusOfUpgrade(calculateStatusCounts(stageStatuses), stageStatuses.size()); // calculate the progress from the task status counts double progressPercent = calculateProgressPercent(calculateTaskStatusCounts(tasks), tasks.size()); return new CalculatedStatus(status, progressPercent); } /** * Returns counts of tasks that are in various states. * * @param hostRoleStatuses the collection of tasks * * @return a map of counts of tasks keyed by the task status */ public static Map<HostRoleStatus, Integer> calculateStatusCounts(Collection<HostRoleStatus> hostRoleStatuses) { Map<HostRoleStatus, Integer> counters = new HashMap<>(); // initialize for (HostRoleStatus hostRoleStatus : HostRoleStatus.values()) { counters.put(hostRoleStatus, 0); } // calculate counts for (HostRoleStatus status : hostRoleStatuses) { // count tasks where isCompletedState() == true as COMPLETED // but don't count tasks with COMPLETED status twice if (status.isCompletedState() && status != HostRoleStatus.COMPLETED) { // Increase total number of completed tasks; counters.put(HostRoleStatus.COMPLETED, counters.get(HostRoleStatus.COMPLETED) + 1); } // Increment counter for particular status counters.put(status, counters.get(status) + 1); } // We overwrite the value to have the sum converged counters.put(HostRoleStatus.IN_PROGRESS, hostRoleStatuses.size() - counters.get(HostRoleStatus.COMPLETED) - counters.get(HostRoleStatus.QUEUED) - counters.get(HostRoleStatus.PENDING)); return counters; } /** * Returns counts of tasks that are in various states. * * @param hostRoleCommands collection of beans {@link HostRoleCommand} * * @return a map of counts of tasks keyed by the task status */ public static Map<HostRoleStatus, Integer> calculateStatusCountsForTasks(Collection<HostRoleCommand> hostRoleCommands) { Map<HostRoleStatus, Integer> counters = new HashMap<>(); // initialize for (HostRoleStatus hostRoleStatus : HostRoleStatus.values()) { counters.put(hostRoleStatus, 0); } // calculate counts for (HostRoleCommand hrc : hostRoleCommands) { // count tasks where isCompletedState() == true as COMPLETED // but don't count tasks with COMPLETED status twice if (hrc.getStatus().isCompletedState() && hrc.getStatus() != HostRoleStatus.COMPLETED) { // Increase total number of completed tasks; counters.put(HostRoleStatus.COMPLETED, counters.get(HostRoleStatus.COMPLETED) + 1); } // Increment counter for particular status counters.put(hrc.getStatus(), counters.get(hrc.getStatus()) + 1); } // We overwrite the value to have the sum converged counters.put(HostRoleStatus.IN_PROGRESS, hostRoleCommands.size() - counters.get(HostRoleStatus.COMPLETED) - counters.get(HostRoleStatus.QUEUED) - counters.get(HostRoleStatus.PENDING)); return counters; } /** * Returns map for counts of stages that are in various states. * * @param stages collection of beans {@link org.apache.ambari.server.events.listeners.tasks.TaskStatusListener.ActiveStage} * * @return a map of counts of tasks keyed by the task status */ public static Map<StatusType,Map<HostRoleStatus, Integer>> calculateStatusCountsForStage(Collection<TaskStatusListener.ActiveStage> stages) { Map<StatusType,Map<HostRoleStatus, Integer>> counters = new HashMap<>(); for (StatusType statusType : StatusType.values()) { Map <HostRoleStatus, Integer> statusMap = new HashMap<>(); counters.put(statusType,statusMap); // initialize for (HostRoleStatus hostRoleStatus : HostRoleStatus.values()) { statusMap.put(hostRoleStatus, 0); } for (TaskStatusListener.ActiveStage stage : stages) { // count tasks where isCompletedState() == true as COMPLETED // but don't count tasks with COMPLETED status twice HostRoleStatus status; if (statusType == StatusType.DISPLAY_STATUS) { status = stage.getDisplayStatus(); } else { status = stage.getStatus(); } if (status.isCompletedState() && status != HostRoleStatus.COMPLETED) { // Increase total number of completed tasks; statusMap.put(HostRoleStatus.COMPLETED, statusMap.get(HostRoleStatus.COMPLETED) + 1); } // Increment counter for particular status statusMap.put(status, statusMap.get(status) + 1); } statusMap.put(HostRoleStatus.IN_PROGRESS, stages.size() - statusMap.get(HostRoleStatus.COMPLETED) - statusMap.get(HostRoleStatus.QUEUED) - statusMap.get(HostRoleStatus.PENDING)); } return counters; } /** * Returns counts of tasks that are in various states. * * @param hostRoleCommands collection of beans {@link HostRoleCommand} * * @return a map of counts of tasks keyed by the task status */ public static Map<HostRoleStatus, Integer> calculateStatusCountsForTasks(Collection<HostRoleCommand> hostRoleCommands, StageEntityPK stage) { Map<HostRoleStatus, Integer> counters = new HashMap<>(); List<HostRoleCommand> hostRoleCommandsOfStage = new ArrayList<>(); // initialize for (HostRoleStatus hostRoleStatus : HostRoleStatus.values()) { counters.put(hostRoleStatus, 0); } // calculate counts for (HostRoleCommand hrc : hostRoleCommands) { if (stage.getStageId() == hrc.getStageId() && stage.getRequestId() == hrc.getRequestId()) { // count tasks where isCompletedState() == true as COMPLETED // but don't count tasks with COMPLETED status twice if (hrc.getStatus().isCompletedState() && hrc.getStatus() != HostRoleStatus.COMPLETED) { // Increase total number of completed tasks; counters.put(HostRoleStatus.COMPLETED, counters.get(HostRoleStatus.COMPLETED) + 1); } // Increment counter for particular status counters.put(hrc.getStatus(), counters.get(hrc.getStatus()) + 1); hostRoleCommandsOfStage.add(hrc); } } // We overwrite the value to have the sum converged counters.put(HostRoleStatus.IN_PROGRESS, hostRoleCommandsOfStage.size() - counters.get(HostRoleStatus.COMPLETED) - counters.get(HostRoleStatus.QUEUED) - counters.get(HostRoleStatus.PENDING)); return counters; } /** * Returns counts of task entities that are in various states. * * @param tasks the collection of task entities * * @return a map of counts of tasks keyed by the task status */ public static Map<HostRoleStatus, Integer> calculateTaskEntityStatusCounts(Collection<HostRoleCommandEntity> tasks) { Collection<HostRoleStatus> hostRoleStatuses = new LinkedList<>(); for (HostRoleCommandEntity hostRoleCommand : tasks) { hostRoleStatuses.add(hostRoleCommand.getStatus()); } return calculateStatusCounts(hostRoleStatuses); } /** * Return counts of task statuses. * @param stageDto the map of stage-to-summary value objects * @param stageIds the stage ids to consider from the value objects * @return the map of status to counts */ public static Map<HostRoleStatus, Integer> calculateTaskStatusCounts( Map<Long, HostRoleCommandStatusSummaryDTO> stageDto, Set<Long> stageIds) { List<HostRoleStatus> status = new ArrayList<>(); for (Long stageId : stageIds) { if (!stageDto.containsKey(stageId)) { continue; } HostRoleCommandStatusSummaryDTO dto = stageDto.get(stageId); status.addAll(dto.getTaskStatuses()); } return calculateStatusCounts(status); } /** * Calculates the overall status of an upgrade. If there are no tasks, then a * status of {@link HostRoleStatus#COMPLETED} is returned. * * @param stageDto * the map of stage-to-summary value objects * @param stageIds * the stage ids to consider from the value objects * @return the calculated status */ public static CalculatedStatus statusFromStageSummary(Map<Long, HostRoleCommandStatusSummaryDTO> stageDto, Set<Long> stageIds) { // if either are empty, then we have no tasks and therefore no status - we // should return COMPLETED. This can happen if someone removes all tasks but // leaves the stages and request if (stageDto.isEmpty() || stageIds.isEmpty()) { return COMPLETED; } Collection<HostRoleStatus> stageStatuses = new HashSet<>(); Collection<HostRoleStatus> stageDisplayStatuses = new HashSet<>(); Collection<HostRoleStatus> taskStatuses = new ArrayList<>(); for (Long stageId : stageIds) { if (!stageDto.containsKey(stageId)) { continue; } HostRoleCommandStatusSummaryDTO summary = stageDto.get(stageId); int total = summary.getTaskTotal(); boolean skip = summary.isStageSkippable(); Map<HostRoleStatus, Integer> counts = calculateStatusCounts(summary.getTaskStatuses()); HostRoleStatus stageStatus = calculateSummaryStatus(counts, total, skip); HostRoleStatus stageDisplayStatus = calculateSummaryDisplayStatus(counts, total, skip); stageStatuses.add(stageStatus); stageDisplayStatuses.add(stageDisplayStatus); taskStatuses.addAll(summary.getTaskStatuses()); } // calculate the overall status from the stage statuses Map<HostRoleStatus, Integer> counts = calculateStatusCounts(stageStatuses); Map<HostRoleStatus, Integer> displayCounts = calculateStatusCounts(stageDisplayStatuses); HostRoleStatus status = calculateSummaryStatusOfUpgrade(counts, stageStatuses.size()); HostRoleStatus displayStatus = calculateSummaryDisplayStatus(displayCounts, stageDisplayStatuses.size(), false); double progressPercent = calculateProgressPercent(calculateStatusCounts(taskStatuses), taskStatuses.size()); return new CalculatedStatus(status, displayStatus, progressPercent); } /** * Returns counts of tasks that are in various states. * * @param tasks the collection of tasks * * @return a map of counts of tasks keyed by the task status */ private static Map<HostRoleStatus, Integer> calculateTaskStatusCounts(Collection<HostRoleCommand> tasks) { Collection<HostRoleStatus> hostRoleStatuses = new LinkedList<>(); for (HostRoleCommand hostRoleCommand : tasks) { hostRoleStatuses.add(hostRoleCommand.getStatus()); } return calculateStatusCounts(hostRoleStatuses); } /** * Calculate the percent complete based on the given status counts. * * @param counters counts of resources that are in various states * @param total total number of resources in request * * @return the percent complete for the stage */ private static double calculateProgressPercent(Map<HostRoleStatus, Integer> counters, double total) { return total == 0 ? 0 : ((counters.get(HostRoleStatus.QUEUED) * 0.09 + counters.get(HostRoleStatus.IN_PROGRESS) * 0.35 + counters.get(HostRoleStatus.HOLDING) * 0.35 + counters.get(HostRoleStatus.HOLDING_FAILED) * 0.35 + counters.get(HostRoleStatus.HOLDING_TIMEDOUT) * 0.35 + counters.get(HostRoleStatus.COMPLETED)) / total) * 100.0; } /** * Calculate overall status of a stage or upgrade based on the given status counts. * * @param counters counts of resources that are in various states * @param total total number of resources in request. NOTE, completed tasks may be counted twice. * @param skippable true if a single failed status should NOT result in an overall failed status return * * @return summary request status based on statuses of tasks in different states. */ public static HostRoleStatus calculateSummaryStatus(Map<HostRoleStatus, Integer> counters, int total, boolean skippable) { // when there are 0 tasks, return COMPLETED if (total == 0) { return HostRoleStatus.COMPLETED; } if (counters.get(HostRoleStatus.PENDING) == total) { return HostRoleStatus.PENDING; } // By definition, any tasks in a future stage must be held in a PENDING status. if (counters.get(HostRoleStatus.HOLDING) > 0 || counters.get(HostRoleStatus.HOLDING_FAILED) > 0 || counters.get(HostRoleStatus.HOLDING_TIMEDOUT) > 0) { return counters.get(HostRoleStatus.HOLDING) > 0 ? HostRoleStatus.HOLDING : counters.get(HostRoleStatus.HOLDING_FAILED) > 0 ? HostRoleStatus.HOLDING_FAILED : HostRoleStatus.HOLDING_TIMEDOUT; } // Because tasks are not skippable, guaranteed to be FAILED if (counters.get(HostRoleStatus.FAILED) > 0 && !skippable) { return HostRoleStatus.FAILED; } // Because tasks are not skippable, guaranteed to be TIMEDOUT if (counters.get(HostRoleStatus.TIMEDOUT) > 0 && !skippable) { return HostRoleStatus.TIMEDOUT; } int numActiveTasks = counters.get(HostRoleStatus.PENDING) + counters.get(HostRoleStatus.QUEUED) + counters.get(HostRoleStatus.IN_PROGRESS); // ABORTED only if there are no other active tasks if (counters.get(HostRoleStatus.ABORTED) > 0 && numActiveTasks == 0) { return HostRoleStatus.ABORTED; } if (counters.get(HostRoleStatus.COMPLETED) == total) { return HostRoleStatus.COMPLETED; } return HostRoleStatus.IN_PROGRESS; } /** * * @param counters counts of resources that are in various states * @param skippable {Boolean} <code>TRUE<code/> if failure of any of the task should not fail the stage * @return {@link HostRoleStatus} */ public static HostRoleStatus calculateSummaryStatusFromPartialSet(Map<HostRoleStatus, Integer> counters, boolean skippable) { HostRoleStatus status = HostRoleStatus.PENDING; // By definition, any tasks in a future stage must be held in a PENDING status. if (counters.get(HostRoleStatus.HOLDING) > 0 || counters.get(HostRoleStatus.HOLDING_FAILED) > 0 || counters.get(HostRoleStatus.HOLDING_TIMEDOUT) > 0) { status = counters.get(HostRoleStatus.HOLDING) > 0 ? HostRoleStatus.HOLDING : counters.get(HostRoleStatus.HOLDING_FAILED) > 0 ? HostRoleStatus.HOLDING_FAILED : HostRoleStatus.HOLDING_TIMEDOUT; } // Because tasks are not skippable, guaranteed to be FAILED if (counters.get(HostRoleStatus.FAILED) > 0 && !skippable) { status = HostRoleStatus.FAILED; } // Because tasks are not skippable, guaranteed to be TIMEDOUT if (counters.get(HostRoleStatus.TIMEDOUT) > 0 && !skippable) { status = HostRoleStatus.TIMEDOUT; } int inProgressTasks = counters.get(HostRoleStatus.QUEUED) + counters.get(HostRoleStatus.IN_PROGRESS); if (inProgressTasks > 0) { status = HostRoleStatus.IN_PROGRESS; } return status; } /** * * @param hostRoleCommands list of {@link HostRoleCommand} for a stage * @param counters counts of resources that are in various states * @param successFactors Map of roles to their successfactor for a stage * @param skippable {Boolean} <code>TRUE<code/> if failure of any of the task should not fail the stage * @return {@link HostRoleStatus} based on success factor */ public static HostRoleStatus calculateStageStatus(List <HostRoleCommand> hostRoleCommands, Map<HostRoleStatus, Integer> counters, Map<Role, Float> successFactors, boolean skippable) { // when there are 0 tasks, return COMPLETED int total = hostRoleCommands.size(); if (total == 0) { return HostRoleStatus.COMPLETED; } if (counters.get(HostRoleStatus.PENDING) == total) { return HostRoleStatus.PENDING; } // By definition, any tasks in a future stage must be held in a PENDING status. if (counters.get(HostRoleStatus.HOLDING) > 0 || counters.get(HostRoleStatus.HOLDING_FAILED) > 0 || counters.get(HostRoleStatus.HOLDING_TIMEDOUT) > 0) { return counters.get(HostRoleStatus.HOLDING) > 0 ? HostRoleStatus.HOLDING : counters.get(HostRoleStatus.HOLDING_FAILED) > 0 ? HostRoleStatus.HOLDING_FAILED : HostRoleStatus.HOLDING_TIMEDOUT; } if (counters.get(HostRoleStatus.FAILED) > 0 && !skippable) { Set<Role> rolesWithFailedTasks = getRolesOfFailedTasks(hostRoleCommands); Boolean didStageFailed = didStageFailed(hostRoleCommands, rolesWithFailedTasks, successFactors); if (didStageFailed) return HostRoleStatus.FAILED; } if (counters.get(HostRoleStatus.TIMEDOUT) > 0 && !skippable) { Set<Role> rolesWithTimedOutTasks = getRolesOfTimedOutTasks(hostRoleCommands); Boolean didStageFailed = didStageFailed(hostRoleCommands, rolesWithTimedOutTasks, successFactors); if (didStageFailed) return HostRoleStatus.TIMEDOUT; } int numActiveTasks = counters.get(HostRoleStatus.PENDING) + counters.get(HostRoleStatus.QUEUED) + counters.get(HostRoleStatus.IN_PROGRESS); if (numActiveTasks > 0) { return HostRoleStatus.IN_PROGRESS; } else if (counters.get(HostRoleStatus.ABORTED) > 0) { Set<Role> rolesWithTimedOutTasks = getRolesOfAbortedTasks(hostRoleCommands); Boolean didStageFailed = didStageFailed(hostRoleCommands, rolesWithTimedOutTasks, successFactors); if (didStageFailed) return HostRoleStatus.ABORTED; } return HostRoleStatus.COMPLETED; } /** * Get all {@link Role} any of whose tasks is in {@link HostRoleStatus#FAILED} * @param hostRoleCommands list of {@link HostRoleCommand} * @return Set of {@link Role} */ protected static Set<Role> getRolesOfFailedTasks(List <HostRoleCommand> hostRoleCommands) { return getRolesOfTasks(hostRoleCommands, HostRoleStatus.FAILED); } /** * Get all {@link Role} any of whose tasks is in {@link HostRoleStatus#TIMEDOUT} * @param hostRoleCommands list of {@link HostRoleCommand} * @return Set of {@link Role} */ protected static Set<Role> getRolesOfTimedOutTasks(List <HostRoleCommand> hostRoleCommands) { return getRolesOfTasks(hostRoleCommands, HostRoleStatus.TIMEDOUT); } /** * Get all {@link Role} any of whose tasks is in {@link HostRoleStatus#ABORTED} * @param hostRoleCommands list of {@link HostRoleCommand} * @return Set of {@link Role} */ protected static Set<Role> getRolesOfAbortedTasks(List <HostRoleCommand> hostRoleCommands) { return getRolesOfTasks(hostRoleCommands, HostRoleStatus.ABORTED); } /** * Get all {@link Role} any of whose tasks are in given {@code status} * @param hostRoleCommands list of {@link HostRoleCommand} * @param status {@link HostRoleStatus} * @return Set of {@link Role} */ protected static Set<Role> getRolesOfTasks(List <HostRoleCommand> hostRoleCommands, final HostRoleStatus status) { Predicate<HostRoleCommand> predicate = new Predicate<HostRoleCommand>() { @Override public boolean apply(HostRoleCommand hrc) { return hrc.getStatus() == status; } }; Function<HostRoleCommand, Role> transform = new Function<HostRoleCommand, Role>() { @Override public Role apply(HostRoleCommand hrc) { return hrc.getRole(); } }; return FluentIterable.from(hostRoleCommands) .filter(predicate) .transform(transform) .toSet(); } /** * * @param hostRoleCommands list of {@link HostRoleCommand} for a stage * @param roles set of roles to be checked for meeting success criteria * @param successFactors map of role to it's success factor * @return {Boolean} <code>TRUE</code> if stage failed due to hostRoleCommands of any role not meeting success criteria */ protected static Boolean didStageFailed(List<HostRoleCommand> hostRoleCommands, Set<Role> roles, Map<Role, Float> successFactors) { Boolean isFailed = Boolean.FALSE; for (Role role: roles) { List <HostRoleCommand> hostRoleCommandsOfRole = getHostRoleCommandsOfRole(hostRoleCommands, role); List <HostRoleCommand> failedHostRoleCommands = getFailedHostRoleCommands(hostRoleCommandsOfRole); float successRatioForRole = (hostRoleCommandsOfRole.size() - failedHostRoleCommands.size())/hostRoleCommandsOfRole.size(); Float successFactorForRole = successFactors.get(role) == null ? 1.0f : successFactors.get(role); if (successRatioForRole < successFactorForRole) { isFailed = Boolean.TRUE; break; } } return isFailed; } /** * * @param hostRoleCommands list of {@link HostRoleCommand} * @param role {@link Role} * @return list of {@link HostRoleCommand} that belongs to {@link Role} */ protected static List<HostRoleCommand> getHostRoleCommandsOfRole(List <HostRoleCommand> hostRoleCommands, final Role role) { Predicate<HostRoleCommand> predicate = new Predicate<HostRoleCommand>() { @Override public boolean apply(HostRoleCommand hrc) { return hrc.getRole() == role; } }; return FluentIterable.from(hostRoleCommands) .filter(predicate) .toList(); } /** * * @param hostRoleCommands list of {@link HostRoleCommand} * @return list of {@link HostRoleCommand} with failed status */ protected static List<HostRoleCommand> getFailedHostRoleCommands(List <HostRoleCommand> hostRoleCommands) { Predicate<HostRoleCommand> predicate = new Predicate<HostRoleCommand>() { @Override public boolean apply(HostRoleCommand hrc) { return hrc.getStatus().isFailedAndNotSkippableState(); } }; return FluentIterable.from(hostRoleCommands) .filter(predicate) .toList(); } /** * Calculate overall status from collection of statuses * @param hostRoleStatuses list of all stage's {@link HostRoleStatus} * @return overall status of a request */ public static HostRoleStatus getOverallStatusForRequest (Collection<HostRoleStatus> hostRoleStatuses) { Map<HostRoleStatus, Integer> statusCount = calculateStatusCounts(hostRoleStatuses); return calculateSummaryStatus(statusCount, hostRoleStatuses.size(), false); } /** * Calculate overall display status from collection of statuses * @param hostRoleStatuses list of all stage's {@link HostRoleStatus} * @return overall display status of a request */ public static HostRoleStatus getOverallDisplayStatusForRequest (Collection<HostRoleStatus> hostRoleStatuses) { Map<HostRoleStatus, Integer> statusCount = calculateStatusCounts(hostRoleStatuses); return calculateSummaryDisplayStatus(statusCount, hostRoleStatuses.size(), false); } /** * Calculate overall status of an upgrade. * * @param counters counts of resources that are in various states * @param total total number of resources in request * * @return summary request status based on statuses of tasks in different states. */ protected static HostRoleStatus calculateSummaryStatusOfUpgrade( Map<HostRoleStatus, Integer> counters, int total) { return calculateSummaryStatus(counters, total, false); } /** * Calculate an overall display status based on the given status counts. * * @param counters counts of resources that are in various states * @param total total number of resources in request * @param skippable true if a single failed status should NOT result in an overall failed status return * * @return summary request status based on statuses of tasks in different states. */ public static HostRoleStatus calculateSummaryDisplayStatus( Map<HostRoleStatus, Integer> counters, int total, boolean skippable) { return counters.get(HostRoleStatus.FAILED) > 0 ? HostRoleStatus.FAILED: counters.get(HostRoleStatus.TIMEDOUT) > 0 ? HostRoleStatus.TIMEDOUT: counters.get(HostRoleStatus.SKIPPED_FAILED) > 0 ? HostRoleStatus.SKIPPED_FAILED : calculateSummaryStatus(counters, total, skippable); } /** * kind of {@link HostRoleStatus} persisted by {@link Stage} and {@link Request} */ public enum StatusType { STATUS("status"), DISPLAY_STATUS("display_status"); private String value; StatusType(String value) { this.value = value; } public String getValue() { return value; } } }