mirror of
https://github.com/Icinga/icingaweb2-module-graphite.git
synced 2026-05-28 04:34:57 -04:00
Merge pull request #280 from Icinga/fix/broken-routes-if-monitoring-not-installed-279
Split `icingadb` and `monitoring` graph controllers
This commit is contained in:
commit
641de8b7e4
4 changed files with 328 additions and 73 deletions
|
|
@ -2,24 +2,19 @@
|
|||
|
||||
namespace Icinga\Module\Graphite\Controllers;
|
||||
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Exception\Http\HttpBadRequestException;
|
||||
use Icinga\Exception\Http\HttpNotFoundException;
|
||||
use Icinga\Module\Graphite\Graphing\GraphingTrait;
|
||||
use Icinga\Module\Graphite\ProvidedHook\Icingadb\IcingadbSupport;
|
||||
use Icinga\Module\Graphite\Util\IcingadbUtils;
|
||||
use Icinga\Module\Graphite\Web\Controller\MonitoringAwareController;
|
||||
use Icinga\Module\Graphite\Web\Widget\Graphs;
|
||||
use Icinga\Module\Monitoring\Object\Host;
|
||||
use Icinga\Module\Monitoring\Object\MonitoredObject;
|
||||
use Icinga\Module\Monitoring\Object\Service;
|
||||
use Icinga\Module\Icingadb\Model\Host;
|
||||
use Icinga\Module\Icingadb\Model\Service;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\UrlParams;
|
||||
use Icinga\Module\Icingadb\Model\Service as IcingadbService;
|
||||
use Icinga\Module\Icingadb\Model\Host as IcingadbHost;
|
||||
use ipl\Orm\Model;
|
||||
use ipl\Stdlib\Filter;
|
||||
|
||||
class GraphController extends MonitoringAwareController
|
||||
class GraphController extends Controller
|
||||
{
|
||||
use GraphingTrait;
|
||||
|
||||
|
|
@ -62,64 +57,12 @@ class GraphController extends MonitoringAwareController
|
|||
}
|
||||
}
|
||||
|
||||
public function hostAction()
|
||||
{
|
||||
if (Module::exists('icingadb') && IcingadbSupport::useIcingaDbAsBackend()) {
|
||||
$this->icingadbHost();
|
||||
return;
|
||||
}
|
||||
|
||||
$hostName = $this->filterParams->getRequired('host.name');
|
||||
$checkCommandColumn = '_host_' . Graphs::getObscuredCheckCommandCustomVar();
|
||||
$host = $this->applyMonitoringRestriction(
|
||||
$this->backend->select()->from('hoststatus', ['host_check_command', $checkCommandColumn])
|
||||
)
|
||||
->where('host_name', $hostName)
|
||||
->limit(1) // just to be sure to save a few CPU cycles
|
||||
->fetchRow();
|
||||
|
||||
if ($host === false) {
|
||||
throw new HttpNotFoundException('%s', $this->translate('No such host'));
|
||||
}
|
||||
|
||||
$this->supplyImage(new Host($this->backend, $hostName), $host->host_check_command, $host->$checkCommandColumn);
|
||||
}
|
||||
|
||||
public function serviceAction()
|
||||
{
|
||||
if (Module::exists('icingadb') && IcingadbSupport::useIcingaDbAsBackend()) {
|
||||
$this->icingadbService();
|
||||
return;
|
||||
}
|
||||
|
||||
$hostName = $this->filterParams->getRequired('host.name');
|
||||
$serviceName = $this->filterParams->getRequired('service.name');
|
||||
$checkCommandColumn = '_service_' . Graphs::getObscuredCheckCommandCustomVar();
|
||||
$service = $this->applyMonitoringRestriction(
|
||||
$this->backend->select()->from('servicestatus', ['service_check_command', $checkCommandColumn])
|
||||
)
|
||||
->where('host_name', $hostName)
|
||||
->where('service_description', $serviceName)
|
||||
->limit(1) // just to be sure to save a few CPU cycles
|
||||
->fetchRow();
|
||||
|
||||
if ($service === false) {
|
||||
throw new HttpNotFoundException('%s', $this->translate('No such service'));
|
||||
}
|
||||
|
||||
$this->supplyImage(
|
||||
new Service($this->backend, $hostName, $serviceName),
|
||||
$service->service_check_command,
|
||||
$service->$checkCommandColumn
|
||||
);
|
||||
}
|
||||
|
||||
private function icingadbService()
|
||||
{
|
||||
$hostName = $this->filterParams->getRequired('host.name');
|
||||
$serviceName = $this->filterParams->getRequired('service.name');
|
||||
$icingadbUtils = IcingadbUtils::getInstance();
|
||||
$query = IcingadbService::on($icingadbUtils->getDb())
|
||||
$query = Service::on($icingadbUtils->getDb())
|
||||
->with('state')
|
||||
->with('host');
|
||||
|
||||
|
|
@ -130,7 +73,7 @@ class GraphController extends MonitoringAwareController
|
|||
|
||||
$icingadbUtils->applyRestrictions($query);
|
||||
|
||||
/** @var IcingadbService $service */
|
||||
/** @var Service $service */
|
||||
$service = $query->first();
|
||||
|
||||
if ($service === null) {
|
||||
|
|
@ -146,16 +89,16 @@ class GraphController extends MonitoringAwareController
|
|||
);
|
||||
}
|
||||
|
||||
private function icingadbHost()
|
||||
public function hostAction()
|
||||
{
|
||||
$hostName = $this->filterParams->getRequired('host.name');
|
||||
$icingadbUtils = IcingadbUtils::getInstance();
|
||||
$query = IcingadbHost::on($icingadbUtils->getDb())->with('state');
|
||||
$query = Host::on($icingadbUtils->getDb())->with('state');
|
||||
$query->filter(Filter::equal('host.name', $hostName));
|
||||
|
||||
$icingadbUtils->applyRestrictions($query);
|
||||
|
||||
/** @var IcingadbHost $host */
|
||||
/** @var Host $host */
|
||||
$host = $query->first();
|
||||
|
||||
if ($host === null) {
|
||||
|
|
@ -172,12 +115,12 @@ class GraphController extends MonitoringAwareController
|
|||
}
|
||||
|
||||
/**
|
||||
* Do all monitored object type independend actions
|
||||
* Do all monitored object type independent actions
|
||||
*
|
||||
* @param MonitoredObject|Model $object The object to render the graphs for
|
||||
* @param string $checkCommand The check command of the object we supply an image for
|
||||
* @param string|null $obscuredCheckCommand The "real" check command (if any) of the object we
|
||||
* display graphs for
|
||||
* @param Model $object The object to render the graphs for
|
||||
* @param string $checkCommand The check command of the object we supply an image for
|
||||
* @param string|null $obscuredCheckCommand The "real" check command (if any) of the object we
|
||||
* display graphs for
|
||||
*/
|
||||
protected function supplyImage($object, $checkCommand, $obscuredCheckCommand)
|
||||
{
|
||||
|
|
|
|||
155
application/controllers/MonitoringGraphController.php
Normal file
155
application/controllers/MonitoringGraphController.php
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Graphite\Controllers;
|
||||
|
||||
use Icinga\Exception\Http\HttpBadRequestException;
|
||||
use Icinga\Exception\Http\HttpNotFoundException;
|
||||
use Icinga\Module\Graphite\Graphing\GraphingTrait;
|
||||
use Icinga\Module\Graphite\Web\Controller\MonitoringAwareController;
|
||||
use Icinga\Module\Graphite\Web\Widget\Graphs;
|
||||
use Icinga\Module\Monitoring\Object\Host;
|
||||
use Icinga\Module\Monitoring\Object\MonitoredObject;
|
||||
use Icinga\Module\Monitoring\Object\Service;
|
||||
use Icinga\Web\UrlParams;
|
||||
|
||||
class MonitoringGraphController extends MonitoringAwareController
|
||||
{
|
||||
use GraphingTrait;
|
||||
|
||||
/**
|
||||
* The URL parameters for the graph
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $graphParamsNames = [
|
||||
'start', 'end',
|
||||
'width', 'height',
|
||||
'legend',
|
||||
'template', 'default_template',
|
||||
'bgcolor', 'fgcolor',
|
||||
'majorGridLineColor', 'minorGridLineColor'
|
||||
];
|
||||
|
||||
/**
|
||||
* The URL parameters for metrics filtering
|
||||
*
|
||||
* @var UrlParams
|
||||
*/
|
||||
protected $filterParams;
|
||||
|
||||
/**
|
||||
* The URL parameters for the graph
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $graphParams = [];
|
||||
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
$this->filterParams = clone $this->getRequest()->getUrl()->getParams();
|
||||
|
||||
foreach ($this->graphParamsNames as $paramName) {
|
||||
$this->graphParams[$paramName] = $this->filterParams->shift($paramName);
|
||||
}
|
||||
}
|
||||
|
||||
public function hostAction()
|
||||
{
|
||||
$hostName = $this->filterParams->getRequired('host.name');
|
||||
$checkCommandColumn = '_host_' . Graphs::getObscuredCheckCommandCustomVar();
|
||||
$host = $this->applyMonitoringRestriction(
|
||||
$this->backend->select()->from('hoststatus', ['host_check_command', $checkCommandColumn])
|
||||
)
|
||||
->where('host_name', $hostName)
|
||||
->limit(1) // just to be sure to save a few CPU cycles
|
||||
->fetchRow();
|
||||
|
||||
if ($host === false) {
|
||||
throw new HttpNotFoundException('%s', $this->translate('No such host'));
|
||||
}
|
||||
|
||||
$this->supplyImage(new Host($this->backend, $hostName), $host->host_check_command, $host->$checkCommandColumn);
|
||||
}
|
||||
|
||||
public function serviceAction()
|
||||
{
|
||||
$hostName = $this->filterParams->getRequired('host.name');
|
||||
$serviceName = $this->filterParams->getRequired('service.name');
|
||||
$checkCommandColumn = '_service_' . Graphs::getObscuredCheckCommandCustomVar();
|
||||
$service = $this->applyMonitoringRestriction(
|
||||
$this->backend->select()->from('servicestatus', ['service_check_command', $checkCommandColumn])
|
||||
)
|
||||
->where('host_name', $hostName)
|
||||
->where('service_description', $serviceName)
|
||||
->limit(1) // just to be sure to save a few CPU cycles
|
||||
->fetchRow();
|
||||
|
||||
if ($service === false) {
|
||||
throw new HttpNotFoundException('%s', $this->translate('No such service'));
|
||||
}
|
||||
|
||||
$this->supplyImage(
|
||||
new Service($this->backend, $hostName, $serviceName),
|
||||
$service->service_check_command,
|
||||
$service->$checkCommandColumn
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do all monitored object type independend actions
|
||||
*
|
||||
* @param MonitoredObject $object The object to render the graphs for
|
||||
* @param string $checkCommand The check command of the object we supply an image for
|
||||
* @param string|null $obscuredCheckCommand The "real" check command (if any) of the object we
|
||||
* display graphs for
|
||||
*/
|
||||
protected function supplyImage($object, $checkCommand, $obscuredCheckCommand)
|
||||
{
|
||||
if (isset($this->graphParams['default_template'])) {
|
||||
$urlParam = 'default_template';
|
||||
$templates = $this->getAllTemplates()->getDefaultTemplates();
|
||||
} else {
|
||||
$urlParam = 'template';
|
||||
$templates = $this->getAllTemplates()->getTemplates(
|
||||
$obscuredCheckCommand === null ? $checkCommand : $obscuredCheckCommand
|
||||
);
|
||||
}
|
||||
|
||||
if (! isset($templates[$this->graphParams[$urlParam]])) {
|
||||
throw new HttpNotFoundException($this->translate('No such template'));
|
||||
}
|
||||
|
||||
$charts = $templates[$this->graphParams[$urlParam]]->getCharts(
|
||||
static::getMetricsDataSource(),
|
||||
$object,
|
||||
array_map('rawurldecode', $this->filterParams->toArray(false))
|
||||
);
|
||||
|
||||
switch (count($charts)) {
|
||||
case 0:
|
||||
throw new HttpNotFoundException($this->translate('No such graph'));
|
||||
|
||||
case 1:
|
||||
$charts[0]
|
||||
->setFrom($this->graphParams['start'])
|
||||
->setUntil($this->graphParams['end'])
|
||||
->setWidth($this->graphParams['width'])
|
||||
->setHeight($this->graphParams['height'])
|
||||
->setBackgroundColor($this->graphParams['bgcolor'])
|
||||
->setForegroundColor($this->graphParams['fgcolor'])
|
||||
->setMajorGridLineColor($this->graphParams['majorGridLineColor'])
|
||||
->setMinorGridLineColor($this->graphParams['minorGridLineColor'])
|
||||
->setShowLegend((bool) $this->graphParams['legend'])
|
||||
->serveImage($this->getResponse());
|
||||
|
||||
// not falling through, serveImage exits
|
||||
default:
|
||||
throw new HttpBadRequestException('%s', $this->translate(
|
||||
'Graphite Web yields more than one metric for the given filter.'
|
||||
. ' Please specify a more precise filter.'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,10 +2,20 @@
|
|||
|
||||
namespace Icinga\Module\Graphite\Web\Controller;
|
||||
|
||||
use ArrayIterator;
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Data\Filterable;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\QueryException;
|
||||
use Icinga\Module\Graphite\ProvidedHook\Icingadb\IcingadbSupport;
|
||||
use Icinga\Module\Monitoring\Controller;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Module\Monitoring\Data\CustomvarProtectionIterator;
|
||||
use Icinga\Module\Monitoring\DataView\DataView;
|
||||
use Icinga\Util\Json;
|
||||
use Icinga\File\Csv;
|
||||
use Icinga\Web\Controller;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
abstract class MonitoringAwareController extends Controller
|
||||
{
|
||||
|
|
@ -34,6 +44,132 @@ abstract class MonitoringAwareController extends Controller
|
|||
return;
|
||||
}
|
||||
|
||||
parent::moduleInit();
|
||||
$this->backend = MonitoringBackend::instance($this->_getParam('backend'));
|
||||
$this->view->url = Url::fromRequest();
|
||||
}
|
||||
|
||||
|
||||
protected function handleFormatRequest($query)
|
||||
{
|
||||
$desiredContentType = $this->getRequest()->getHeader('Accept');
|
||||
if ($desiredContentType === 'application/json') {
|
||||
$desiredFormat = 'json';
|
||||
} elseif ($desiredContentType === 'text/csv') {
|
||||
$desiredFormat = 'csv';
|
||||
} else {
|
||||
$desiredFormat = strtolower($this->params->get('format', 'html'));
|
||||
}
|
||||
|
||||
if ($desiredFormat !== 'html' && ! $this->params->has('limit')) {
|
||||
$query->limit(); // Resets any default limit and offset
|
||||
}
|
||||
|
||||
switch ($desiredFormat) {
|
||||
case 'sql':
|
||||
echo '<pre>'
|
||||
. htmlspecialchars(wordwrap($query->dump()))
|
||||
. '</pre>';
|
||||
exit;
|
||||
case 'json':
|
||||
$response = $this->getResponse();
|
||||
$response
|
||||
->setHeader('Content-Type', 'application/json')
|
||||
->setHeader('Cache-Control', 'no-store')
|
||||
->setHeader(
|
||||
'Content-Disposition',
|
||||
'inline; filename=' . $this->getRequest()->getActionName() . '.json'
|
||||
)
|
||||
->appendBody(
|
||||
Json::sanitize(
|
||||
iterator_to_array(
|
||||
new CustomvarProtectionIterator(
|
||||
new ArrayIterator($query->fetchAll())
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
->sendResponse();
|
||||
exit;
|
||||
case 'csv':
|
||||
$response = $this->getResponse();
|
||||
$response
|
||||
->setHeader('Content-Type', 'text/csv')
|
||||
->setHeader('Cache-Control', 'no-store')
|
||||
->setHeader(
|
||||
'Content-Disposition',
|
||||
'attachment; filename=' . $this->getRequest()->getActionName() . '.csv'
|
||||
)
|
||||
->appendBody((string) Csv::fromQuery(new CustomvarProtectionIterator($query)))
|
||||
->sendResponse();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a restriction of the authenticated on the given filterable
|
||||
*
|
||||
* @param string $name Name of the restriction
|
||||
* @param Filterable $filterable Filterable to restrict
|
||||
*
|
||||
* @return Filterable The filterable having the restriction applied
|
||||
*/
|
||||
protected function applyRestriction($name, Filterable $filterable)
|
||||
{
|
||||
$filterable->applyFilter($this->getRestriction($name));
|
||||
return $filterable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a restriction of the authenticated
|
||||
*
|
||||
* @param string $name Name of the restriction
|
||||
*
|
||||
* @return Filter Filter object
|
||||
* @throws ConfigurationError If the restriction contains invalid filter columns
|
||||
*/
|
||||
protected function getRestriction($name)
|
||||
{
|
||||
$restriction = Filter::matchAny();
|
||||
$restriction->setAllowedFilterColumns(array(
|
||||
'host_name',
|
||||
'hostgroup_name',
|
||||
'instance_name',
|
||||
'service_description',
|
||||
'servicegroup_name',
|
||||
function ($c) {
|
||||
return preg_match('/^_(?:host|service)_/i', $c);
|
||||
}
|
||||
));
|
||||
foreach ($this->getRestrictions($name) as $filter) {
|
||||
if ($filter === '*') {
|
||||
return Filter::matchAll();
|
||||
}
|
||||
try {
|
||||
$restriction->addFilter(Filter::fromQueryString($filter));
|
||||
} catch (QueryException $e) {
|
||||
throw new ConfigurationError(
|
||||
$this->translate(
|
||||
'Cannot apply restriction %s using the filter %s. You can only use the following columns: %s'
|
||||
),
|
||||
$name,
|
||||
$filter,
|
||||
implode(', ', array(
|
||||
'instance_name',
|
||||
'host_name',
|
||||
'hostgroup_name',
|
||||
'service_description',
|
||||
'servicegroup_name',
|
||||
'_(host|service)_<customvar-name>'
|
||||
)),
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($restriction->isEmpty()) {
|
||||
return Filter::matchAll();
|
||||
}
|
||||
|
||||
return $restriction;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
21
run.php
21
run.php
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
/** @var \Icinga\Application\Modules\Module $this */
|
||||
|
||||
use Icinga\Module\Graphite\ProvidedHook\Icingadb\IcingadbSupport;
|
||||
|
||||
require_once $this->getLibDir() . '/vendor/Psr/Loader.php';
|
||||
require_once $this->getLibDir() . '/vendor/iplx/Loader.php';
|
||||
|
||||
|
|
@ -9,3 +11,22 @@ $this->provideHook('monitoring/DetailviewExtension');
|
|||
$this->provideHook('icingadb/IcingadbSupport');
|
||||
$this->provideHook('icingadb/HostDetailExtension');
|
||||
$this->provideHook('icingadb/ServiceDetailExtension');
|
||||
|
||||
if (! $this->exists('icingadb') || ! IcingadbSupport::useIcingaDbAsBackend()) {
|
||||
$this->addRoute('graphite/monitoring-graph/host', new Zend_Controller_Router_Route(
|
||||
'graphite/graph/host',
|
||||
[
|
||||
'controller' => 'monitoring-graph',
|
||||
'action' => 'host',
|
||||
'module' => 'graphite'
|
||||
]
|
||||
));
|
||||
$this->addRoute('graphite/monitoring-graph/service', new Zend_Controller_Router_Route(
|
||||
'graphite/graph/service',
|
||||
[
|
||||
'controller' => 'monitoring-graph',
|
||||
'action' => 'service',
|
||||
'module' => 'graphite'
|
||||
]
|
||||
));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue