/src/main/java/com/atlassian/bamboo/plugin/agentsmith/ViewAgentWallboard.java
Java | 368 lines | 294 code | 63 blank | 11 comment | 71 complexity | e0887028e005658d0de06cca72892382 MD5 | raw file
Possible License(s): Apache-2.0
- package com.atlassian.bamboo.plugin.agentsmith;
- import com.atlassian.bamboo.agent.elastic.server.ElasticInstanceManager;
- import com.atlassian.bamboo.agent.elastic.server.RemoteElasticInstance;
- import com.atlassian.bamboo.agent.elastic.server.RemoteElasticInstanceState;
- import com.atlassian.bamboo.build.BuildExecutionManager;
- import com.atlassian.bamboo.buildqueue.manager.AgentManager;
- import com.atlassian.bamboo.buildqueue.manager.LocalAgentManager;
- import com.atlassian.bamboo.v2.build.BuildContext;
- import com.atlassian.bamboo.v2.build.CurrentlyBuilding;
- import com.atlassian.bamboo.v2.build.agent.BuildAgent;
- import com.atlassian.bamboo.v2.build.queue.BuildQueueManager;
- import com.atlassian.bamboo.ww2.BambooActionSupport;
- import com.atlassian.bamboo.ww2.actions.admin.elastic.ElasticUIBean;
- import org.apache.log4j.Logger;
- import java.util.*;
- public class ViewAgentWallboard extends BambooActionSupport {
- // ------------------------------------------------------------------------------------------------------- Constants
- @SuppressWarnings({"UnusedDeclaration"})
- private static final Logger log = Logger.getLogger(ViewAgentWallboard.class);
- private static final List<RemoteElasticInstanceState> ELASTIC_INSTANCE_PENDING =
- Collections.unmodifiableList(Arrays.asList(RemoteElasticInstanceState.INITIAL, RemoteElasticInstanceState.STARTING, RemoteElasticInstanceState.IDENTIFIED));
- private static final List<RemoteElasticInstanceState> ELASTIC_INSTANCE_SHUTTING_DOWN =
- Collections.unmodifiableList(Arrays.asList(RemoteElasticInstanceState.STOPPING, RemoteElasticInstanceState.STOPPED, RemoteElasticInstanceState.SHUTTING_DOWN));
- private static final int DEFAULT_SECONDS_BEFORE_NEXT_REFRESH = 15;
- private static final int DEFAULT_MINUTES_BEFORE_QUEUE_ITEM_OVERDUE = 1;
- private static final int DEFAULT_MINUTES_BEFORE_PENDING_AGENT_OVERDUE = 5;
- private static final Comparator<Map> QUEUE_LIST_COMPARATOR = new Comparator<Map>() {
- public int compare(Map left, Map right) {
- return ((Long) right.get("elapsedTime")).compareTo((Long) left.get("elapsedTime"));
- }
- };
- // ---------------------------------------------------------------------------------------------------- Dependencies
- private AgentManager agentManager;
- private ElasticInstanceManager elasticInstanceManager;
- private BuildExecutionManager buildExecutionManager;
- private BuildQueueManager buildQueueManager;
- private ElasticUIBean elasticUIBean;
- // ------------------------------------------------------------------------------------------------- Type Properties
- private boolean showLegend = true;
- private int secondsBeforeNextRefresh = DEFAULT_SECONDS_BEFORE_NEXT_REFRESH;
- private int minutesBeforeQueueItemOverdue = DEFAULT_MINUTES_BEFORE_QUEUE_ITEM_OVERDUE;
- private int minutesBeforePendingAgentOverdue = DEFAULT_MINUTES_BEFORE_PENDING_AGENT_OVERDUE;
- private List<Map> agentStats = new ArrayList<Map>();
- private List<Map> queueList = new ArrayList<Map>();
- private Map<String, Long> queuetimes = new HashMap<String, Long>();
- private Map createStatistics(List<BuildAgent> buildAgents, String agentType) {
- int idle = 0;
- int busy = 0;
- int hung = 0;
- int disabled = 0;
- for (BuildAgent buildAgent : buildAgents) {
- if (buildAgent.isActive() && buildAgent.isEnabled()) {
- if (buildAgent.isBusy()) {
- CurrentlyBuilding currentlyBuilding = buildExecutionManager.getBuildRunningOnAgent(buildAgent.getId());
- if (currentlyBuilding != null && currentlyBuilding.getBuildHangDetails() != null) {
- hung++;
- } else {
- busy++;
- }
- } else {
- idle++;
- }
- } else if (buildAgent.isActive()) {
- disabled++;
- }
- }
- int total = idle + busy + hung + disabled;
- Map result = new HashMap();
- result.put("agentType", agentType);
- result.put("i18nKeyName", "agent.smith." + agentType + ".agents");
- result.put("idle", idle);
- result.put("busy", busy);
- result.put("hung", hung);
- result.put("disabled", disabled);
- result.put("total", total);
- int idlePercent = getPercentage(idle, total);
- int hungPercent = getPercentage(hung, total);
- int disabledPercent = getPercentage(disabled, total);
- //fix the percentages so they add to 100
- int missingPercent = 100 - (idlePercent + hungPercent + disabledPercent);
- if (busy == 0 && missingPercent != 0) {
- if (idlePercent != 0) {
- idlePercent += missingPercent;
- } else if (disabledPercent != 0) {
- disabledPercent += missingPercent;
- } else {
- hungPercent += missingPercent;
- }
- }
- result.put("idlePercent", idlePercent);
- result.put("hungPercent", hungPercent);
- result.put("disabledPercent", disabledPercent);
- if (idlePercent == 100) {
- result.put("idlePercentCssClass", "idle curveball");
- } else if (idle != 0 && hung == 0 && busy == 0){
- result.put("idlePercentCssClass", "idle curveball");
- }else {
- result.put("idlePercentCssClass", "idle");
- }
- if (hungPercent == 100) {
- result.put("hungPercentCssClass", "hung curveball");
- } else {
- result.put("hungPercentCssClass", "hung");
- }
- if (disabledPercent == 100) {
- result.put("disabledPercentCssClass", "disabled curveball");
- //this makes sure the idle bar doesn't stick out past the round corners
- result.put("idlePercentCssClass", "idle curveball");
- } else {
- result.put("disabledPercentCssClass", "disabled");
- }
- result.put("instanceStatus", Collections.emptyList());
- result.put("show", (total > 0));
- result.put("agentCssClass", "agent");
- if (hung > 0) {
- result.put("qtyCssClass", "qty hung");
- } else {
- result.put("qtyCssClass", "qty");
- }
- result.put("totalInstanceCost", 0d);
- return result;
- }
- private int getPercentage(int value, int total) {
- float percentage = 0;
- if (value > 0) {
- percentage = (float) value / (float) total * 100;
- }
- return (int) percentage;
- }
- @Override
- public String doDefault() throws Exception {
- if (elasticInstanceManager == null) {
- throw new UnsupportedOperationException("Bamboo 3.1.1 or higher is required for this plugin");
- }
- List<BuildAgent> localAgents = new ArrayList<BuildAgent>(agentManager.getAllLocalAgents());
- List<BuildAgent> elasticAgents = agentManager.getOnlineElasticAgents();
- List<BuildAgent> remoteAgents = new ArrayList<BuildAgent>(agentManager.getActiveAndEnabledAgents());
- remoteAgents.removeAll(localAgents);
- remoteAgents.removeAll(elasticAgents);
- agentStats.add(createStatistics(localAgents, "local"));
- agentStats.add(createStatistics(remoteAgents, "remote"));
- //ELASTIC
- List<String> instanceStatus = new ArrayList<String>();
- Map elasticAgentStatistics = createStatistics(elasticAgents, "elastic");
- agentStats.add(elasticAgentStatistics);
- Double totalInstanceCost = 0d;
- Integer elasticPendingCount = 0;
- Integer elasticShuttingCount = 0;
- Integer elasticFailedCount = 0;
- Long maxElasticWaitTime = 0L;
- Long totalElasticWaitTime = 0L;
- for (RemoteElasticInstance elasticAgent : elasticInstanceManager.getElasticRemoteAgents()) {
- RemoteElasticInstanceState status = elasticAgent.getState();
- String currentStatus = "";
- if (ELASTIC_INSTANCE_PENDING.contains(status) ||
- (status == RemoteElasticInstanceState.RUNNING && elasticAgent.isAgentLoading())) {
- currentStatus = "pending";
- elasticPendingCount++;
- } else if (ELASTIC_INSTANCE_SHUTTING_DOWN.contains(status)) {
- currentStatus = "shutting";
- elasticShuttingCount++;
- } else if (status.isFinal()) {
- currentStatus = "failed";
- elasticFailedCount++;
- }
- //elasticUIBean is only available from Bamboo 3.2
- if (elasticUIBean != null) {
- Double instanceCost = elasticUIBean.getInstancePrice(elasticAgent);
- if (instanceCost != null) {
- totalInstanceCost += instanceCost;
- }
- }
-
- //check time data for pending agents
- if (currentStatus.equals("pending")) {
- Long elapsed = getCurrentSystemTime() - elasticAgent.getInstance().getLaunchTime().getTime();
- totalElasticWaitTime += elapsed;
- if (elapsed > maxElasticWaitTime) {
- maxElasticWaitTime = elapsed;
- }
- if (elapsed > getMinutesBeforePendingAgentOverdue()*60*1000) {
- currentStatus = "overdue";
- }
- }
- instanceStatus.add(currentStatus);
- }
- elasticAgentStatistics.put("totalInstanceCost", totalInstanceCost);
- elasticAgentStatistics.put("pendingCount", elasticPendingCount);
- elasticAgentStatistics.put("shuttingCount", elasticShuttingCount);
- elasticAgentStatistics.put("failedCount", elasticFailedCount);
- elasticAgentStatistics.put("maxElasticWaitTime", maxElasticWaitTime);
- elasticAgentStatistics.put("totalElasticWaitTime", totalElasticWaitTime);
- Collections.sort(instanceStatus);
- elasticAgentStatistics.put("instanceStatus", instanceStatus);
- if (!instanceStatus.isEmpty()) {
- elasticAgentStatistics.put("show", true);
- elasticAgentStatistics.put("agentCssClass", "agent has-misc");
- }
- //QUEUE TIMES
- Long maxElapsed = 0L;
- Long totalQueueTime = 0L;
- for (BuildContext buildContext : buildQueueManager.getBuildQueue()) {
- CurrentlyBuilding currentlyBuilding = buildExecutionManager.getCurrentlyBuildingByBuildResult(buildContext);
- Long elapsed = getCurrentSystemTime() - currentlyBuilding.getQueueTime().getTime();
- if (maxElapsed < elapsed) {
- maxElapsed = elapsed;
- }
- totalQueueTime += elapsed;
- Map queueItem = new HashMap();
- queueItem.put("elapsedTime", elapsed);
- boolean isOverdue = elapsed > getMinutesBeforeQueueItemOverdue() * 60 * 1000;
- queueItem.put("isOverdue", isOverdue);
- queueItem.put("cssClass", isOverdue ? "overdue" : "");
- queueItem.put("planName", buildContext.getPlanName());
- String readableElapsedTimei18nKeyName = "agent.smith.queue.time.none";
- long readableElapsedTime = 0;
- if (elapsed > 0) {
- readableElapsedTime = elapsed / 1000;
- if (readableElapsedTime > 60) {
- readableElapsedTime /= 60;
- if (readableElapsedTime > 60) {
- readableElapsedTime /= 60;
- readableElapsedTimei18nKeyName = "agent.smith.queue.time.hour";
- } else {
- readableElapsedTimei18nKeyName = "agent.smith.queue.time.minute";
- }
- } else {
- readableElapsedTimei18nKeyName = "agent.smith.queue.time.second";
- }
- }
- queueItem.put("readableElapsedTime", readableElapsedTime);
- queueItem.put("readableElapsedTimei18nKeyName", readableElapsedTimei18nKeyName);
- queueList.add(queueItem);
- }
-
- queuetimes.put("maxQueueTime", maxElapsed);
- queuetimes.put("totalQueueTime", totalQueueTime);
- for (Map queueItem : queueList) {
- int width = (int) ((float) (Long) queueItem.get("elapsedTime") / (float) maxElapsed * 100);
- if (width == 0) {
- width = 1;
- }
- queueItem.put("width", width);
- }
- Collections.sort(queueList, QUEUE_LIST_COMPARATOR);
- return SUCCESS;
- }
- // -------------------------------------------------------------------------------------------------- Public Methods
- public List<Map> getQueueList() {
- return queueList;
- }
- public List<Map> getAgentStats() {
- return agentStats;
- }
-
- public Map getQueueTimes() {
- return this.queuetimes;
- }
- public int getMinutesBeforeQueueItemOverdue() {
- if (minutesBeforeQueueItemOverdue < DEFAULT_MINUTES_BEFORE_QUEUE_ITEM_OVERDUE) {
- return DEFAULT_MINUTES_BEFORE_QUEUE_ITEM_OVERDUE;
- }
- return minutesBeforeQueueItemOverdue;
- }
- public void setMinutesBeforeQueueItemOverdue(int minutesBeforeQueueItemOverdue) {
- this.minutesBeforeQueueItemOverdue = minutesBeforeQueueItemOverdue;
- }
- public int getMinutesBeforePendingAgentOverdue() {
- if (minutesBeforePendingAgentOverdue < DEFAULT_MINUTES_BEFORE_PENDING_AGENT_OVERDUE) {
- return DEFAULT_MINUTES_BEFORE_PENDING_AGENT_OVERDUE;
- }
- return minutesBeforePendingAgentOverdue;
- }
- public void setMinutesBeforePendingAgentOverdue(int minutesBeforePendingAgentOverdue) {
- this.minutesBeforePendingAgentOverdue = minutesBeforePendingAgentOverdue;
- }
- public boolean getShowLegend() {
- return showLegend;
- }
- public void setShowLegend(boolean showLegend) {
- this.showLegend = showLegend;
- }
- public int getSecondsBeforeNextRefresh() {
- if (secondsBeforeNextRefresh < DEFAULT_SECONDS_BEFORE_NEXT_REFRESH) {
- return DEFAULT_SECONDS_BEFORE_NEXT_REFRESH;
- }
- return secondsBeforeNextRefresh;
- }
- public void setSecondsBeforeNextRefresh(int secondsBeforeNextRefresh) {
- this.secondsBeforeNextRefresh = secondsBeforeNextRefresh;
- }
- // -------------------------------------------------------------------------------------- Basic accessors & mutators
- public void setAgentManager(AgentManager agentManager) {
- this.agentManager = agentManager;
- }
- public void setElasticInstanceManager(ElasticInstanceManager elasticInstanceManager) {
- this.elasticInstanceManager = elasticInstanceManager;
- }
- public void setBuildExecutionManager(BuildExecutionManager buildExecutionManager) {
- this.buildExecutionManager = buildExecutionManager;
- }
- public void setBuildQueueManager(BuildQueueManager buildQueueManager) {
- this.buildQueueManager = buildQueueManager;
- }
- public void setElasticUIBean(ElasticUIBean elasticUIBean) {
- this.elasticUIBean = elasticUIBean;
- }
- }