/* * The MIT License * * Copyright 2013 Sony Mobile Communications AB. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.sonyericsson.jenkins.plugins.bfa.graphs; import java.util.Calendar; import java.util.Date; import java.util.Map; import java.util.regex.Pattern; import com.sonyericsson.jenkins.plugins.bfa.BfaGraphAction; import com.sonyericsson.jenkins.plugins.bfa.PluginImpl; import com.sonyericsson.jenkins.plugins.bfa.utils.BfaUtils; import hudson.model.ModelObject; import hudson.model.Computer; import hudson.model.Hudson; import hudson.model.Node; import hudson.model.Slave; import hudson.util.Graph; /** * Class for displaying graphs for nodes - slaves/masters. * @author Christoffer Lauri <christoffer.lauri@sonymobile.com> * */ public class ComputerGraphAction extends BfaGraphAction { /** * Title for graphs with failure causes */ private static final String GRAPH_TITLE_CAUSES = "Failure causes for this node"; /** * Title for graphs with categories */ private static final String GRAPH_TITLE_CATEGORIES = "Failures grouped by categories for this node"; /** * The url-name of the Action */ private static final String URL_NAME = "bfa-comp-graphs"; /** * The display-name of the action */ private static final String DISPLAY_NAME = "Graph statistics"; private Computer computer; /** * Standard constructor. * @param computer The computer/node */ public ComputerGraphAction(Computer computer) { this.computer = computer; } @Override public String getIconFileName() { if (Hudson.getInstance().hasPermission(PluginImpl.UPDATE_PERMISSION) && PluginImpl.getInstance().isGraphsEnabled()) { return PluginImpl.getDefaultIcon(); } else { return null; } } @Override public String getDisplayName() { if (PluginImpl.getInstance().isGraphsEnabled()) { return DISPLAY_NAME; } return null; } @Override public String getUrlName() { return URL_NAME; } /** * Get the name of the node. * @return The name as a String, or null */ private String getNodeName() { if (computer == null) { return null; } return computer.getName(); } /** * Returns whether the node is a slave or master * @return True if a slave, otherwise false */ private boolean isSlave() { if (computer == null) { return false; } return computer.getNode() instanceof Slave; } @Override public ModelObject getOwner() { return computer; } @Override public GraphType[] getGraphTypes() { return new GraphType[] { GraphType.BAR_CHART_CAUSES, GraphType.PIE_CHART_CAUSES, GraphType.TIME_SERIES_CHART_CAUSES, GraphType.BAR_CHART_CATEGORIES, GraphType.PIE_CHART_CATEGORIES, GraphType.TIME_SERIES_CHART_CATEGORIES, }; } @Override public String getGraphsPageTitle() { return "Statistics for node " + getNodeName(); } @Override protected Graph getGraph(GraphType which, Date timePeriod, boolean hideManAborted, boolean forAllMasters, Map<String, String> rawReqParams) { GraphFilterBuilder filter = getDefaultBuilder(hideManAborted, timePeriod); switch (which) { case BAR_CHART_CAUSES: return new BarChart(-1, DEFAULT_GRAPH_WIDTH, DEFAULT_GRAPH_HEIGHT, null, filter, GRAPH_TITLE_CAUSES, false); case BAR_CHART_CATEGORIES: return new BarChart(-1, DEFAULT_GRAPH_WIDTH, DEFAULT_GRAPH_HEIGHT, null, filter, GRAPH_TITLE_CATEGORIES, true); case PIE_CHART_CAUSES: return new PieChart(-1, DEFAULT_GRAPH_WIDTH, DEFAULT_GRAPH_HEIGHT, null, filter, GRAPH_TITLE_CAUSES, false); case PIE_CHART_CATEGORIES: return new PieChart(-1, DEFAULT_GRAPH_WIDTH, DEFAULT_GRAPH_HEIGHT, null, filter, GRAPH_TITLE_CATEGORIES, true); case TIME_SERIES_CHART_CAUSES: return getTimeSeriesChart(false, GRAPH_TITLE_CAUSES, filter, rawReqParams); case TIME_SERIES_CHART_CATEGORIES: return getTimeSeriesChart(true, GRAPH_TITLE_CATEGORIES, filter, rawReqParams); default: break; } return null; } /** * Get a time series chart corresponding to the specified arguments. * @param byCategories True to group by categories, or false causes * @param title The title of the graph * @param filter GraphFilterBuilder to specify data to use * @param rawReqParams A map with the url-parameters from the request * @return A time series graph */ private Graph getTimeSeriesChart(boolean byCategories, String title, GraphFilterBuilder filter, Map<String, String> rawReqParams) { String date = rawReqParams.get(URL_PARAM_TIME_PERIOD); int interval; Calendar cal = Calendar.getInstance(); if (URL_PARAM_VALUE_TODAY.equals(date)) { interval = Calendar.HOUR_OF_DAY; cal.add(Calendar.DAY_OF_YEAR, -1); } else { interval = Calendar.DATE; cal.add(Calendar.MONTH, -1); } filter.setSince(cal.getTime()); return new TimeSeriesChart(-1, DEFAULT_GRAPH_WIDTH, DEFAULT_GRAPH_HEIGHT, null, filter, interval, byCategories, title); } /** * Get a GraphFilterBuilder corresponding to the specified arguments. * @param hideAborted Hide manually aborted * @param period The time period * @return A GraphFilterBuilder */ private GraphFilterBuilder getDefaultBuilder(boolean hideAborted, Date period) { GraphFilterBuilder filter = new GraphFilterBuilder(); if (hideAborted) { filter.setExcludeResult(EXCLUDE_ABORTED); } filter.setSince(period); String nodeName = getNodeName(); if (isSlave()) { filter.setSlaveName(nodeName); } else { // Computer.getName() returns empty string for master, // so let's get the name the other way filter.setMasterName(BfaUtils.getMasterName()); } return filter; } @Override protected String getGraphCacheId(GraphType whichGraph, String reqTimePeriod, boolean hideAborted, boolean forAllMasters) { return getClass().getSimpleName() + ID_SEPARATOR + whichGraph.getValue() + ID_SEPARATOR + getNodeName() + ID_SEPARATOR + reqTimePeriod + ID_SEPARATOR + String.valueOf(hideAborted); } /** * Invalidate all graph caches for the specified computer. * @param computer The computer whose graphs to invalidate */ public static void invalidateNodeGraphCache(Computer computer) { if (computer != null) { Pattern projectPattern = Pattern.compile("^.*" + ID_SEPARATOR + computer.getName() + ID_SEPARATOR + ".*$"); GraphCache.getInstance().invalidateMatching(projectPattern); } } /** * Invalidate all graph caches for the specified buildNode. * @param buildNode The buildNode whose graphs to invalidate */ public static void invalidateNodeGraphCache(Node buildNode) { if (buildNode != null) { Computer correspondingComputer = buildNode.toComputer(); invalidateNodeGraphCache(correspondingComputer); } } }