2025-08-06 18:11:51 +02:00

1246 lines
42 KiB
PHP

<?php
// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
// phpcs:disable PSR1.Files.SideEffects
defined('SYSPATH') or die('No direct access allowed.');
// phpcs:enable PSR1.Files.SideEffects
// phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
/**
* Retrieves and manipulates current status of hosts (and services?)
*/
class Data_Model extends System_Model
{
private $XML = [];
public $DS = [];
public $MACRO = [];
private $RRD = [];
public $STRUCT = [];
public $TIMERANGE = [];
public $PAGE_DEF = [];
public $PAGE_GRAPH = [];
public $XPORT = '';
public $TEMPLATE_FILE = '';
public $GRAPH_TYPE = 'normal';
public $config = '';
public $auth = '';
public function __construct()
{
$this->config = new Config_Model();
$this->config->read_config();
$this->auth = new Auth_Model();
}
//end __construct()
/*
* Get All Special Templates
*
*/
public function getSpecialTemplates()
{
$conf = $this->config->conf;
$templates = [];
if (is_dir($conf['special_template_dir'])) {
if ($dh = opendir($conf['special_template_dir'])) {
while (($file = readdir($dh)) !== false) {
if ($file == '.' || $file == '..') {
continue;
}
if (!preg_match('/(.*)\.php$/', $file, $template)) {
continue;
}
$templates[] = $template[1];
}
}
}
if (empty($templates)) {
return false;
} else {
sort($templates);
return $templates;
}
}
//end getSpecialTemplates()
public function getFirstSpecialTemplate()
{
$templates = $this->getSpecialTemplates();
if ($templates === false) {
return false;
} else {
return $templates[0];
}
}
//end getFirstSpecialTemplate()
public function getHosts()
{
$hosts = [];
$conf = $this->config->conf;
$i = 0;
if (is_dir($conf['rrdbase'])) {
if ($dh = opendir($conf['rrdbase'])) {
while (($file = readdir($dh)) !== false) {
if ($file == '.' || $file == '..' || $file == '.pnp-internal') {
continue;
}
if (is_file($conf['rrdbase'] . '/' . $file)) {
continue;
}
if ($this->auth->is_authorized($file) === false) {
continue;
}
$stat = stat($conf['rrdbase'] . '/' . $file);
$age = (time() - $stat['mtime']);
$hosts[$i]['name'] = $file;
$hosts[$i]['sort'] = strtoupper($file);
if ($age < $conf['max_age']) {
$hosts[$i]['state'] = 'active';
} else {
$hosts[$i]['state'] = 'inactive';
}
$i++;
}
//end while
closedir($dh);
} else {
throw new Kohana_User_Exception('Perfdata Dir', "Can not open $path");
}
//end if
}
//end if
if (empty($hosts)) {
throw new Kohana_Exception('error.perfdata-dir-empty', $conf['rrdbase']);
} else {
// Obtain a list of columns
foreach ($hosts as $key => $row) {
$sort[$key] = $row['sort'];
}
// Sort the data with volume descending, edition ascending
// Add $data as the last parameter, to sort by the common key
array_multisort($sort, SORT_ASC, $hosts);
}
return $hosts;
}
//end getHosts()
private function getRawServices($hostname)
{
$services = [];
$host = [];
$conf = $this->config->conf;
$i = 0;
$path = $conf['rrdbase'] . $hostname;
if (is_dir($path)) {
if ($dh = opendir($path)) {
while (($file = readdir($dh) ) !== false) {
if ($file == '.' || $file == '..') {
continue;
}
if (!preg_match('/(.*)\.xml$/', $file, $servicedesc)) {
continue;
}
$fullpath = $path . '/' . $file;
$stat = stat("$fullpath");
$age = (time() - $stat['mtime']);
$state = 'active';
if ($age > $conf['max_age']) {
// 6Stunden
$state = 'inactive';
}
$services[$i]['state'] = $state;
$services[$i]['name'] = $servicedesc[1];
$i++;
}
//end while
}
//end if
} else {
throw new Kohana_Exception('error.perfdata-dir-for-host', $path, $hostname);
}
//end if
if (is_array($services) && (!empty($services))) {
// Obtain a list of columns
foreach ($services as $key => $row) {
$sort[$key] = $row['name'];
}
// Sort the data with volume descending, edition ascending
// Add $data as the last parameter, to sort by the common key
array_multisort($sort, SORT_STRING, $services);
} else {
throw new Kohana_Exception('error.host-perfdata-dir-empty', $path, $hostname);
}
return $services;
}
//end getRawServices()
public function getServices($hostname)
{
$services = [];
$host = [];
$i = 0;
$service_list = $this->getRawServices($hostname);
foreach ($service_list as $s) {
if (!$this->readXML($hostname, $s['name'], false)) {
continue;
}
if ($s['name'] == '_HOST_') {
// Check authorization
if ($this->auth->is_authorized((string) $this->XML->NAGIOS_AUTH_HOSTNAME, '_HOST_') === false) {
continue;
}
$host[0]['name'] = '_HOST_';
$host[0]['hostname'] = (string) $this->XML->NAGIOS_HOSTNAME;
$host[0]['state'] = $s['state'];
$host[0]['servicedesc'] = 'Host Perfdata';
$host[0]['is_multi'] = (string) $this->XML->DATASOURCE[0]->IS_MULTI[0];
} else {
// Check authorization
if ($this->auth->is_authorized((string) $this->XML->NAGIOS_AUTH_HOSTNAME, (string) $this->XML->NAGIOS_AUTH_SERVICEDESC) === false) {
continue;
}
$services[$i]['name'] = $s['name'];
// Sorting check_multi
if ((string) $this->XML->NAGIOS_MULTI_PARENT == '') {
$services[$i]['sort'] = strtoupper($s['name']);
} else {
$services[$i]['sort'] = strtoupper((string) $this->XML->NAGIOS_MULTI_PARENT);
$services[$i]['sort'] .= (string) $this->XML->DATASOURCE[0]->IS_MULTI[0];
$services[$i]['sort'] .= strtoupper($s['name']);
}
$services[$i]['state'] = $s['state'];
$services[$i]['hostname'] = (string) $this->XML->NAGIOS_DISP_HOSTNAME;
$services[$i]['servicedesc'] = (string) $this->XML->NAGIOS_DISP_SERVICEDESC;
$services[$i]['is_multi'] = (string) $this->XML->DATASOURCE[0]->IS_MULTI[0];
}
//end if
$i++;
}
//end foreach
// print Kohana::debug($services);
if (is_array($services) && (!empty($services))) {
// Obtain a list of columns
foreach ($services as $key => $row) {
$sort[$key] = $row['sort'];
}
// Sort the data with volume descending, edition ascending
// Add $data as the last parameter, to sort by the common key
array_multisort($sort, SORT_STRING, $services);
}
if (is_array($host) && (!empty($host))) {
array_unshift($services, $host[0]);
}
return $services;
}
//end getServices()
public function getFirstService($hostname)
{
$conf = $this->config->conf;
$services = $this->getServices($hostname);
foreach ($services as $srv) {
if ($srv['state'] == 'active') {
break;
}
}
if (empty($srv)) {
throw new Kohana_Exception('error.get-first-service', $hostname);
}
return $srv['name'];
}
//end getFirstService()
public function getFirstHost()
{
$conf = $this->config->conf;
$hosts = $this->getHosts();
foreach ($hosts as $host) {
if ($host['state'] == 'active') {
break;
}
}
if (empty($host)) {
throw new Kohana_Exception('error.get-first-host');
}
return $host['name'];
}
//end getFirstHost()
public function readXML($hostname, $servicedesc, $throw_exception = true)
{
$conf = $this->config->conf;
$xmlfile = $conf['rrdbase'] . $hostname . '/' . $servicedesc . '.xml';
$xml = [];
if (file_exists($xmlfile)) {
libxml_use_internal_errors(true);
libxml_clear_errors();
if (! $xml = simplexml_load_file($xmlfile)) {
;
if ($throw_exception == true) {
$errors = '<br>';
foreach (libxml_get_errors() as $error) {
$errors .= $error->message . '<br>';
}
throw new Kohana_Exception('error.xml-generic_error', $xmlfile, $errors);
} else {
return false;
}
}
$this->XML = [];
$this->MACRO = [];
$this->MACRO['AUTH_SERVICEDESC'] = '';
$this->MACRO['AUTH_HOSTNAME'] = '';
$this->DS = [];
// Throw excaption without a valid structure version
if (!isset($xml->XML->VERSION) && $throw_exception == true) {
throw new Kohana_Exception('error.xml-structure-without-version-tag', $xmlfile);
}
if (!isset($xml->XML->VERSION) && $throw_exception == false) {
return false;
}
foreach ($xml as $key => $val) {
if (preg_match('/^NAGIOS_(.*)$/', $key, $match)) {
// print $match[1]." => ".$val."\n";
$key = $match[1];
$this->MACRO[$key] = (string) $val;
}
}
$i = 0;
foreach ($xml->DATASOURCE as $datasource) {
foreach ($datasource as $key => $val) {
// print "$key => $val\n";
// $$key[$i] = (string) $val;
$this->DS[$i][$key] = (string) $val;
}
$i++;
}
$this->XML = $xml;
return true;
} else {
throw new Kohana_Exception('error.xml-not-found', $xmlfile);
}
//end if
}
//end readXML()
public function buildDataStruct($host = false, $service = false, $view = null, $source = null)
{
if ($host === false && $service === false) {
return false;
}
$conf = $this->config->conf;
/*
* Special templates without Host/Service
*/
if ($host == '__special') {
// $service contains the template name
$this->includeTemplate($service, 'special');
} else {
if ($this->readXML($host, $service) == false) {
throw new Kohana_Exception('error.xml-not-found', 'Undefined error');
return false;
}
$this->includeTemplate($this->DS[0]['TEMPLATE']);
}
if (isset($this->TIMERANGE['type']) && $this->TIMERANGE['type'] == 'start-end') {
$view = intval($view);
$i = 0;
foreach ($this->RRD['def'] as $key => $val) {
if (! is_null($source) && $source != $key) {
continue;
}
$tmp_struct = [];
$tmp_struct['LEVEL'] = $i;
$tmp_struct['VIEW'] = $view;
$tmp_struct['TEMPLATE_FILE'] = $this->TEMPLATE_FILE;
;
$tmp_struct['SOURCE'] = $key;
$tmp_struct['RRD_CALL'] = $this->TIMERANGE['cmd'] . ' ' . $this->RRD['opt'][$key] . ' ' . $this->RRD['def'][$key];
$tmp_struct['TIMERANGE'] = $this->TIMERANGE;
$tmp_struct['GRAPH_WIDTH'] = $this->getGraphDimensions('width', $tmp_struct['RRD_CALL']);
$tmp_struct['GRAPH_HEIGHT'] = $this->getGraphDimensions('height', $tmp_struct['RRD_CALL']);
if (isset($this->RRD['ds_name'][$key])) {
$tmp_struct['ds_name'] = $this->RRD['ds_name'][$key];
} elseif (array_key_exists($i, $this->DS)) {
$tmp_struct['ds_name'] = $this->DS[$i]['NAME'];
} else {
$tmp_struct['ds_name'] = 'UNDEF';
}
$tmp_struct['MACRO'] = $this->MACRO;
if (isset($this->XML->XML->VERSION)) {
$tmp_struct['VERSION'] = pnp::xml_version_check((string) $this->XML->XML->VERSION);
} else {
$tmp_struct['VERSION'] = pnp::xml_version_check('0');
}
$this->addToDataStruct($tmp_struct);
$i++;
}
//end foreach
return;
}
//end if
if ($view === '') {
$v = 0;
foreach ($this->config->views as $view_key => $view_val) {
$i = 0;
foreach ($this->RRD['def'] as $key => $val) {
if (! is_null($source) && $source != $key) {
continue;
}
$tmp_struct = [];
$tmp_struct['LEVEL'] = $i;
$tmp_struct['VIEW'] = $view_key;
$tmp_struct['TEMPLATE_FILE'] = $this->TEMPLATE_FILE;
;
$tmp_struct['SOURCE'] = $key;
$tmp_struct['RRD_CALL'] = $this->TIMERANGE[$v]['cmd'] . ' ' . $this->RRD['opt'][$key] . ' ' . $this->RRD['def'][$key];
$tmp_struct['GRAPH_WIDTH'] = $this->getGraphDimensions('width', $tmp_struct['RRD_CALL']);
$tmp_struct['GRAPH_HEIGHT'] = $this->getGraphDimensions('height', $tmp_struct['RRD_CALL']);
if (isset($this->RRD['ds_name'][$key])) {
$tmp_struct['ds_name'] = $this->RRD['ds_name'][$key];
} elseif (array_key_exists($i, $this->DS)) {
$tmp_struct['ds_name'] = $this->DS[$i]['NAME'];
} else {
$tmp_struct['ds_name'] = 'UNDEF';
}
$tmp_struct['TIMERANGE'] = $this->TIMERANGE[$v];
$tmp_struct['MACRO'] = $this->MACRO;
if (isset($this->XML->XML->VERSION)) {
$tmp_struct['VERSION'] = pnp::xml_version_check((string) $this->XML->XML->VERSION);
} else {
$tmp_struct['VERSION'] = pnp::xml_version_check('0');
}
$this->addToDataStruct($tmp_struct);
$i++;
}
//end foreach
$v++;
}
//end foreach
} else {
$view = intval($view);
$i = 0;
foreach ($this->RRD['def'] as $key => $val) {
if (! is_null($source) && $source != $key) {
continue;
}
$tmp_struct = [];
$tmp_struct['LEVEL'] = $i;
$tmp_struct['VIEW'] = $view;
$tmp_struct['TEMPLATE_FILE'] = $this->TEMPLATE_FILE;
;
$tmp_struct['SOURCE'] = $key;
$tmp_struct['RRD_CALL'] = $this->TIMERANGE[$view]['cmd'] . ' ' . $this->RRD['opt'][$key] . ' ' . $this->RRD['def'][$key];
$tmp_struct['TIMERANGE'] = $this->TIMERANGE[$view];
$tmp_struct['GRAPH_WIDTH'] = $this->getGraphDimensions('width', $tmp_struct['RRD_CALL']);
$tmp_struct['GRAPH_HEIGHT'] = $this->getGraphDimensions('height', $tmp_struct['RRD_CALL']);
if (isset($this->RRD['ds_name'][$key])) {
$tmp_struct['ds_name'] = $this->RRD['ds_name'][$key];
} elseif (array_key_exists($i, $this->DS)) {
$tmp_struct['ds_name'] = $this->DS[$i]['NAME'];
} else {
$tmp_struct['ds_name'] = 'UNDEF';
}
$tmp_struct['MACRO'] = $this->MACRO;
if (isset($this->XML->XML->VERSION)) {
$tmp_struct['VERSION'] = pnp::xml_version_check((string) $this->XML->XML->VERSION);
} else {
$tmp_struct['VERSION'] = pnp::xml_version_check('0');
}
$this->addToDataStruct($tmp_struct);
$i++;
}
//end foreach
}
//end if
}
//end buildDataStruct()
private function addToDataStruct($data = false)
{
if ($data === false) {
return false;
}
array_push($this->STRUCT, $data);
}
//end addToDataStruct()
private function includeTemplate($template = false, $type = 'normal')
{
if ($template === false) {
return false;
}
$this->RRD = [];
/*
* Normal PNP Templates
*/
if ($type == 'normal') {
$template_file = $this->findTemplate($template);
$this->TEMPLATE_FILE = $template_file;
$hostname = $this->MACRO['HOSTNAME'];
$servicedesc = $this->MACRO['SERVICEDESC'];
$TIMERANGE = $this->TIMERANGE;
} elseif ($type == 'special') {
$template_file = $this->findTemplate($template, $type);
$TIMERANGE = $this->TIMERANGE;
}
$def = false;
$opt = false;
$ds_name = false;
/*
* 0.4.x Template compatibility
*/
foreach ($this->DS as $key => $val) {
$key++;
foreach (array_keys($val) as $tag) {
${$tag}[$key] = $val[$tag];
}
}
foreach ($this->MACRO as $key => $val) {
${'NAGIOS_' . $key} = $val;
}
if (isset($RRDFILE[1])) {
$rrdfile = $RRDFILE[1];
}
// Include template
if ($template_file == false) {
throw new Kohana_Exception('error.no-templates-found');
} else {
ob_start();
include $template_file;
ob_end_clean();
}
// Compatibility for very old Templates
if (!is_array($def) && $def != false) {
$tmp[1] = $def;
$def = $tmp;
}
if (!is_array($opt) && $opt != false) {
$tmp[1] = $opt;
$opt = $tmp;
}
if (!is_array($ds_name) && $ds_name != false) {
$tmp[1] = $ds_name;
$ds_name = $tmp;
}
if ($def != false) {
$this->RRD['def'] = $this->array_reindex($def);
} else {
throw new Kohana_Exception('error.template-without-def', $template_file);
}
if ($opt != false) {
$this->RRD['opt'] = $this->array_reindex($opt);
} else {
throw new Kohana_Exception('error.template-without-opt', $template_file);
}
if ($ds_name != false) {
$this->RRD['ds_name'] = $this->array_reindex($ds_name);
}
return true;
}
//end includeTemplate()
private function getGraphDimensions($search, $command)
{
if ($search == 'width') {
if (preg_match_all('/(-w|--width|--width=)\s([0-9]+)\s/i', $command, $match)) {
$value = array_pop($match[2]);
return $value;
} else {
return $this->config->conf['graph_width'];
}
}
if ($search == 'height') {
if (preg_match_all('/(-h|--height|--height=)\s([0-9]+)\s/i', $command, $match)) {
$value = array_pop($match[2]);
return $value;
} else {
return $this->config->conf['graph_height'];
}
}
return false;
}
//end getGraphDimensions()
private function array_reindex($data)
{
$i = 0;
foreach ($data as $d) {
$tmp[$i] = $d;
$i++;
}
return $tmp;
}
//end array_reindex()
public function findTemplate($template, $type = 'normal')
{
$conf = $this->config->conf;
/*
* Normal templates
*/
if ($type == 'normal') {
// Build a list of directories to search for templates
$template_dirs = [];
if (array_key_exists('template_dirs', $this->config->conf)) {
foreach ($this->config->conf['template_dirs'] as $dir) {
$template_dirs[] = $dir;
}
}
foreach (Kohana::config('core.template_dirs') as $dir) {
$template_dirs[] = $dir;
}
// throw new Kohana_Exception(print_r($template_dirs,TRUE));
foreach ($template_dirs as $dir) {
$match = $this->findRecursiveTemplate($template, $dir);
if ($match != false) {
return $match;
}
}
/*
* Fallback to default templates
*/
foreach ($template_dirs as $dir) {
$match = $this->findRecursiveTemplate('default', $dir);
if ($match != false) {
return $match;
}
}
return false;
}
//end if
/*
* Special Templates
*/
if ($type == 'special') {
if (is_readable($conf['special_template_dir'] . '/' . $template . '.php')) {
$template_file = $conf['special_template_dir'] . '/' . $template . '.php';
} else {
throw new Kohana_Exception("Special Template '$template' not found");
}
return $template_file;
}
}
//end findTemplate()
private function findRecursiveTemplate($template, $dir)
{
if (!is_readable($dir)) {
return false;
}
$template_file = '';
$r_template_file = '';
$r_template = '';
$recursive = explode('_', $template);
if ($this->config->conf['enable_recursive_template_search'] == 1) {
$i = 0;
foreach ($recursive as $value) {
if ($i == 0) {
$r_template = $value;
} else {
$r_template = $r_template . '_' . $value;
}
$file = $dir . '/' . $r_template . '.php';
if (is_readable($file)) {
$r_template_file = $file;
}
$i++;
}
if ($r_template_file != '') {
return $r_template_file;
} else {
return false;
}
} else {
$file = $dir . '/' . $template . '.php';
if (is_readable($file)) {
return $file;
} else {
return false;
}
}
//end if
}
//end findRecursiveTemplate()
public function getTimeRange($start = false, $end = false, $view = '')
{
if ($end != false) {
// we are in a custom timerange
if (!is_numeric($end)) {
$timestamp = strtotime($end);
if (!$timestamp) {
throw new Kohana_User_Exception('Wrong Format', "End -> $end");
} else {
$end = $timestamp;
}
}
} else {
$end = time();
}
if ($start != false) {
// we are in a custom timerange
if (!is_numeric($start)) {
$timestamp = strtotime($start);
if (!$timestamp) {
throw new Kohana_User_Exception('Wrong Format', "Start -> $start");
} else {
$start = $timestamp;
}
}
}
if ($start && $end) {
$timerange['title'] = Kohana::lang('common.timerange-selector-link');
$timerange['start'] = $start;
$timerange['f_start'] = date($this->config->conf['date_fmt'], $start);
$timerange['end'] = $end;
$timerange['f_end'] = date($this->config->conf['date_fmt'], $end);
$timerange['cmd'] = $this->buildViewCmd(false, $start, $end);
$timerange['type'] = 'start-end';
$this->TIMERANGE = $timerange;
return;
}
$view = intval(pnp::clean($view));
if ($view >= count($this->config->views)) {
$view = 1;
}
if (!$end) {
$end = time();
} elseif (!is_numeric($end)) {
$timestamp = strtotime($end);
if (!$timestamp) {
throw new Kohana_User_Exception('Wrong Format', "$end");
} else {
$end = $timestamp;
}
} else {
$end = $end;
}
if (!$start) {
$start = ( $end - $this->config->views[$view]['start']);
} elseif (!is_numeric($start)) {
$timestamp = strtotime($start);
if (!$timestamp) {
throw new Kohana_User_Exception('Wrong Format', "$start");
} else {
$start = $timestamp;
}
} else {
$start = pnp::clean($start);
}
if ($start >= $end) {
// Fixme i18n
throw new Kohana_User_Exception('Wrong Timerange', 'start >= end');
}
$timerange['title'] = $this->config->views[$view]['title'];
$timerange['start'] = $start;
$timerange['f_start'] = date($this->config->conf['date_fmt'], $start);
$timerange['end'] = $end;
$timerange['f_end'] = date($this->config->conf['date_fmt'], $end);
$timerange['cmd'] = $this->buildViewCmd($view, $start, $end);
$timerange['type'] = 'views';
for ($i = 0; $i < count($this->config->views); $i++) {
$timerange[$i]['title'] = $this->config->views[$i]['title'];
$timerange[$i]['start'] = ($end - $this->config->views[$i]['start']);
$timerange[$i]['f_start'] = date($this->config->conf['date_fmt'], ($end - $this->config->views[$i]['start']));
$timerange[$i]['end'] = $end;
$timerange[$i]['f_end'] = date($this->config->conf['date_fmt'], $end);
$timerange[$i]['cmd'] = $this->buildViewCmd($i, ($end - $this->config->views[$i]['start']), $end);
$timerange[$i]['type'] = 'views';
}
$this->TIMERANGE = $timerange;
}
//end getTimeRange()
public function buildViewCmd($view = false, $start = false, $end = false)
{
// abstract creation of RRDtool options string, so we can add more features to a view;
// implemented in this file by replacing cmd builds containing '--start'
if ($view !== false && !array_key_exists($view, $this->config->views)) {
$view = 1;
}
$view = $this->config->views[$view];
$cmd = '';
if ($start !== false) {
$cmd .= " --start $start";
} elseif (array_key_exists('start', $view)) {
$cmd .= (' --start ' . $view['start']);
}
if ($end !== false) {
$cmd .= " --end $end";
} elseif (array_key_exists('end', $view)) {
$cmd .= (' --end ' . $view['end']);
}
if (array_key_exists('extra_args', $view)) {
$cmd .= (' ' . $view['extra_args']);
}
return "$cmd ";
}
//end buildViewCmd()
public function buildBasketStruct($basket, $view = null)
{
if (is_array($basket) && (!empty($basket))) {
if ($view == '') {
$views = array_keys($this->config->views);
} else {
$views = [$view];
}
foreach ($views as $view) {
foreach ($basket as $item) {
// explode host::service::source
$slices = explode('::', $item);
if (count($slices) == 2) {
$this->buildDataStruct($slices[0], $slices[1], $view);
}
if (count($slices) == 3) {
$this->buildDataStruct($slices[0], $slices[1], $view, $slices[2]);
}
}
// break on custom time ranges
if (isset($this->TIMERANGE['type']) && $this->TIMERANGE['type'] == 'start-end') {
break;
}
}
}
//end if
}
//end buildBasketStruct()
public function buildPageStruct($page, $view)
{
$servicelist = [];
$this->parse_page_cfg($page);
$hosts = $this->getHostsByPage();
// No regex so we keep the order defined by config
if ($this->PAGE_DEF['use_regex'] == 0) {
// Loop through graph definitions
foreach ($this->PAGE_GRAPH as $graph) {
$hosts_to_search_for = explode(',', $graph['host_name']);
foreach ($hosts_to_search_for as $host) {
if (in_array($host, $hosts)) {
$services = $this->getServices($host);
foreach ($services as $service) {
// search for definition
$data = $this->filterServiceByPage($graph, $host, $service);
if ($data) {
$servicelist[] = [
'host' => $host,
'service' => $service['name'],
'source' => $data['source'],
];
}
}
}
}
}
} else {
foreach ($hosts as $host) {
$services = $this->getServices($host);
foreach ($services as $service) {
// search for definition
$data = $this->filterServiceByPage($this->PAGE_GRAPH, $host, $service);
if ($data) {
$servicelist[] = [
'host' => $host,
'service' => $service['name'],
'source' => $data['source'],
];
}
}
}
}
//end if
// print Kohana::debug($servicelist);
if (empty($servicelist)) {
$this->ERROR = 'ERROR: ' . Kohana::lang('error.no-data-for-page', $page . '.cfg');
} else {
foreach ($servicelist as $s) {
$this->buildDataStruct($s['host'], $s['service'], $view, $s['source']);
}
}
}
//end buildPageStruct()
public function parse_page_cfg($page)
{
$page_cfg = $this->config->conf['page_dir'] . $page . '.cfg';
if (is_readable($page_cfg)) {
$data = file($page_cfg);
} else {
throw new Kohana_Exception('error.page-not-readable', $page . '.cfg');
}
$l = 0;
$line = '';
$tag = '';
$inside = 0;
$this->PAGE_DEF['page_name'] = 'UNDEF';
$this->PAGE_DEF['use_regex'] = 0;
$this->PAGE_GRAPH = [];
$allowed_tags = [
'page',
'graph',
];
foreach ($data as $line) {
if (preg_match('/(^#|^;)/', $line)) {
continue;
}
preg_match('/define\s+(\w+)\W+{/', $line, $tag);
if (isset($tag[1]) && in_array($tag[1], $allowed_tags)) {
$inside = 1;
$t = $tag[1];
$l++;
continue;
}
if (preg_match('/\s?(\w+)\s+([^#]+)(#.*)?$/', $line, $key) && $inside == 1) {
$k = strtolower($key[1]);
$v = $key[2];
if ($t == 'page') {
$this->PAGE_DEF[$k] = trim($v);
} elseif ($t == 'graph') {
$this->PAGE_GRAPH[$l][$k] = trim($v);
}
}
if (preg_match('/}/', $line)) {
$inside = 0;
$t = '';
continue;
}
}
//end foreach
}
//end parse_page_cfg()
public function getHostsByPage()
{
$hosts = $this->getHosts();
$new_hosts = [];
foreach ($hosts as $host) {
if ($host['state'] == 'inactive') {
continue;
}
if ($tmp = $this->filterHostByPage($host['name'])) {
$new_hosts[] = $tmp;
}
}
return $new_hosts;
}
//end getHostsByPage()
private function filterHostByPage($host)
{
if (isset($this->PAGE_DEF['use_regex']) && $this->PAGE_DEF['use_regex'] == 1) {
// Search Host by regex
foreach ($this->PAGE_GRAPH as $g) {
if (isset($g['host_name']) && preg_match('/' . $g['host_name'] . '/', $host)) {
return $host;
}
}
} else {
foreach ($this->PAGE_GRAPH as $g) {
$hosts_to_search_for = explode(',', $g['host_name']);
if (isset($g['host_name']) && in_array($host, $hosts_to_search_for)) {
return $host;
}
}
}
return false;
}
//end filterHostByPage()
private function filterServiceByPage($g, $host, $service)
{
$data = [];
if (isset($this->PAGE_DEF['use_regex']) && $this->PAGE_DEF['use_regex'] == 1) {
// Search Host by regex
foreach ($this->PAGE_GRAPH as $g) {
if (isset($g['host_name']) && preg_match('/' . $g['host_name'] . '/', $host)) {
if (isset($g['service_desc']) && preg_match('/' . $g['service_desc'] . '/', $service['name'])) {
$data['service_desc'] = $g['service_desc'];
$data['host_name'] = $g['host_name'];
$data['source'] = null;
// if we only want a single image
if (isset($g['source'])) {
$this->readXML($host, $service['name']);
$this->includeTemplate($this->DS[0]['TEMPLATE']);
$source = intval($g['source']);
if (array_key_exists($source, $this->RRD['def'])) {
$data['source'] = $source;
}
}
return $data;
}
}
}
} else {
$hosts_to_search_for = explode(',', $g['host_name']);
$services_to_search_for = explode(',', $g['service_desc']);
if (isset($g['host_name']) && in_array($host, $hosts_to_search_for)) {
if (isset($g['service_desc']) && in_array($service['name'], $services_to_search_for)) {
$data['service_desc'] = $g['service_desc'];
$data['host_name'] = $g['host_name'];
$data['source'] = null;
// if we only want a single image
if (isset($g['source'])) {
$this->readXML($host, $service['name']);
$this->includeTemplate($this->DS[0]['TEMPLATE']);
$source = intval($g['source']);
if (array_key_exists($source, $this->RRD['def'])) {
$data['source'] = $source;
}
}
return $data;
}
}
}
//end if
return false;
}
//end filterServiceByPage()
public function getPages()
{
$pages = [];
if (is_dir($this->config->conf['page_dir'])) {
if ($dh = opendir($this->config->conf['page_dir'])) {
while (($file = readdir($dh)) !== false) {
if (preg_match('/(.*)\.cfg$/', basename($file), $page)) {
$pages[] = urlencode($page[1]);
}
}
closedir($dh);
} else {
die("Cannot open directory: $path");
}
}
if (empty($pages)) {
return false;
} else {
natsort($pages);
}
return $pages;
}
//end getPages()
public function getFirstPage()
{
$pages = $this->getPages();
if (empty($pages)) {
return false;
} else {
return urldecode($pages[0]);
}
}
//end getFirstPage()
public function getPageDetails($page)
{
$this->parse_page_cfg($page);
return $this->PAGE_DEF['page_name'];
}
//end getPageDetails()
public function buildXport($host, $service)
{
// FIXME add max rows to config
$this->XPORT = ' -m 2000';
$this->XPORT .= $this->buildViewCmd(false, $this->TIMERANGE['start'], $this->TIMERANGE['end']);
$this->readXML($host, $service);
$count = 0;
$RRAs = [
'MIN',
'MAX',
'AVERAGE',
];
foreach ($this->DS as $key => $value) {
foreach ($RRAs as $RRA) {
$this->XPORT .= sprintf(' DEF:%d%s=%s:%d:%s ', $count, $RRA, $value['RRDFILE'], $value['DS'], $RRA);
$this->XPORT .= sprintf(' XPORT:%d%s:%s_%s ', $count, $RRA, $value['NAME'], $RRA);
}
$count++;
}
}
//end buildXport()
public function xml2csv($string)
{
$xml = simplexml_load_string($string);
$csv = 'timestamp';
foreach ($xml->meta->legend->entry as $key => $value) {
$csv .= ';' . $value;
}
/*
* from rrdtool 1.5 on, timestamp ( value->t ) is not set anymore
* from 1.6 on it can be reactivated by -- showrime option to rrdtool xport
* here we take care of the timestamp ourselves regardless which
* rrdtool version is used
*/
$timestamp2 = $xml->meta->start;
$step = $xml->meta->step;
$csv .= "\n";
foreach ($xml->data->row as $key => $value) {
$csv .= $timestamp2;
foreach ($value->v as $item) {
$csv .= ';' . floatval((string) $item);
}
$csv .= "\n";
$timestamp2 = ($timestamp2 + $step);
}
return $csv;
}
//end xml2csv()
/*
*
* Used in Special Templates to gather data
*/
public function tplGetData($hostname, $servicedesc, $throw_exception = true)
{
$conf = $this->config->conf;
$xmlfile = $conf['rrdbase'] . $hostname . '/' . $servicedesc . '.xml';
$data = [];
if (file_exists($xmlfile)) {
$xml = simplexml_load_file($xmlfile);
// Throw excaption without a valid structure version
if (!isset($xml->XML->VERSION) && $throw_exception == true) {
throw new Kohana_Exception('error.xml-structure-without-version-tag', $xmlfile);
}
if (!isset($xml->XML->VERSION) && $throw_exception == false) {
return false;
}
foreach ($xml as $key => $val) {
if (preg_match('/^NAGIOS_(.*)$/', $key, $match)) {
$key = $match[1];
$data['MACRO'][$key] = (string) $val;
}
}
$i = 0;
foreach ($xml->DATASOURCE as $datasource) {
foreach ($datasource as $key => $val) {
$data['DS'][$i][$key] = (string) $val;
}
$i++;
}
return $data;
} else {
throw new Kohana_Exception('error.xml-not-found', $xmlfile);
}
//end if
}
//end tplGetData()
/*
*
* Used in Special Templates to gather data
*/
public function tplGetServices($hostregex = false, $serviceregex = '')
{
if ($hostregex === false) {
return false;
}
$hostregex = sprintf('/%s/', $hostregex);
$serviceregex = sprintf('/%s/', $serviceregex);
$hosts = $this->getHosts();
$new_hosts = [];
foreach ($hosts as $host) {
if (preg_match($hostregex, $host['name'])) {
$new_hosts[] = $host['name'];
}
}
if (empty($new_hosts)) {
throw new Kohana_Exception('error.tpl-no-hosts-found', $hostregex);
}
$i = 0;
$new_services = [];
foreach ($new_hosts as $host) {
$services = $this->getRawServices($host);
if (empty($services)) {
throw new Kohana_Exception('error.tpl-no-services-found', $serviceregex);
}
foreach ($services as $service) {
if (preg_match($serviceregex, $service['name'])) {
$new_services[$i]['hostname'] = $host;
$new_services[$i]['host'] = $host;
$new_services[$i]['service_description'] = $service['name'];
$new_services[$i]['service'] = $service['name'];
$i++;
}
}
}
if (empty($new_services)) {
throw new Kohana_Exception('error.tpl-no-services-found', $serviceregex);
}
return $new_services;
}
//end tplGetServices()
}
//end class