diff options
Diffstat (limited to 'library/Pnp')
-rw-r--r-- | library/Pnp/ProvidedHook/Grapher.php | 274 | ||||
-rw-r--r-- | library/Pnp/Web/Controller.php | 27 |
2 files changed, 301 insertions, 0 deletions
diff --git a/library/Pnp/ProvidedHook/Grapher.php b/library/Pnp/ProvidedHook/Grapher.php new file mode 100644 index 0000000..2dcfbda --- /dev/null +++ b/library/Pnp/ProvidedHook/Grapher.php @@ -0,0 +1,274 @@ +<?php + +namespace Icinga\Module\Pnp\ProvidedHook; + +use Icinga\Application\Config; +use Icinga\Exception\ConfigurationError; +use Icinga\Application\Hook\GrapherHook; +use Icinga\Module\Monitoring\Object\MonitoredObject; +use Icinga\Module\Monitoring\Object\Host; +use Icinga\Module\Monitoring\Object\Service; +use Icinga\Web\Url; + +class Grapher extends GrapherHook +{ + protected $hasPreviews = true; + + protected $pnpConfig; + + protected $pnpViews; + + protected $configDir = '/etc/pnp4nagios'; + + protected $baseUrl = '/pnp4nagios'; + + protected function init() + { + $cfg = Config::module('pnp')->getSection('pnp4nagios'); + $this->configDir = rtrim($cfg->get('config_dir', $this->configDir), '/'); + $this->baseUrl = rtrim($cfg->get('base_url', $this->baseUrl), '/'); + $this->readPnpConfig(); + } + + public function has(MonitoredObject $object) + { + if ($object instanceof Host) { + $service = '_HOST_'; + } elseif ($object instanceof Service) { + $service = $object->service_description; + } else { + return false; + } + + $host = $object->host_name; + return is_file($this->getXmlFilename($host, $service)); + } + + public function getPreviewHtml(MonitoredObject $object) + { + if (! $object->process_perfdata) { + return ''; + } + + // Skip preview images when missing, for local installations only + if (false === strpos($this->baseUrl, '://') && ! $this->has($object)) { + return ''; + } + + if ($object instanceof Host) { + $service = '_HOST_'; + } elseif ($object instanceof Service) { + $service = $object->service_description; + } else { + return ''; + } + + $host = $object->host_name; + + $html = '<table style="width: 100%; max-width: 40em; text-align: center;' + . ' font-size: 0.8em; line-height: 0.8em; table-layout: fixed">' + . "\n <tr>\n"; + $viewKeys = array_reverse(array_keys($this->pnpViews)); + foreach ($viewKeys as $view) { + $html .= '<th>' . htmlspecialchars($this->getViewName($view)) . "</th>\n"; + } + $html .= " </tr>\n <tr>\n"; + foreach ($viewKeys as $view) { + $html .= ' <td style="border-left: 1px solid #555; padding-right: 3px">' + . $this->getPreviewImg($host, $service, $view) + . "</td>\n"; + } + $html .= "</tr></table>\n"; + return $html; + } + + // Currently unused, but would work fine. This is for tiny preview images + // in list views + public function getSmallPreviewImage($host, $service = null) + { + if ($service === null) { + $service = '_HOST_'; + } + + return sprintf( + '<img src="%s/image?host=%s&srv=%s&view=0&source=0&h=20&w=50" alt="" style="float: right" />', + $this->baseUrl, + urlencode($this->pnpClean($host)), + urlencode($this->pnpClean($service)) + ); + } + + private function listAdditionalConfigFiles() + { + $files = array(); + $base = $this->configDir . '/config'; + + $file = $base . '_local.php'; + if (file_exists($file) && is_readable($file)) { + $files[] = $file; + } + + $confd = $base . '.d'; + if (is_dir($confd) && is_readable($confd)) { + $dh = opendir($confd); + while ($file === readdir($dh)) { + if ($file[0] === '.') continue; + if (substr($file, -4) !== '.php') continue; + + $filename = $confd . '/' . $file; + if (is_file($filename) && is_readable($filename)) { + $files[] = $filename; + } + } + + closedir($dh); + } + + return $files; + } + + // This reads the PNP4Nagios config and makes it's $conf available + private function readPnpConfig() + { + $file = $this->configDir . '/config.php'; + + if (! is_readable($file)) { + throw new ConfigurationError( + sprintf( + 'Cannot read PNP4Nagios-Web config file "%s"', + $file + ) + ); + } + if (! include($file)) { + throw new ConfigurationError( + sprintf( + 'Including PNP4Nagios-Web config "%s" failed', + $file + ) + ); + } + + if (! isset($views)) { + $views = array(); + } + + foreach ($this->listAdditionalConfigFiles() as $file) { + $oldViews = $views; + include $file; + if (empty($views)) { + $views = $oldViews; + } + } + + if (! isset($conf) || ! is_array($conf)) { + throw new ConfigurationError( + sprintf( + 'There is no $conf in your PNP4Nagios config file "%s"', + $file + ) + ); + } + + if (! isset($views) || ! is_array($views)) { + throw new ConfigurationError( + sprintf( + 'There is no $views array in your PNP4Nagios config file "%s"', + $file + ) + ); + } + + if (! array_key_exists('rrdbase', $conf)) { + throw new ConfigurationError( + sprintf( + 'There is no rrdbase in your PNP4Nagios config file "%s"', + $file + ) + ); + } + $this->pnpConfig = $conf; + $this->pnpViews = $views; + return $this; + } + + // pnp_Core::clean + private function pnpClean($string) + { + if ($string === false) { + return null; + } + return preg_replace('~[ :/\\\]~', '_', $string); + } + + private function getBasePath($host, $service) + { + if ($service === null) { + $service = '_HOST_'; + } + return rtrim($this->pnpConfig['rrdbase'], '/') + . '/' . $this->pnpClean($host) . '/' + . $this->pnpClean($service); + } + + private function getRrdFilename($host, $service) + { + return $this->getBasePath($host, $service) . '.rrd'; + } + + private function getXmlFilename($host, $service) + { + return $this->getBasePath($host, $service) . '.xml'; + } + + private function getPreviewImg($host, $service, $view) + { + $viewName = $this->getViewName($view); + + $host = $this->pnpClean($host); + $service = $this->pnpClean($service); + + $title = $service === '_HOST_' ? sprintf( + '%s, %s', $host, $viewName + ) : sprintf( + '%s on %s, %s', $service, $host, $viewName + ); + + $url = Url::fromPath('pnp/graph', array( + 'host' => $this->pnpClean($host), + 'srv' => $this->pnpClean($service), + 'view' => $view + )); + $imgUrl = sprintf( + '%s/image?host=%s&srv=%s&view=%d&source=0&w=120&h=30', + $this->baseUrl, + urlencode($this->pnpClean($host)), + urlencode($this->pnpClean($service)), + $view + ); + + $html = '<a href="%s" title="%s"><img src="%s" alt="%s" width="100%%" height="30" /></a>'; + + return sprintf( + $html, + $url, + htmlspecialchars($title), + $imgUrl, + htmlspecialchars(mt('pnp', 'Loading') . '...') + ); + } + + protected function getViewName($view) + { + return mt('pnp4nagios', $this->pnpViews[$view]['title']); + } + + private function unusedFunctionAllowingToTranslateForeignStrings() + { + mt('pnp4nagios', '4 Hours'); + mt('pnp4nagios', '25 Hours'); + mt('pnp4nagios', 'One Week'); + mt('pnp4nagios', 'One Month'); + mt('pnp4nagios', 'One Year'); + } +} diff --git a/library/Pnp/Web/Controller.php b/library/Pnp/Web/Controller.php new file mode 100644 index 0000000..4af5c06 --- /dev/null +++ b/library/Pnp/Web/Controller.php @@ -0,0 +1,27 @@ +<?php + +namespace Icinga\Module\Pnp\Web; + +use Icinga\Web\Controller as IcingaController; + +class Controller extends IcingaController +{ + public function init() + { + $this->getTabs()->add('pnp', array( + 'label' => $this->translate('PNP'), + 'url' => 'pnp', + )); + } + + protected function setViewScript($name) + { + $this->_helper->viewRenderer->setNoController(true); + $this->_helper->viewRenderer->setScriptAction($name); + } + + protected function getBaseUrl() + { + return rtrim($this->Config()->get('pnp4nagios', 'base_url', '/pnp4nagios'), '/'); + } +} |