"Fossies" - the Fresh Open Source Software Archive

Member "ganglia-web-3.7.2/graph.php" (8 Jun 2016, 56029 Bytes) of package /linux/www/ganglia-web-3.7.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "graph.php" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.7.1_vs_3.7.2.

    1 <?php
    2 // vim: tabstop=2:softtabstop=2:shiftwidth=2:expandtab
    3 
    4 include_once "./eval_conf.php";
    5 include_once "./get_context.php";
    6 include_once "./functions.php";
    7 
    8 function add_total_to_cdef($cdef, 
    9                $total_ids, 
   10                $graph_config_scale) {
   11   // Percentage calculation for cdefs, if required
   12   $total = " CDEF:'total'=";
   13   if (count($total_ids) == 0) {
   14     // Handle nothing gracefully, do nothing
   15   } else if (count($total_ids) == 1) {
   16     // Concat just that id, leave it at that (100%)
   17     $total .= $total_ids[0];
   18     if (isset($graph_config_scale))
   19       $total .= ",${graph_config_scale},*";
   20     $cdef = $total . ' ' . $cdef;
   21   } else {
   22     $total .= $total_ids[0];
   23     for ($i = 1; $i < count($total_ids); $i++)
   24       $total .= ',' . $total_ids[$i] . ',ADDNAN';
   25     
   26     if (isset($graph_config['scale']))
   27       $total .= ",${graph_config_scale},*";
   28     
   29     // Prepend total calculation
   30     $cdef = $total . ', ' . $cdef;
   31   }
   32   return $cdef;
   33 }
   34 
   35 function graphdef_add_series($graphdef, 
   36                  $series,
   37                  $series_type,
   38                  $graph_config_percent,
   39                  $graph_config_scale,
   40                  $stack_counter,
   41                  $series_id,
   42                  $max_label_length,
   43                  $conf_graphreport_stats,
   44                  $conf_graphreport_stat_items) {
   45   static $line_widths = array("1", "2", "3");
   46   
   47   $label = str_pad(sanitize($series['label']), $max_label_length);
   48   switch ($series_type) {
   49   case "line":
   50     // Make sure it's a recognized line type
   51     $line_width = isset($series['line_width']) && 
   52       in_array($series['line_width'], $line_widths) ? 
   53       $series['line_width'] : '1';
   54     $graphdef .= "LINE" . $line_width;
   55     $graphdef .= ":'";
   56     if (isset($graph_config_percent) && 
   57     $graph_config_percent == '1') {
   58       $graphdef .= "p";
   59     } else if (isset($graph_config_scale)) {
   60       $graphdef .= "s";
   61     }
   62     $graphdef .= "${series_id}'#${series['color']}:'${label}' ";
   63     break;
   64     
   65   case "stack":
   66   case "percent":
   67     // First element in a stack has to be AREA
   68     if ($stack_counter == 0) {
   69       $graphdef .= "AREA";
   70       $stack_counter++;
   71     } else {
   72       $graphdef .= "STACK";
   73     }
   74     $graphdef .= ":'";
   75     if (isset($graph_config_percent) && 
   76     $graph_config_percent == '1') {
   77       $graphdef .= "p";
   78     } else if (isset($graph_config_scale)) {
   79       $graphdef .= "s";
   80     }
   81     $graphdef .= "${series_id}'#${series['color']}:'${label}' ";
   82     break;
   83   
   84     // Percentile lines
   85   case "percentile":
   86     $percentile = isset($series['percentile']) ? 
   87       floatval($series['percentile']): 95;
   88     $graphdef .= "VDEF:t${series_id}=${series_id},${percentile},PERCENT ";
   89     $line_width = isset($series['line_width']) && 
   90       in_array($series['line_width'], $line_widths) ? 
   91       $series['line_width'] : '1';
   92     $graphdef .= "LINE" . $line_width . 
   93       ":'t$series_id'#{$series['color']}:'{$label}':dashes ";
   94     break;
   95     
   96   case "area":
   97     $graphdef .= "AREA";
   98     $graphdef .= ":'$series_id'#${series['color']}:'${label}' ";
   99     break;
  100   }
  101 
  102   if ($conf_graphreport_stats) {
  103     $id = $series_id;
  104     if (isset($graph_config_percent) && 
  105     $graph_config_percent == '1') {
  106       $id = 'p' . $id;
  107     } else if (isset($graph_config_scale)) {
  108       $id = 's' . $id;
  109     }
  110     $graphdef .= legendEntry($id, $conf_graphreport_stat_items);
  111   }
  112   
  113   return array($graphdef, $stack_counter);
  114 }
  115 
  116 ///////////////////////////////////////////////////////////////////////////////
  117 // Populate $rrdtool_graph from $config (from JSON file).
  118 ///////////////////////////////////////////////////////////////////////////////
  119 function rrdtool_graph_merge_args_from_json($rrdtool_graph,
  120                         $graph_config,
  121                         $context,
  122                         $size,
  123                         $conf_rrds,
  124                         $conf_graphreport_stats,
  125                         $conf_graphreport_stat_items) {
  126                         
  127   $title = sanitize($graph_config['title']);
  128   $rrdtool_graph['title'] = $title; 
  129   // If vertical label is empty or non-existent set it to space otherwise 
  130   // rrdtool will fail
  131   if (! isset($graph_config['vertical_label']) || 
  132       $graph_config['vertical_label'] == "") {
  133      $rrdtool_graph['vertical-label'] = " ";   
  134   } else {
  135     $rrdtool_graph['vertical-label'] = 
  136       sanitize($graph_config['vertical_label']);
  137   }
  138   
  139   $rrdtool_graph['lower-limit'] = '0';
  140   
  141   if (isset($graph_config['height_adjustment']) ) {
  142     $rrdtool_graph['height'] += 
  143       ($size == 'medium') ? $graph_config['height_adjustment'] : 0;
  144   } else {
  145     $rrdtool_graph['height'] += ($size == 'medium') ? 28 : 0;
  146   } 
  147   
  148   // find longest label length, so we pad the others accordingly to get 
  149   // consistent column alignment
  150   $max_label_length = 0;
  151   foreach($graph_config['series'] as $series)
  152     $max_label_length = max(strlen($series['label']), $max_label_length);
  153   
  154   $seriesdef = '';
  155   $cdef = '';
  156   $graphdef = '';
  157   $stack_counter = 0;
  158   $total_ids = array();
  159 
  160   // Loop through all the graph series
  161   foreach ($graph_config['series'] as $series_id => $series) {
  162     // ignore series if context is not defined in json template
  163     if (isset($series['contexts']) and 
  164     !in_array($context, $series['contexts']))
  165       continue;
  166 
  167     $rrd_dir = $conf_rrds . "/" . 
  168       $series['clustername'] . "/" . 
  169       $series['hostname'];
  170     
  171     $metric = sanitize($series['metric']);
  172     $metric_file = $rrd_dir . "/" . $metric . ".rrd";
  173     
  174     // Make sure metric file exists. Otherwise we'll get a broken graph
  175     if (is_file($metric_file)) {
  176       // Need this when defining graphs that may use same metric names
  177       $unique_id = "a" . $series_id;
  178       $total_ids[] = $unique_id;
  179         
  180       // use custom DS defined in json template if it's 
  181       // defined (default = 'sum')
  182       $DS = isset($series['ds']) ? sanitize($series['ds']) : 'sum';
  183       $seriesdef .= " DEF:'$unique_id'='$metric_file':'$DS':AVERAGE ";
  184 
  185       if (isset($graph_config['scale']))
  186     $cdef .= 
  187       " CDEF:'s${unique_id}'=${unique_id},${graph_config['scale']},* ";
  188 
  189       if (isset($graph_config['percent']) && $graph_config['percent'] == '1')
  190     $cdef .= " CDEF:'p${unique_id}'=${unique_id},total,/,100,* ";
  191 
  192       // By default graph is a line graph
  193       $series_type = isset($series['type']) ? $series['type'] : "line";
  194       
  195       list($graphdef, $stack_counter) =
  196     graphdef_add_series($graphdef, 
  197                 $series,
  198                 $series_type,
  199                 $graph_config['percent'],
  200                 $graph_config['scale'],
  201                 $stack_counter,
  202                 $unique_id,
  203                 $max_label_length,
  204                 $conf_graphreport_stats,
  205                 $conf_graphreport_stat_items);
  206     } // end of if (is_file($metric_file))
  207   }
  208 
  209   $show_total = isset($graph_config['show_total']) && 
  210     ($graph_config['show_total'] == 1);
  211   if ($show_total ||
  212       (isset($graph_config['percent']) && 
  213        $graph_config['percent'] == '1')) {
  214     $cdef = add_total_to_cdef($cdef,
  215                   $total_ids,
  216                   $graph_config['scale']);
  217     if ($show_total) {
  218       $cdef .= " LINE1:'total'#000000:'Total' ";
  219       if ($conf_graphreport_stats)
  220     $cdef .= legendEntry('total', $conf_graphreport_stat_items);
  221     }
  222   }
  223 
  224   // If we end up with the empty series it means that no RRD files matched. 
  225   // This can happen if we are trying to create a report and metrics for 
  226   // this host were not collected. If that happens we should create an 
  227   // empty graph
  228   if ($seriesdef == "") {
  229     $rrdtool_graph['series'] = 
  230       'HRULE:1#FFCC33:"No matching metrics detected or RRDs not readable"';   
  231   } else {
  232     $rrdtool_graph['series'] = $seriesdef . ' ' . $cdef . ' ' . $graphdef;
  233   }
  234   
  235   return $rrdtool_graph;
  236 }
  237 
  238 function build_aggregate_graph_config_from_url($conf_graph_colors) {
  239   // If graph type is not specified default to line graph
  240   $graph_type = isset($_GET["gtype"]) && 
  241     in_array($_GET["gtype"], array("stack", "line", "percent")) ?
  242     $_GET["gtype"] : 'line';
  243 
  244   // If line width not specified default to 2
  245   $line_width = isset($_GET["lw"]) && 
  246     in_array($_GET["lw"], array("1", "2", "3")) ?
  247     $_GET["lw"] : '2';
  248 
  249   $graph_legend = isset($_GET["glegend"]) && 
  250     in_array($_GET["glegend"], array("show", "hide")) ?
  251     $_GET["glegend"] : 'show';
  252 
  253   /////////////////////////////////////////////////////////////////////////////
  254   // In order to reduce the load on the machine when someone is doing host
  255   // compare we look whether host list has been supplied via hl arg.
  256   // That way we do not have get metric cache
  257   /////////////////////////////////////////////////////////////////////////////
  258   if (isset($_GET['hl'])) {
  259     $counter = 0;
  260     $color_count = count($conf_graph_colors);
  261     $metric_name = str_replace("$", 
  262                    "", 
  263                    str_replace("^", 
  264                        "", 
  265                        $_GET['mreg'][0]));
  266     $host_list = explode(",", $_GET['hl']);
  267     foreach ($host_list as $host_cluster) {
  268       $color_index = $counter % $color_count;
  269       $parts = explode("|", $host_cluster);
  270       $hostname = $parts[0];
  271       $clustername = $parts[1];
  272 
  273       $series = array("hostname" => $hostname,
  274                       "clustername" => $clustername,
  275                       "fill" => "true", 
  276                       "metric" => $metric_name,  
  277                       "color" => $conf_graph_colors[$color_index], 
  278                       "label" => $hostname, 
  279                       "type" => $graph_type);
  280 
  281       if ($graph_type == "line" || $graph_type == "area") {
  282         $series['line_width'] = $line_width;
  283       } else if ($graph_type == "percent") {
  284         $graph_config['percent'] = "1";
  285       } else {
  286         $series['stack'] = "1";
  287       }
  288       $graph_config['series'][] = $series;
  289       
  290       $counter++;
  291     } 
  292   } else {
  293     $exclude_host_from_legend_label = 
  294       (array_key_exists('lgnd_xh', $_GET) && 
  295        $_GET['lgnd_xh'] == "true") ? TRUE : FALSE;
  296 
  297     $sortit = true;
  298     if($_GET['sortit'] == "false") {
  299       $sortit = false;
  300     }
  301 
  302     $graph_config = 
  303       build_aggregate_graph_config($graph_type, 
  304                    $line_width, 
  305                    $_GET['hreg'], 
  306                    $_GET['mreg'],
  307                    $graph_legend,
  308                    $exclude_host_from_legend_label,
  309                                    $sortit);
  310   }
  311 
  312   // Set up 
  313   $graph_config["report_type"] = "standard";
  314   $graph_config["vertical_label"] =  isset($_GET["vl"]) ? 
  315     sanitize($_GET["vl"])  : NULL;
  316   $graph_config["graph_scale"] = isset($_GET["gs"]) ? 
  317     sanitize($_GET["gs"]) : NULL;
  318   $graph_config["scale"] = isset($_GET["scale"]) ?
  319     sanitize($_GET["scale"]) : NULL;
  320   $graph_config["show_total"] = isset($_GET["show_total"]) ? 
  321     sanitize($_GET["show_total"]) : NULL;
  322   if (isset($_GET['title']) && $_GET['title'] != "")
  323     $graph_config["title"] = sanitize($_GET['title']);
  324   return $graph_config;
  325 }
  326 
  327 ###############################################################################
  328 # This builds rrdtool config for composite graphs that are defined directly
  329 # in a view. It requires a view name and item id in order to be able
  330 # to find the graph configuration. item_id needs to be unique otherwise
  331 # only first definition will be used
  332 ###############################################################################
  333 function rrdtool_graph_build_view_graph($rrdtool_graph,
  334                     $view_name,
  335                     $item_id,
  336                     $context,
  337                     $size,
  338                     $conf_rrds,
  339                     $conf_graphreport_stats,
  340                     $conf_graphreport_stat_items) {
  341   $available_views = get_available_views();
  342   foreach ($available_views as $view) {
  343     // Find view settings
  344     if ($view_name == $view['view_name'])
  345       break;
  346   }
  347 
  348   foreach ($view['items'] as $view_item) {
  349     if ($item_id == $view_item['item_id'])
  350       break;
  351   }
  352   $rrdtool_graph = 
  353     rrdtool_graph_merge_args_from_json($rrdtool_graph,
  354                        $view_item,
  355                        $context,
  356                        $size,
  357                        $conf_rrds,
  358                        $conf_graphreport_stats,
  359                        $conf_graphreport_stat_items);
  360   return array( $rrdtool_graph, $view_item);
  361 }
  362 
  363 ///////////////////////////////////////////////////////////////////////////////
  364 // Graphite graphs
  365 ///////////////////////////////////////////////////////////////////////////////
  366 function build_graphite_series($context, $graph_config, $host_cluster = "") {
  367   $targets = array();
  368   $colors = array();
  369   
  370   // Keep track of stacked items
  371   $stacked = 0;
  372 
  373   foreach ($graph_config['series'] as $item) {
  374     if (isset($item['contexts']) and
  375     !in_array($context, $item['contexts']))
  376       continue;
  377 
  378     if ($item['type'] == "stack")
  379       $stacked++;
  380 
  381     if (isset($item['hostname']) && isset($item['clustername'])) {
  382       $host_cluster = $item['clustername'] . "." . 
  383     str_replace(".", "_", $item['hostname']);
  384     }
  385 
  386     $targets[] = 
  387       "target=". urlencode("alias(" . 
  388                $host_cluster . "." . 
  389                $item['metric'] . 
  390                ".sum,'" . $item['label'] . 
  391                "')");
  392     $colors[] = $item['color'];
  393   }
  394   $series = implode($targets, '&');
  395   $series .= "&colorList=" . implode($colors, ',');
  396   $series .= "&vtitle=" . 
  397     urlencode(isset($graph_config['vertical_label']) ? 
  398           $graph_config['vertical_label'] : "");
  399 
  400   // Do we have any stacked elements. We assume if there is only one element
  401   // that is stacked that rest of it is line graphs
  402   if ($stacked > 0) {
  403     if ($stacked > 1)
  404       $series .= "&areaMode=stacked";
  405     else
  406       $series .= "&areaMode=first";
  407   }
  408   
  409   return $series;
  410 }
  411 
  412 function build_graphite_url($rrd_graphite_link,
  413                 $rrd_dir,
  414                 $conf,
  415                 $clustername,
  416                 $host,
  417                 $size,
  418                 $height,
  419                 $width,
  420                 $graph_config,
  421                 $context,
  422                 $metric_name,
  423                 $cs,
  424                 $ce,
  425                 $start,
  426                 $end,
  427                 $min,
  428                 $max,
  429                 $title,
  430                 $range) {
  431   // Check whether the link exists from Ganglia RRD tree to the graphite 
  432   // storage/rrd_dir area
  433   if (! is_link($rrd_graphite_link)) {
  434     // Does the directory exist for the cluster. If not create it
  435     if (! is_dir($conf['graphite_rrd_dir'] . "/" . 
  436          str_replace(" ", "_", $clustername)) )
  437       mkdir($conf['graphite_rrd_dir'] . "/" . 
  438         str_replace(" ", "_", $clustername));
  439     symlink($rrd_dir, str_replace(" ", "_", $rrd_graphite_link));
  440   }
  441   
  442   // Generate host cluster string
  443   if (isset($clustername))
  444     $host_cluster = str_replace(" ", "_", $clustername) . "." . $host;
  445   else
  446     $host_cluster = $host;
  447   
  448   $height += 70;
  449   
  450   if ($size == "small")
  451     $width += 20;
  452   
  453   // If graph_config is already set we can use it immediately
  454   if (isset($graph_config)) {
  455     $target = build_graphite_series($context, $graph_config, "");
  456   } else {
  457     if (isset($_GET['g'])) {
  458       // if it's a report increase the height for additional 30 pixels
  459       $height += 40;
  460       $report_name = sanitize($_GET['g']);
  461       $report_definition_file = $conf['gweb_root'] . "/graph.d/" . 
  462     $report_name . ".json";
  463       // Check whether report is defined in graph.d directory
  464       if (is_file($report_definition_file)) {
  465     $graph_config = json_decode(file_get_contents($report_definition_file),
  466                     TRUE);
  467       } else {
  468     error_log("There is JSON config file specifying $report_name.");
  469     exit(1);
  470       }
  471     
  472       if (isset($graph_config)) {
  473     switch ($graph_config["report_type"]) {
  474         case "template":
  475           $target = str_replace("HOST_CLUSTER", 
  476                 $conf['graphite_prefix'] . $host_cluster,
  477                 $graph_config["graphite"]);
  478           break;
  479     
  480         case "standard":
  481           $target = 
  482         build_graphite_series($context, 
  483                   $graph_config, 
  484                   $conf['graphite_prefix'] . $host_cluster);
  485           break;
  486     
  487         default:
  488           error_log("No valid report_type specified in the " .
  489                     $report_name .
  490                     " definition.");
  491           break;
  492     }
  493     
  494     $title = $graph_config['title'];
  495       } else {
  496     error_log("Configuration file to $report_name exists; " .
  497           "however, it doesn't appear it's a valid JSON file");
  498     exit(1);
  499       }
  500     } else {
  501       // It's a simple metric graph
  502       $vlabel = isset($_GET["vl"]) ? sanitize($_GET["vl"])  : NULL;
  503       $target = "target=" . $conf['graphite_prefix'] . 
  504     "$host_cluster.$metric_name.sum&hideLegend=true&vtitle=" . 
  505     urlencode($vlabel) . 
  506     "&areaMode=all&colorList=". $conf['default_metric_color'];
  507       $title = " ";
  508     }
  509   } 
  510     
  511   if ($cs) 
  512     $start = date("H:i_Ymd", strtotime($cs));
  513 
  514   if ($ce) 
  515     $end = date("H:i_Ymd", strtotime($ce));
  516 
  517   if ($max == 0) 
  518     $max = "";
  519 
  520   $graphite_url = $conf['graphite_url_base'] . 
  521     "?width=$width&height=$height&" . 
  522     $target . 
  523     "&from=" . $start . "&until=" . $end . 
  524     "&yMin=" . $min . "&yMax=" . $max . 
  525     "&bgcolor=FFFFFF&fgcolor=000000&title=" . 
  526     urlencode($title . " last " . $range);
  527 
  528   return $graphite_url;
  529 }
  530 
  531 function build_value_for_json($value) {
  532   if (is_numeric($value))
  533     $val = floatval($value);
  534   else
  535     $val = $value;
  536 
  537   return $val;
  538 }
  539 
  540 function get_timestamp($time) {
  541   $timestamp = NULL;
  542   if ($time == "-now" || $time == "now") {
  543     $timestamp = time();
  544   } else if (preg_match("/\-([0-9]*)(s)/", $time, $out)) {
  545     $timestamp = time() - $out[1];
  546   } else if (is_numeric($time)) {
  547     $timestamp = $time;
  548   } else {
  549     $t = strtotime($time);
  550     if ($t !== FALSE)
  551       $timestamp = $t;
  552     else
  553       error_log("get_timestamp: ".
  554         "Unable to convert time ${time} to Unix timestamp");
  555   }
  556   return $timestamp;
  557 }
  558 
  559 function get_nagios_events($overlay_nagios_base_url, 
  560                $host,
  561                $start,
  562                $end) {
  563   $nagios_events = array();
  564   $nagios_pull_url = 
  565     $overlay_nagios_base_url . 
  566     '/cgi-bin/api.cgi?action=host.gangliaevents' .
  567     '&host=' . urlencode($host) .
  568     '&start=' . urlencode($start) . 
  569     '&end=' . urlencode($end);
  570   $raw_nagios_events = 
  571     @file_get_contents(
  572       $nagios_pull_url,
  573       0,
  574       stream_context_create(array('http' => array('timeout' => 5), 
  575                   'https' => array('timeout' => 5))));
  576   if (strlen($raw_nagios_events) > 3) {
  577     $nagios_events = json_decode($raw_nagios_events, TRUE);
  578     // Handle any "ERROR" formatted messages and wipe resulting array.
  579     if (isset($nagios_events['response_type']) && 
  580         $nagios_events['response_type'] == 'ERROR') {
  581       $nagios_events = array();
  582     }
  583   }
  584   return $nagios_events;
  585 }
  586 
  587 function rrdgraph_cmd_add_overlay_events($command,
  588                      $graph_start,
  589                      $graph_end,
  590                      $conf_overlay_events_color_map_file,
  591                      $conf_overlay_events_shade_alpha,
  592                      $conf_overlay_events_tick_alpha,
  593                      $conf_overlay_events_line_type,
  594                      $conf_graph_colors,
  595                      $nagios_events) {
  596   $debug = FALSE;
  597 
  598   // In order not to pollute the command line with all the possible VRULEs
  599   // we need to find the time range for the graph
  600   $graph_end_timestamp = get_timestamp($graph_end);
  601   $graph_start_timestamp = get_timestamp($graph_start);
  602 
  603   if (($graph_start_timestamp == NULL) ||
  604       ($graph_end_timestamp == NULL)) {
  605     error_log("process_over_events: ".
  606           "Start/end timestamp(s) are NULL");
  607     return $command;
  608   }
  609 
  610   // Get array of events for time range
  611   $events_array = ganglia_events_get($graph_start_timestamp,
  612                      $graph_end_timestamp);
  613   
  614   if (empty($events_array))
  615     return $command;
  616   
  617   $event_color_json = file_get_contents($conf_overlay_events_color_map_file);
  618   if ($debug) 
  619     error_log("$event_color_json");
  620   $event_color_array = json_decode($event_color_json, TRUE);
  621   $initial_event_color_count = count($event_color_array);
  622   $event_color_map = array();
  623   foreach ($event_color_array as $event_color_entry) {
  624     $event_color_map[$event_color_entry['summary']] = 
  625       $event_color_entry['color'];
  626     if ($debug) 
  627       error_log("Adding event color to map: " .
  628         $event_color_entry['summary'] .
  629         ' ' .
  630         $event_color_entry['color']);
  631   }
  632 
  633   // Combine the nagios_events array, if it exists
  634   if (count($nagios_events) > 0) {
  635     // World's dumbest array merge:
  636     foreach ($nagios_events as $ne) {
  637       $events_array[] = $ne;
  638     }
  639   }
  640 
  641   foreach ($events_array as $key => $row) {
  642     $start_time[$key]  = $row['start_time'];
  643   }
  644 
  645   // Sort events in reverse chronological order
  646   array_multisort($start_time, SORT_DESC, $events_array);
  647 
  648   // Default to dashed line unless events_line_type is set to solid
  649   if ($conf_overlay_events_line_type == "solid")
  650     $overlay_events_line_type = "";
  651   else
  652     $overlay_events_line_type = ":dashes";
  653 
  654   // Preserve original rrdtool command. That's the one we'll run regex checks
  655   // against
  656   $original_command = $command;
  657 
  658   // Loop through all the events
  659   $color_count = count($conf_graph_colors);
  660   $counter = 0;
  661   $legend_items = array();
  662   foreach ($events_array as $id => $event) {
  663     $evt_start = $event['start_time'];
  664     // Make sure it's a number
  665     if (! is_numeric($evt_start)) {
  666       continue;
  667     }
  668 
  669     unset($evt_end);
  670     if (array_key_exists('end_time', $event) && 
  671     is_numeric($event['end_time'])) {
  672       $evt_end = $event['end_time'];
  673     }
  674 
  675     // If event start is less than start bail out of the loop since 
  676     // there is nothing more to do since events are sorted in reverse 
  677     // chronological order and these events are not gonna show up in 
  678     // the graph
  679     $in_graph = (($evt_start >= $graph_start_timestamp) &&
  680          ($evt_start <= $graph_end_timestamp)) ||
  681       (isset($evt_end) && 
  682        ($evt_end >= $graph_start_timestamp) && 
  683        ($evt_start <= $graph_end_timestamp));
  684     if (!$in_graph) {
  685       if ($debug)
  686     error_log("process_overlay_events: " .
  687           "Event [$evt_start] does not overlap with graph " .
  688           "[$graph_start_timestamp, $graph_end_timestamp]");
  689       continue;
  690     }
  691 
  692     // Compute the part of the event to be displayed
  693     $evt_start_in_graph_range = TRUE;
  694     if ($evt_start < $graph_start_timestamp) {
  695       $evt_start = $graph_start_timestamp;
  696       $evt_start_in_graph_range = FALSE;
  697     }
  698  
  699     $evt_end_in_graph_range = TRUE;
  700     if (isset($evt_end)) {
  701       if ($evt_end > $graph_end_timestamp) {
  702     $evt_end = $graph_end_timestamp;
  703     $evt_end_in_graph_range = FALSE;
  704       }
  705     } else
  706       $evt_end_in_graph_range = FALSE;
  707     
  708     if (preg_match("/" . $event["host_regex"] . "/", $original_command)) {
  709       if ($evt_start >= $graph_start_timestamp) {
  710     // Do we have the end timestamp. 
  711     if (!isset($graph_end_timestamp) ||
  712         ($evt_start < $graph_end_timestamp)) {
  713       // This is a potential vector since this gets added to the 
  714       // command line_width TODO: Look over sanitize
  715       $summary = 
  716         isset($event['summary']) ? sanitize($event['summary']) : "";
  717 
  718       // We need to keep track of summaries so that if we have identical
  719       // summaries e.g. Deploy we can use the same color
  720       if (array_key_exists($summary, $event_color_map)) {
  721         $color = $event_color_map[$summary];
  722         if ($debug)
  723           error_log("process_overlay_events: " .
  724             "Found existing color: $summary $color");
  725         // Reset summary to empty string if it is already present in
  726         // the legend
  727         if (array_key_exists($summary, $legend_items))
  728           $summary = "";
  729         else
  730           $legend_items[$summary] = TRUE;
  731       } else {
  732         // Haven't seen this summary before. Assign it a color
  733         $color_index = count($event_color_map) % $color_count;
  734         $color = $conf_graph_colors[$color_index];
  735         $event_color_map[$summary] = $color;
  736         $event_color_array[] = array('summary' => $summary,
  737                      'color' => $color);
  738         if ($debug)
  739           error_log("process_overlay_events: " .
  740             "Adding new event color: $summary $color");
  741       }
  742   
  743       if (isset($evt_end)) {
  744         // Attempt to draw a shaded area between start and end points.
  745         // Force solid line for ranges
  746         $overlay_events_line_type = "";
  747         
  748         $start_vrule = '';
  749         if ($evt_start_in_graph_range)
  750           $start_vrule = " VRULE:" . $evt_start .
  751         "#$color" . $conf_overlay_events_tick_alpha .
  752         ":\"" . $summary . "\"" . $overlay_events_line_type;
  753         
  754         $end_vrule = '';
  755         if ($evt_end_in_graph_range)
  756           $end_vrule = " VRULE:" . $evt_end .
  757         "#$color" . $conf_overlay_events_tick_alpha .
  758         ':""' . $overlay_events_line_type;
  759         
  760         // We need a dummpy DEF statement, because RRDtool is too stupid
  761         // to plot graphs without a DEF statement.
  762         // We can't count on a static name, so we have to "find" one.
  763         if (preg_match("/DEF:['\"]?(\w+)['\"]?=/", $command, $matches)) {
  764           // stupid rrdtool limitation.
  765           $area_cdef = 
  766         " CDEF:area_$counter=$matches[1],POP," .
  767         "TIME,$evt_start,GT,1,UNKN,IF,TIME,$evt_end,LT,1,UNKN,IF,+";
  768           $area_shade = $color . $conf_overlay_events_shade_alpha;
  769           $area = " TICK:area_$counter#$area_shade:1";
  770           if (!$evt_start_in_graph_range)
  771         $area .= ':"' . $summary . '"';
  772           $command .= "$area_cdef $area $start_vrule $end_vrule";
  773         } else {
  774           error_log("No DEF statements found in \$command?!");
  775         }
  776       } else {
  777         $command .= " VRULE:" . $evt_start . "#" . $color .
  778           ":\"" . $summary . "\"" . $overlay_events_line_type;
  779       }
  780       $counter++;
  781     } else {
  782       if ($debug)  
  783         error_log("process_overlay_events: " .
  784               "Event start [$evt_start] >= graph end " .
  785               "[$graph_end_timestamp]");
  786     }
  787       } else {
  788     if ($debug)
  789       error_log("process_overlay_events: " .
  790             "Event start [$evt_start] < graph start " .
  791             "[$graph_start_timestamp]");
  792       }
  793     } // end of if ( preg_match ...
  794     else {
  795       // error_log("Doesn't match host_regex");
  796     }
  797   } // end of foreach ( $events_array ...
  798 
  799   unset($events_array);
  800   if (count($event_color_array) > $initial_event_color_count) {
  801     $event_color_json = json_encode($event_color_array);
  802     file_put_contents($conf_overlay_events_color_map_file,
  803               $event_color_json);
  804   }
  805   return $command;
  806 }
  807 
  808 function process_graph_arguments($graph) {
  809   $graph_report = $graph;
  810   $graph_arguments = array();
  811 
  812   $pos = strpos($graph, ",");
  813   if ($pos !== FALSE) {
  814     $graph_report = substr($graph, 0, $pos);
  815     $args = str_getcsv(substr($graph, $pos + 1), ",", "'");
  816     /*
  817       ob_start();
  818       var_dump($args);
  819       $result = ob_get_clean();
  820       error_log("args = $result");
  821     */
  822     foreach ($args as $arg) {
  823       if (is_numeric($arg)) {
  824     if (ctype_digit($arg))
  825       $graph_arguments[] = intval($arg);
  826     else
  827       $graph_arguments[] = floatval($arg);
  828       } else
  829     $graph_arguments[] = $arg;
  830     }
  831   }
  832   return array($graph_report, $graph_arguments);
  833 }
  834 
  835 
  836 ##############################################################################
  837 # Build rrdtool command line
  838 ##############################################################################
  839 function rrdgraph_cmd_build($rrdtool_graph,
  840                 $vlabel,
  841                 $conf,
  842                 $graph_config,
  843                 $max,
  844                 $min,
  845                 $user_trend_range,
  846                 $user_trend_history,
  847                 $user_trend_line,
  848                 $user_clustername,
  849                 $rrd_options,
  850                 $range,
  851                 $title,
  852                 $subtitle,
  853                 $size,
  854                 $context,
  855                 $grid,
  856                 $raw_host,
  857                 $graph, 
  858                 $graph_arguments) {
  859   if (! isset($graph_config)) {
  860     $php_report_file = $conf['graphdir'] . "/" . $graph . ".php";
  861     $json_report_file = $conf['graphdir'] . "/" . $graph . ".json";
  862     
  863     if (is_file($php_report_file)) {
  864       // Check for path traversal issues by making sure real path is 
  865       // actually in graphdir
  866       if (dirname(realpath($php_report_file)) !=  $conf['graphdir']) {
  867     $rrdtool_graph['series'] = 
  868       'HRULE:1#FFCC33:"Check \$conf[graphdir] should not be relative path"';
  869       } else {
  870     $graph_function = "graph_${graph}";
  871     if ($conf['enable_pass_in_arguments_to_optional_graphs'] &&
  872         count($graph_arguments)) {
  873       $rrdtool_graph['arguments'] = $graph_arguments;
  874       // Pass by reference call, $rrdtool_graph modified inplace
  875       $graph_function($rrdtool_graph);
  876       unset($rrdtool_graph['arguments']);
  877     } else {
  878       $graph_function($rrdtool_graph);
  879     }
  880       }
  881     } else if (is_file($json_report_file )) {
  882       if (dirname(realpath($json_report_file)) !=  $conf['graphdir']) {
  883     $rrdtool_graph['series'] = 
  884       'HRULE:1#FFCC33:"Check \$conf[graphdir] should not be relative path"';
  885       } else {
  886     $graph_config = 
  887       json_decode(file_get_contents($json_report_file), TRUE );
  888     
  889     // We need to add hostname and clustername if it's not specified
  890     foreach (array_keys($graph_config['series']) as $series_id) {
  891       if (! isset($graph_config['series'][$index]['hostname'])) {
  892         $graph_config['series'][$series_id]['hostname'] = $raw_host;
  893         if (isset($grid))
  894           $graph_config['series'][$series_id]['clustername'] = $grid;
  895         else
  896           $graph_config['series'][$series_id]['clustername'] = 
  897         $user_clustername;
  898       }
  899     }
  900 
  901     $rrdtool_graph = 
  902       rrdtool_graph_merge_args_from_json($rrdtool_graph,
  903                          $graph_config,
  904                          $context,
  905                          $size,
  906                          $conf['rrds'],
  907                          $conf['graphreport_stats'],
  908                          $conf['graphreport_stat_items']);
  909       }
  910     }
  911   } else { 
  912     $rrdtool_graph = 
  913       rrdtool_graph_merge_args_from_json($rrdtool_graph,
  914                      $graph_config,
  915                      $context,
  916                      $size,
  917                      $conf['rrds'],
  918                      $conf['graphreport_stats'],
  919                      $conf['graphreport_stat_items']);
  920   }
  921   
  922   // We must have a 'series' value, or this is all for naught
  923   if (!array_key_exists('series', $rrdtool_graph) || 
  924       !strlen($rrdtool_graph['series'])) {
  925     $rrdtool_graph['series'] = 
  926       'HRULE:1#FFCC33:"Empty RRDtool command. Likely bad graph config"';
  927   }
  928   
  929   // Make small graphs (host list) cleaner by removing the too-big
  930   // legend: it is displayed above on larger cluster summary graphs.
  931   if (($size == "small" and ! isset($subtitle)) ||
  932       ($graph_config["glegend"] == "hide"))
  933     $rrdtool_graph['extras'] = isset($rrdtool_graph['extras']) ? 
  934       $rrdtool_graph['extras'] . " -g" : " -g" ;
  935 
  936   // add slope-mode if rrdtool_slope_mode is set
  937   if (isset($conf['rrdtool_slope_mode']) && 
  938       $conf['rrdtool_slope_mode'] == TRUE)
  939     $rrdtool_graph['slope-mode'] = '';
  940   
  941   if (isset($rrdtool_graph['title']) && isset($title)) {
  942     if ($conf['decorated_graph_title'])
  943       $rrdtool_graph['title'] = $title . " " . 
  944     $rrdtool_graph['title'] . 
  945     " last $range";
  946   }
  947 
  948   $command = 
  949     $conf['rrdtool'] . 
  950     " graph" . 
  951     (isset($_GET["verbose"]) ? 'v' : '') . 
  952     " - $rrd_options ";
  953 
  954   // Look ahead six months
  955   if ($user_trend_line) {
  956     // We may only want to use last x months of data since for example
  957     // if we are trending disk we may have added a disk recently which will
  958     // skew a trend line. By default we'll use 6 months however we'll let
  959     // user define this if they want to.
  960     $rrdtool_graph['start'] = "-" . $user_trend_history * 2592000 . "s";
  961     // Project the trend line this many months ahead
  962     $rrdtool_graph['end'] = "+" . $user_trend_range * 2592000 . "s";
  963   }
  964 
  965   if ($max)
  966     $rrdtool_graph['upper-limit'] = $max;
  967 
  968   if ($min)
  969     $rrdtool_graph['lower-limit'] = $min;
  970 
  971   if (isset($graph_config['percent']) && 
  972       $graph_config['percent'] == '1' ) {
  973     $rrdtool_graph['upper-limit'] = 100;
  974     $rrdtool_graph['lower-limit'] = 0;
  975   }
  976 
  977   if ($max || 
  978       $min || 
  979       (isset($graph_config['percent']) && $graph_config['percent'] == '1'))
  980     $rrdtool_graph['extras'] = isset($rrdtool_graph['extras']) ? 
  981       $rrdtool_graph['extras'] . " --rigid" : " --rigid" ;
  982 
  983   if (isset($graph_config['graph_scale'])) {
  984     // Log scale support
  985     if ($graph_config['graph_scale'] == 'log') {
  986       $rrdtool_graph['extras'] = isset($rrdtool_graph['extras']) ? 
  987     $rrdtool_graph['extras'] . " --logarithm --units=si" : 
  988     " --logarithm --units=si" ;
  989       if (!isset($rrdtool_graph['lower-limit']) || 
  990       $rrdtool_graph['lower-limit'] < 1) {
  991     // With log scale, the lower limit *has* to be 1 or greater.
  992     $rrdtool_graph['lower-limit'] = 1;
  993       }
  994     }
  995   }
  996   if ($conf['rrdtool_base_1024'] &&
  997       in_array($vlabel, array('bytes',
  998                   'Bytes',
  999                   'bytes/s',
 1000                   'Bytes/s',
 1001                   'kB',
 1002                   'MB',
 1003                   'GB',
 1004                   'bits',
 1005                   'Bits', 
 1006                   'bits/s',
 1007                   'Bits/s'))) {
 1008     // Set graph base value to 1024 
 1009     $rrdtool_graph['extras'] = isset($rrdtool_graph['extras']) ? 
 1010       $rrdtool_graph['extras'] . " --base=1024" : " --base=1024" ;
 1011   }
 1012 
 1013   // The order of the other arguments isn't important, except for the
 1014   // 'extras' and 'series' values.  These two require special handling.
 1015   // Otherwise, we just loop over them later, and tack $extras and
 1016   // $series onto the end of the command.
 1017   foreach (array_keys($rrdtool_graph) as $key) {
 1018     if (preg_match('/extras|series/', $key))
 1019       continue;
 1020 
 1021     $value = $rrdtool_graph[$key];
 1022 
 1023     if (preg_match('/\W/', $value)) {
 1024       // more than alphanumerics in value, so quote it
 1025       $value = "'$value'";
 1026     }
 1027     $command .= " --$key $value";
 1028   }
 1029   
 1030   // And finish up with the two variables that need special handling.
 1031   // See above for how these are created
 1032   $command .= array_key_exists('extras', $rrdtool_graph) ? 
 1033     ' ' . $rrdtool_graph['extras'] . ' ' : '';
 1034   $command .= " $rrdtool_graph[series]";
 1035   return array($command, $rrdtool_graph);
 1036 }
 1037 
 1038 
 1039 #############################################################################
 1040 # Output data in external non-image formats e.g. CSV, JSON etc.
 1041 #############################################################################
 1042 function output_data_to_external_format($rrdtool_graph_series,
 1043                     $rrdtool_graph_start,
 1044                     $rrdtool_graph_end,
 1045                     $rrdtool_graph_title,
 1046                     $rrdtool,
 1047                     $graphlot_output,
 1048                     $csv_output,
 1049                     $flot_output,
 1050                     $live_dashboard,
 1051                     $json_output,
 1052                     $step,
 1053                     $rrd_options) {
 1054   // First find RRDtool DEFs by parsing $rrdtool_graph['series']
 1055   preg_match_all("/([^V]DEF|CDEF):(.*)(:AVERAGE|\s)/", 
 1056          " " . $rrdtool_graph_series, 
 1057          $matches);
 1058 
 1059   $rrdtool_graph_args = "";
 1060   foreach ($matches[0] as $value) {
 1061     $rrdtool_graph_args .= $value . " ";
 1062   }
 1063 
 1064   preg_match_all("/(LINE[0-9]*|AREA|STACK):\'[^']*\'[^']*\'[^']*\'[^ ]* /",
 1065          " " . $rrdtool_graph_series, 
 1066          $matches);
 1067   foreach ($matches[0] as $value) {
 1068     if (preg_match("/(LINE[0-9]*:\'|AREA:\'|STACK:\')([^']*)(\')([^']*)(\')([^']*)(')/", $value, $out)) {
 1069       $ds_name = $out[2];
 1070       $metric_type = "line";
 1071       if (preg_match("/(STACK:|AREA:)/", $value, $ignore))
 1072     $metric_type = "stack";
 1073       $metric_name = $out[6];
 1074       $ds_attr = array("ds_name" => $ds_name,
 1075                "cluster_name" => '',
 1076                "graph_type" => $metric_type,
 1077                "host_name" => '', 
 1078                "metric_name" => $metric_name);
 1079 
 1080       // Add color if it exists
 1081       $pos_hash = strpos($out[4], '#');
 1082       if ($pos_hash !== FALSE) {
 1083     $pos_colon = strpos($out[4], ':');
 1084     if ($pos_colon !== FALSE)
 1085       $ds_attr['color'] = substr($out[4], 
 1086                      $pos_hash, 
 1087                      $pos_colon - $pos_hash); 
 1088     else
 1089       $ds_attr['color'] = substr($out[4], $pos_hash); 
 1090       }
 1091       $output_array[] = $ds_attr;
 1092       $rrdtool_graph_args .=  
 1093     " " . "XPORT:'" . $ds_name . "':'" . $metric_name . "' ";
 1094     }
 1095   }
 1096 
 1097   // This command will export values for the specified format in XML
 1098   $command = $rrdtool . 
 1099     " xport --start '" . $rrdtool_graph_start . 
 1100     "' --end '" .  $rrdtool_graph_end . "' " 
 1101     /*
 1102       Allow a custom step, if it was specified by the user. 
 1103       Also, we need to specify a --maxrows in case the number 
 1104       of rows with $step end up being higher than 
 1105       rrdxport's default (in which case the step is changed 
 1106       to fit inside the default --maxrows), but we also need 
 1107       to guard against "underflow" because rrdxport craps out 
 1108       when --maxrows is less than 10.
 1109     */
 1110     . ($step ? 
 1111        " --step '" . $step . "' --maxrows '" 
 1112        . max(10, round(($rrdtool_graph_end - 
 1113             $rrdtool_graph_start) / $step)) . "' " : "")
 1114     . $rrd_options . " " . $rrdtool_graph_args;
 1115 
 1116   // Read in the XML
 1117   $string = "";
 1118   if (strlen($command) < 100000) {
 1119     $fp = popen($command,"r"); 
 1120     while (!feof($fp)) { 
 1121       $buffer = fgets($fp, 4096);
 1122       $string .= $buffer;
 1123     }
 1124   } else {
 1125     $tempfile = tempnam("/tmp", "ganglia-graph-json");
 1126     file_put_contents($tempfile, $command);
 1127     exec("/bin/bash $tempfile", $tempout);
 1128     foreach ($tempout as $line) {
 1129       $string .= $line;
 1130     }
 1131     unlink($tempfile);
 1132   }
 1133 
 1134   // Parse it
 1135   $xml = simplexml_load_string($string);
 1136 
 1137   // If there are multiple metrics columns will be > 1
 1138   $num_of_metrics = $xml->meta->columns;
 1139 
 1140   $metric_values = array();
 1141   // Build the metric_values array
 1142 
 1143   foreach ($xml->data->row as $objects) {
 1144     $values = get_object_vars($objects);
 1145 
 1146     // If $values["v"] is an array we have multiple data sources/metrics and 
 1147     // we need to iterate over those
 1148     if (is_array($values["v"])) {
 1149       foreach ($values["v"] as $key => $value) {
 1150     $output_array[$key]["datapoints"][] = 
 1151       array(build_value_for_json($value), intval($values['t']));
 1152       }
 1153     } else {
 1154       $output_array[0]["datapoints"][] = 
 1155     array(build_value_for_json($values["v"]), intval($values['t']));
 1156     }
 1157   }
 1158 
 1159   // If JSON output request simple encode the array as JSON
 1160   if ($json_output) {
 1161     // First let's check if JSON output is requested for 
 1162     // Live Dashboard and we are outputting aggregate graph. 
 1163     // If so we need to add up all the values
 1164     if ($live_dashboard && count($output_array) > 1) {
 1165       $summed_output = array();
 1166       foreach ($output_array[0]['datapoints'] as $index => $datapoint) {
 1167     // Data point is an array with value and UNIX time stamp. Initialize
 1168     // summed output as 0
 1169     if (is_numeric($datapoint[0]) && is_numeric($datapoint[1])) {
 1170       $summed_output[$index] = array(0, $datapoint[1]);
 1171       for ($i = 0 ; $i < count($output_array) ; $i++) {
 1172         $summed_output[$index][0] += 
 1173           $output_array[$i]['datapoints'][$index][0];
 1174       }
 1175     }
 1176       }
 1177       
 1178       unset($output_array);
 1179       $output_array[0]['datapoints'] = $summed_output;
 1180     }
 1181     header("Content-type: application/json");
 1182     header("Content-Disposition: inline; filename=\"ganglia-metrics.json\"");
 1183     print json_encode($output_array);
 1184   }
 1185 
 1186   // If Flot output massage the data JSON
 1187   if ($flot_output) {
 1188     foreach ($output_array as $metric_array) {
 1189       foreach ($metric_array['datapoints'] as $values) {
 1190     $data_array[] = array ($values[1] * 1000, $values[0]);
 1191       }
 1192 
 1193       $gdata = array('label' => 
 1194              strip_domainname($metric_array['host_name']) . 
 1195              " " . 
 1196              $metric_array['metric_name'], 
 1197              'data' => $data_array);
 1198 
 1199       if (array_key_exists('color', $metric_array))
 1200     $gdata['color'] = $metric_array['color'];
 1201       
 1202       if ($metric_array['graph_type'] == "stack")
 1203     $gdata['stack'] = '1';
 1204       
 1205       $gdata['graph_title'] = $rrdtool_graph_title;
 1206       
 1207       $flot_array[] = $gdata;
 1208       
 1209       unset($data_array);
 1210     }
 1211     header("Content-type: application/json");
 1212     print json_encode($flot_array);
 1213   }
 1214 
 1215   if ($csv_output) {
 1216     header("Content-Type: application/csv");
 1217     header("Content-Disposition: inline; filename=\"ganglia-metrics.csv\"");
 1218     
 1219     print "Timestamp";
 1220 
 1221     // Print out headers
 1222     for ($i = 0 ; $i < count($output_array) ; $i++) {
 1223       print "," . $output_array[$i]["metric_name"];
 1224     }
 1225 
 1226     print "\n";
 1227     
 1228     foreach ($output_array[0]['datapoints'] as $key => $row) {
 1229       print date("c", $row[1]);
 1230       for ( $j = 0 ; $j < $num_of_metrics ; $j++ ) {
 1231     print "," . $output_array[$j]["datapoints"][$key][0];
 1232       }
 1233       print "\n";
 1234     }
 1235   }
 1236 
 1237   // Implement Graphite style Raw Data
 1238   if ($graphlot_output) {
 1239     header("Content-Type: application/json");
 1240 
 1241     $last_index = count($output_array[0]["datapoints"]) - 1;
 1242   
 1243     $output_vals['step'] = 
 1244       $output_array[0]["datapoints"][1][1] - 
 1245       $output_array[0]["datapoints"][0][1];
 1246     $output_vals['name'] = "stats." . $output_array[0]["metric_name"];
 1247     $output_vals['start'] = $output_array[0]["datapoints"][0][1];
 1248     $output_vals['end'] = $output_array[0]["datapoints"][$last_index][1];
 1249 
 1250     foreach ($output_array[0]["datapoints"] as $array) {
 1251       $output_vals['data'][] = $array[0];
 1252     } 
 1253       
 1254     print json_encode(array($output_vals, $output_vals));
 1255   }
 1256 }
 1257 
 1258 function execute_graph_command($graph_engine, $command) {
 1259   global $debug, $user;
 1260 
 1261   // always modified
 1262   header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 
 1263   header ("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
 1264   header ("Pragma: no-cache"); // HTTP/1.0
 1265   if ($debug > 2) {
 1266     header ("Content-type: text/html");
 1267     print "<html><body>";
 1268     
 1269     switch ($graph_engine) {
 1270     case "flot":
 1271     case "rrdtool":
 1272       print htmlentities($command);
 1273     break;
 1274     case "graphite":
 1275       print $command;
 1276       break;
 1277     }        
 1278     print "</body></html>";
 1279   } else {
 1280     if ( $user['image_format'] == "svg" )
 1281       header ("Content-type: image/svg+xml");
 1282     else
 1283       header ("Content-type: image/png");
 1284     switch ($graph_engine) {  
 1285     case "flot":
 1286     case "rrdtool":
 1287       if (strlen($command) < 100000) {
 1288     my_passthru($command);
 1289       } else {
 1290     $tf = tempnam("/tmp", "ganglia-graph");
 1291     file_put_contents($tf, $command);
 1292     my_passthru("/bin/bash $tf");
 1293     unlink($tf);
 1294       }
 1295     break;
 1296     case "graphite":
 1297       echo file_get_contents($command);
 1298       break;
 1299     }        
 1300   }
 1301 }
 1302 
 1303 $gweb_root = dirname(__FILE__);
 1304 
 1305 $metric_name = isset($_GET["m"]) ? sanitize($_GET["m"]) : NULL;
 1306 // In clusterview we may supply report as metric name so let's make sure it
 1307 // doesn't treat it as a metric
 1308 if ( preg_match("/_report$/", $metric_name) && !isset($_GET["g"]) ) {
 1309   $graph = $metric_name;
 1310 } else {
 1311   // If graph arg is not specified default to metric
 1312   $graph = isset($_GET["g"]) ? sanitize($_GET["g"]) : "metric";
 1313 }
 1314 
 1315 if ($conf['enable_pass_in_arguments_to_optional_graphs'])
 1316   list($graph, $graph_arguments) = process_graph_arguments($graph);
 1317 else
 1318   $graph_arguments = array();
 1319 
 1320 $grid = isset($_GET["G"]) ? sanitize( $_GET["G"]) : NULL;
 1321 $self = isset($_GET["me"]) ? sanitize( $_GET["me"]) : NULL;
 1322 $vlabel = isset($_GET["vl"]) ? sanitize($_GET["vl"])  : NULL;
 1323 $value = isset($_GET["v"]) ? sanitize ($_GET["v"]) : NULL;
 1324 // Max, min, critical and warning values
 1325 $max = isset($_GET["x"]) && is_numeric($_GET["x"]) ? $_GET["x"] : NULL;
 1326 $min = isset($_GET["n"]) && is_numeric($_GET["n"]) ? $_GET["n"] : NULL;
 1327 
 1328 $summary = isset($_GET["su"]) ? 1 : 0;
 1329 $debug = isset($_GET['debug']) ? clean_number(sanitize($_GET["debug"])) : 0;
 1330 $user['time_shift'] = isset($_GET["ts"]) ? 
 1331   clean_number(sanitize($_GET["ts"])) : 0;
 1332 
 1333 $user['json_output'] = isset($_GET["json"]) ? 1 : NULL;
 1334 // Request for live dashboard
 1335 if (isset($_REQUEST['live'])) {
 1336   $user['live_dashboard'] = 1;
 1337   $user['json_output'] = 1;
 1338 } else {
 1339   $user['live_output'] = NULL;
 1340 }
 1341 $user['csv_output'] = isset($_REQUEST["csv"]) ? 1 : NULL;
 1342 $user['graphlot_output'] = isset($_REQUEST["graphlot"]) ? 1 : NULL;
 1343 $user['flot_output'] = isset($_REQUEST["flot"]) ? 1 : NULL;
 1344 
 1345 # Check if user is asking for an alternate image format e.g. SVG
 1346 $user['image_format'] = (isset($_REQUEST["image_format"]) and $_REQUEST["image_format"] == "svg") ? "svg" : NULL;
 1347 
 1348 
 1349 $user['trend_line'] = isset($_REQUEST["trend"]) ? 1 : NULL;
 1350 // How many months ahead to extend the trend e.g. 6 months
 1351 $user['trend_range'] = 
 1352   isset($_GET["trendrange"]) && is_numeric($_GET["trendrange"]) ? 
 1353   $_GET["trendrange"] : 6;
 1354 
 1355 $user['trend_history'] = 
 1356   isset($_GET["trendhistory"]) && is_numeric($_GET["trendhistory"]) ? 
 1357   $_GET["trendhistory"] : 6;
 1358 
 1359 // Get hostname
 1360 $raw_host = isset($_GET["h"]) ? sanitize($_GET["h"]) : "__SummaryInfo__";  
 1361 
 1362 // For graphite purposes we need to replace all dots with underscore.
 1363 // dot separates subtrees in graphite
 1364 $graphite_host = str_replace(".", "_", $raw_host);
 1365 
 1366 $size = 
 1367   isset($_GET["z"]) && 
 1368   in_array($_GET['z'], $conf['graph_sizes_keys']) ? 
 1369   $_GET["z"] : 'default';
 1370 
 1371 if (isset($_GET['height']) && is_numeric($_GET['height'])) 
 1372   $height = $_GET['height'];
 1373 else 
 1374   $height  = $conf['graph_sizes'][$size]['height'];
 1375 
 1376 if (isset($_GET['width']) && is_numeric($_GET['width'])) 
 1377   $width =  $_GET['width'];
 1378 else
 1379   $width = $conf['graph_sizes'][$size]['width'];
 1380 
 1381 $fudge_0 = $conf['graph_sizes'][$size]['fudge_0'];
 1382 $fudge_1 = $conf['graph_sizes'][$size]['fudge_1'];
 1383 $fudge_2 = $conf['graph_sizes'][$size]['fudge_2'];
 1384 
 1385 ///////////////////////////////////////////////////////////////////////////
 1386 // Set some variables depending on the context. Context is set in
 1387 // get_context.php
 1388 ///////////////////////////////////////////////////////////////////////////
 1389 $rrd_dir = $conf['rrds'];
 1390 $rrd_graphite_link = $conf['graphite_rrd_dir'];
 1391 switch ($context) {
 1392 case "meta":
 1393   $rrd_dir .= "/__SummaryInfo__";
 1394   $rrd_graphite_link .= "/__SummaryInfo__";
 1395   $title = "$self ${conf['meta_designator']}";
 1396   break;
 1397 case "grid":
 1398   $rrd_dir .= "/$grid/__SummaryInfo__";
 1399   $rrd_graphite_link .= "/$grid/__SummaryInfo__";
 1400   if (preg_match('/grid/i', $gridname))
 1401     $title = $gridname;
 1402   else
 1403     $title = "$gridname ${conf['meta_designator']}";
 1404   break;
 1405 case "cluster":
 1406   $rrd_dir .= "/" . $user['clustername'] . "/__SummaryInfo__";
 1407   $rrd_graphite_link .= "/" . $user['clustername'] ."/__SummaryInfo__";
 1408   if (preg_match('/cluster/i', $user['clustername']))
 1409     $title = $user['clustername'];
 1410   else
 1411     $title = $user['clustername'] . " Cluster";
 1412   break;
 1413 case "host":
 1414   $rrd_dir .= "/" . $user['clustername'] . "/$raw_host";
 1415   $rrd_graphite_link .= "/" . $user['clustername'] . "/" . $graphite_host;
 1416   // Add hostname to report graphs' title in host view
 1417   if ($graph != 'metric')
 1418     if ($conf['strip_domainname'])
 1419       $title = strip_domainname($raw_host);
 1420     else
 1421       $title = $raw_host;
 1422   break;
 1423 default:
 1424   unset($rrd_dir);
 1425   unset($rrd_graphite_link);
 1426   break;
 1427 }
 1428 
 1429 $resource = GangliaAcl::ALL_CLUSTERS;
 1430 if ($context == "grid") {
 1431   $resource = $grid;
 1432 } else if ($context == "cluster" || $context == "host") {
 1433   $resource = $user['clustername']; 
 1434 }
 1435 
 1436 if (! checkAccess($resource, GangliaAcl::VIEW, $conf)) {
 1437   header("HTTP/1.1 403 Access Denied");
 1438   header("Content-type: image/jpg");
 1439   echo file_get_contents($gweb_root.'/img/access-denied.jpg');
 1440   die();
 1441 }
 1442 
 1443 // Aliases for $user['cs'] and $user['ce'] (which are set in get_context.php).
 1444 $cs = $user['cs'];
 1445 if ($cs and (is_numeric($cs) or strtotime($cs)))
 1446   $start = $cs;
 1447 
 1448 $ce = $user['ce'];
 1449 if ($ce and (is_numeric($ce) or strtotime($ce)))
 1450   $end = $ce;
 1451 
 1452 // Set some standard defaults that don't need to change much
 1453 $rrdtool_graph = array('start' => $start,
 1454                'end' => $end,
 1455                'width' => $width,
 1456                'height' => $height);
 1457 
 1458 // automatically strip domainname from small graphs where it won't fit
 1459 if ($size == "small")
 1460   $conf['strip_domainname'] = TRUE;
 1461 
 1462 $load_color = isset($_GET["l"]) && 
 1463   is_valid_hex_color(rawurldecode($_GET['l'])) ?
 1464   sanitize($_GET["l"]) : NULL;
 1465 if (! isset($subtitle) && $load_color)
 1466   $rrdtool_graph['color'] = "BACK#'$load_color'";
 1467 
 1468 if ($debug)
 1469   error_log("Graph [$graph] in context [$context]");
 1470 
 1471 /* 
 1472    If we have $graph, then a specific report was requested, such as 
 1473    "network_report" or "cpu_report.  These graphs usually have some 
 1474    special logic and custom handling required, instead of simply 
 1475    plotting a single metric.  If $graph is not set, then we are (hopefully),
 1476    plotting a single metric, and will use the commands in the metric.php file.
 1477 
 1478    With modular graphs, we look for a "${graph}.php" file, and if it 
 1479    exists, we source it, and call a pre-defined function name.  
 1480    The current scheme for the function names is:   'graph_' + 
 1481    <name_of_report>.  So a 'cpu_report' would call graph_cpu_report(),
 1482    which would be found in the cpu_report.php file.
 1483 
 1484    These functions take the $rrdtool_graph array as an argument.  
 1485    This variable is PASSED BY REFERENCE, and will be modified by the 
 1486    various functions.  Each key/value pair represents an option/argument, 
 1487    as passed to the rrdtool program.  Thus, $rrdtool_graph['title'] 
 1488    will refer to the --title option for rrdtool, and pass the array
 1489    value accordingly.
 1490    
 1491    There are two exceptions to:  the 'extras' and 'series' keys in 
 1492    $rrdtool_graph.  These are assigned to $extras and $series 
 1493    respectively, and are treated specially.  $series will contain
 1494    the various DEF, CDEF, RULE, LINE, AREA, etc statements that 
 1495    actually plot the charts.  The rrdtool program requires that 
 1496    this come *last* in the argument string; we make sure that it
 1497    is put in it's proper place.  The $extras variable is used 
 1498    for other arguemnts that may not fit nicely for other reasons.  
 1499    Complicated requests for --color, or adding --ridgid, for example.
 1500    It is simply a way for the graph writer to add an arbitrary 
 1501    options when calling rrdtool, and to forcibly override other 
 1502    settings, since rrdtool will use the last version of an 
 1503    option passed. (For example, if you call 'rrdtool' with 
 1504    two --title statements, the second one will be used.)
 1505    
 1506    See ${conf['graphdir']}/sample.php for more documentation, and 
 1507    details on the common variables passed and used.
 1508  */
 1509 
 1510 // Calculate time range.
 1511 $sourcetime = isset($_GET["st"]) ? clean_number(sanitize($_GET["st"])) : NULL;
 1512 if ($sourcetime) {
 1513   $end = $sourcetime;
 1514   // Get_context makes start negative.
 1515   $start = $sourcetime + $start;
 1516 }
 1517 
 1518 // Fix from Phil Radden, but step is not always 15 anymore.
 1519 if ($range == "month")
 1520   $rrdtool_graph['end'] = floor($rrdtool_graph['end'] / 672) * 672;
 1521 
 1522 ///////////////////////////////////////////////////////////////////////////////
 1523 // Are we generating aggregate graphs
 1524 ///////////////////////////////////////////////////////////////////////////////
 1525 if (isset($_GET["aggregate"]) && $_GET['aggregate'] == 1) {
 1526   // Set start time, assume that start is negative number of seconds
 1527   $start = time() + $start;
 1528 
 1529   $graph_config = build_aggregate_graph_config_from_url($conf['graph_colors']);
 1530 
 1531   // Reset graph title 
 1532   $title = (isset($_GET['title']) && $_GET['title'] != "") ? "" : "Aggregate";
 1533 }
 1534 
 1535 ///////////////////////////////////////////////////////////////////////////
 1536 // Composite graphs/reports specified in a view
 1537 ///////////////////////////////////////////////////////////////////////////
 1538 $user['view_name'] = isset($_GET["vn"]) ? sanitize ($_GET["vn"]) : NULL;
 1539 $user['item_id'] = isset($_GET["item_id"]) ? sanitize ($_GET["item_id"]) : NULL;
 1540 if ($user['view_name'] && $user['item_id']) {
 1541   list ($rrdtool_graph, $graph_config) = 
 1542     rrdtool_graph_build_view_graph($rrdtool_graph,
 1543                    $user['view_name'],
 1544                    $user['item_id'],
 1545                    $context,
 1546                    $size,
 1547                    $conf['rrds'],
 1548                    $conf['graphreport_stats'],
 1549                    $conf['graphreport_stat_items']);
 1550   # Reset title
 1551   $title ="";              
 1552 }
 1553                    
 1554 //////////////////////////////////////////////////////////////////////////////
 1555 // Build graph execution command based graph engine
 1556 //////////////////////////////////////////////////////////////////////////////
 1557 $graphite_url = '';
 1558 $command = '';
 1559 switch ($conf['graph_engine']) {
 1560   case "flot":
 1561   case "rrdtool":
 1562     // If graph is based on PHP report file then include it
 1563     // at the global scope
 1564     if (! isset($graph_config)) {
 1565       $php_report_file = $conf['graphdir'] . "/" . $graph . ".php";
 1566       if (is_file($php_report_file) &&
 1567       (dirname(realpath($php_report_file)) ==  $conf['graphdir'])) {
 1568     if (($graph == "metric") &&
 1569         isset($_GET['title']) && 
 1570         $_GET['title'] !== '')
 1571       $metrictitle = sanitize($_GET['title']);
 1572     include_once $php_report_file;
 1573       }
 1574     }
 1575 
 1576     list($command,
 1577        $rrdtool_graph) = rrdgraph_cmd_build($rrdtool_graph,
 1578                         $vlabel,
 1579                         $conf,
 1580                         $graph_config,
 1581                         $max,
 1582                         $min,
 1583                         $user['trend_range'],
 1584                         $user['trend_history'],
 1585                         $user['trend_line'],
 1586                         $user['clustername'],
 1587                         $rrd_options,
 1588                         $range,
 1589                         $title,
 1590                         $subtitle,
 1591                         $size,
 1592                         $context,
 1593                         $grid,
 1594                         $raw_host,
 1595                         $graph, 
 1596                         $graph_arguments);
 1597     break;
 1598 
 1599     case "graphite": 
 1600     $graphite_url = build_graphite_url($rrd_graphite_link,
 1601                        $rrd_dir,
 1602                        $conf,
 1603                        $user['clustername'],
 1604                        $graphite_host,
 1605                        $size,
 1606                        $height,
 1607                        $width,
 1608                        $graph_config,
 1609                        $context,
 1610                        $metric_name,
 1611                        $cs,
 1612                        $ce,
 1613                        $start,
 1614                        $end,
 1615                        $min,
 1616                        $max,
 1617                        $title,
 1618                        $range);
 1619     break;
 1620 } 
 1621 
 1622 // Output graph data to external formats
 1623 if ($user['json_output'] || 
 1624     $user['csv_output'] || 
 1625     $user['flot_output'] || 
 1626     $user['graphlot_output']) {
 1627   if ($conf['graph_engine'] == "graphite") {
 1628     if ($user['json_output'] == 1) { 
 1629       $output_format = "json"; 
 1630     } elseif ($user['csv_output'] == 1) {
 1631       $output_format = "csv"; 
 1632     }
 1633     echo file_get_contents($graphite_url . "&format=" . $output_format);
 1634   } else {
 1635     output_data_to_external_format($rrdtool_graph['series'],
 1636                    $rrdtool_graph['start'],
 1637                    $rrdtool_graph['end'],
 1638                    $rrdtool_graph['title'],
 1639                    $conf['rrdtool'],
 1640                    $user['graphlot_output'],
 1641                    $user['csv_output'],
 1642                    $user['flot_output'],
 1643                    $user['live_dashboard'],
 1644                    $user['json_output'],
 1645                    $user['step'],
 1646                    $rrd_options);
 1647   }
 1648   exit(0);
 1649 }
 1650 
 1651 //////////////////////////////////////////////////////////////////////////////
 1652 // Check whether user wants to plot overlay events on graphs
 1653 //////////////////////////////////////////////////////////////////////////////
 1654 $showEvents = isset($_GET["event"]) ? sanitize ($_GET["event"]) : "show";
 1655 if ($showEvents == "show" &&
 1656     $conf['overlay_events'] && 
 1657     $conf['graph_engine'] == "rrdtool" && 
 1658     ! in_array($range, $conf['overlay_events_exclude_ranges']) && 
 1659     ! $user['trend_line']) {
 1660   $nagios_events = array();
 1661   if ($conf['overlay_nagios_events'])
 1662     $nagios_events = get_nagios_events($conf['overlay_nagios_base_url'], 
 1663                        $raw_host,
 1664                        $start,
 1665                        $end);
 1666   $command = 
 1667     rrdgraph_cmd_add_overlay_events($command,
 1668                     $rrdtool_graph['start'],
 1669                     $rrdtool_graph['end'],
 1670                     $conf['overlay_events_color_map_file'],
 1671                     $conf['overlay_events_shade_alpha'],
 1672                     $conf['overlay_events_tick_alpha'],
 1673                     $conf['overlay_events_line_type'],
 1674                     $conf['graph_colors'],
 1675                     $nagios_events);
 1676 }
 1677 
 1678 ////////////////////////////////////////////////////////////////////////////////
 1679 // Add a trend line
 1680 ////////////////////////////////////////////////////////////////////////////////
 1681 if ($user['trend_line']) {
 1682   $command .= " VDEF:D2=sum,LSLSLOPE VDEF:H2=sum,LSLINT CDEF:avg2=sum,POP,D2,COUNT,*,H2,+";
 1683   $command .= " 'LINE3:avg2" . $conf['trend_line_color'] . ":Trend:dashes'";
 1684 }
 1685 
 1686 ////////////////////////////////////////////////////////////////////////////////
 1687 // Timeshift is only available to metric graphs
 1688 ////////////////////////////////////////////////////////////////////////////////
 1689 if ($user['time_shift'] && $graph == "metric") {
 1690   preg_match_all("/(DEF|CDEF):((([^ \"'])+)|(\"[^\"]*\")|('[^']*'))+/", 
 1691                  " " . $rrdtool_graph['series'], 
 1692                  $matches);
 1693 
 1694   // Only do this for metric graphs
 1695   $start = intval(abs(str_replace("s", "", $rrdtool_graph['start'])));
 1696   $offset = 2 * $start;
 1697   
 1698   $def = str_replace("DEF:'sum'", "DEF:'sum2'", trim($matches[0][0])) . 
 1699     ":start=end-" . $offset;
 1700   
 1701   $command .= " " . $def . " SHIFT:sum2:" . $start;
 1702   $command .= " 'LINE2:sum2" . $conf['timeshift_line_color'] . 
 1703     ":Previous " . $range . ":dashes'";
 1704 }
 1705 
 1706 ////////////////////////////////////////////////////////////////////////////////
 1707 // Add warning and critical lines
 1708 ////////////////////////////////////////////////////////////////////////////////
 1709 $warning = isset($_GET["warn"]) && is_numeric($_GET["warn"]) ? 
 1710   $_GET["warn"] : NULL;
 1711 if ($warning) {
 1712   $command .= " 'HRULE:" . $warning . "#FFF600:Warning:dashes'";  
 1713 }
 1714 
 1715 $critical = isset($_GET["crit"]) && is_numeric($_GET["crit"]) ? 
 1716   $_GET["crit"] : NULL;
 1717 if ($critical) {
 1718   $command .= " 'HRULE:" . $critical . "#FF0000:Critical:dashes'";
 1719 }
 1720 
 1721 ////////////////////////////////////////////////////////////////////////////////
 1722 // Turn on SVG rendering
 1723 ////////////////////////////////////////////////////////////////////////////////
 1724 if ( $user['image_format'] == "svg" )
 1725   $command .= " -a SVG";
 1726 
 1727 
 1728 if ($debug) {
 1729   error_log("Final rrdtool command:  $command");
 1730 }
 1731 
 1732 # Did we generate a command? Run it.
 1733 if ($command || $graphite_url)
 1734   execute_graph_command($conf['graph_engine'],
 1735             ($conf['graph_engine'] == "graphite") ? 
 1736             $graphite_url : $command);
 1737 
 1738 ?>