diff --git a/application/controllers/GraphController.php b/application/controllers/GraphController.php index c2c147d..986d2c1 100644 --- a/application/controllers/GraphController.php +++ b/application/controllers/GraphController.php @@ -2,19 +2,29 @@ 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\Web\Controller\MonitoringAwareController; use Icinga\Module\Graphite\Web\Widget\Graphs; +use Icinga\Module\Icingadb\Common\Auth; use Icinga\Module\Monitoring\Object\Host; use Icinga\Module\Monitoring\Object\MonitoredObject; use Icinga\Module\Monitoring\Object\Service; use Icinga\Web\UrlParams; +use Icinga\Module\Icingadb\Common\Database; +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 { use GraphingTrait; + use Database; + use Auth; /** * The URL parameters for the graph @@ -57,6 +67,11 @@ 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( @@ -75,6 +90,11 @@ class GraphController extends MonitoringAwareController 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(); @@ -97,15 +117,70 @@ class GraphController extends MonitoringAwareController ); } + private function icingadbService() + { + $hostName = $this->filterParams->getRequired('host.name'); + $serviceName = $this->filterParams->getRequired('service.name'); + + $query = IcingadbService::on($this->getDb())->with(['state', 'host']); + + $query->filter(Filter::all( + Filter::equal('service.name', $serviceName), + Filter::equal('service.host.name', $hostName) + )); + + $this->applyRestrictions($query); + + /** @var IcingadbService $service */ + $service = $query->first(); + + if ($service === null) { + throw new HttpNotFoundException($this->translate('No such service')); + } + + $checkCommandColumn = $service->vars[Graphs::getObscuredCheckCommandCustomVar()] ?? null; + + $this->supplyImage( + $service, + $service->checkcommand, + $checkCommandColumn + ); + } + + private function icingadbHost() + { + $hostName = $this->filterParams->getRequired('host.name'); + + $query = IcingadbHost::on($this->getDb())->with(['state']); + $query->filter(Filter::equal('host.name', $hostName)); + + $this->applyRestrictions($query); + + /** @var IcingadbHost $host */ + $host = $query->first(); + + if ($host === null) { + throw new HttpNotFoundException($this->translate('No such host')); + } + + $checkCommandColumn = $host->vars[Graphs::getObscuredCheckCommandCustomVar()] ?? null; + + $this->supplyImage( + $host, + $host->checkcommand, + $checkCommandColumn + ); + } + /** * Do all monitored object type independend actions * - * @param MonitoredObject $monitoredObject The monitored object to render the graphs of - * @param string $checkCommand The check command of the monitored object we supply an image for - * @param string|null $obscuredCheckCommand The "real" check command (if any) of the monitored object - * we display graphs for + * @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 */ - protected function supplyImage(MonitoredObject $monitoredObject, $checkCommand, $obscuredCheckCommand) + protected function supplyImage($object, $checkCommand, $obscuredCheckCommand) { if (isset($this->graphParams['default_template'])) { $urlParam = 'default_template'; @@ -123,7 +198,7 @@ class GraphController extends MonitoringAwareController $charts = $templates[$this->graphParams[$urlParam]]->getCharts( static::getMetricsDataSource(), - $monitoredObject, + $object, array_map('rawurldecode', $this->filterParams->toArray(false)) ); diff --git a/library/Graphite/Graphing/MetricsQuery.php b/library/Graphite/Graphing/MetricsQuery.php index 9ccc73a..951cba7 100644 --- a/library/Graphite/Graphing/MetricsQuery.php +++ b/library/Graphite/Graphing/MetricsQuery.php @@ -10,17 +10,21 @@ use Icinga\Exception\NotImplementedError; use Icinga\Module\Graphite\GraphiteUtil; use Icinga\Module\Graphite\Util\MacroTemplate; use Icinga\Module\Graphite\Util\InternalProcessTracker as IPT; +use Icinga\Module\Icingadb\Common\Macros; use Icinga\Module\Monitoring\Object\Macro; use Icinga\Module\Monitoring\Object\MonitoredObject; use Icinga\Util\Json; use Icinga\Web\Url; use InvalidArgumentException; +use ipl\Orm\Model; /** * Queries a {@link MetricsDataSource} */ class MetricsQuery implements Queryable, Filterable, Fetchable { + use Macros; + /** * @var MetricsDataSource */ @@ -41,11 +45,11 @@ class MetricsQuery implements Queryable, Filterable, Fetchable protected $filter = []; /** - * The monitored object to render the graphs of + * The object to render the graphs for * - * @var MonitoredObject + * @var MonitoredObject|Model */ - protected $monitoredObject; + protected $object; /** * Constructor @@ -128,12 +132,24 @@ class MetricsQuery implements Queryable, Filterable, Fetchable continue; } - $workaroundMacro = str_replace('.', '_', $macro); - if ($workaroundMacro === 'service_name') { - $workaroundMacro = 'service_description'; - } + if ($this->object instanceof Model) { + // icingadb macros + $workaroundMacro = $macro; + if ($workaroundMacro === 'service.check_command') { + $workaroundMacro = 'service.checkcommand'; + } + if ($workaroundMacro === 'host.check_command') { + $workaroundMacro = 'host.checkcommand'; + } + $result = $this->resolveMacro($workaroundMacro, $this->object); + } else { + $workaroundMacro = str_replace('.', '_', $macro); + if ($workaroundMacro === 'service_name') { + $workaroundMacro = 'service_description'; + } - $result = Macro::resolveMacro($workaroundMacro, $this->monitoredObject); + $result = Macro::resolveMacro($workaroundMacro, $this->object); + } if ($result !== $workaroundMacro) { $filter[$macro] = $this->escapeMetricStep($result); @@ -164,15 +180,15 @@ class MetricsQuery implements Queryable, Filterable, Fetchable } /** - * Set the monitored object to render the graphs of + * Set the object to render the graphs for * - * @param MonitoredObject $monitoredObject + * @param MonitoredObject|Model $object * * @return $this */ - public function setMonitoredObject($monitoredObject) + public function setObject($object) { - $this->monitoredObject = $monitoredObject; + $this->object = $object; return $this; } diff --git a/library/Graphite/Graphing/Template.php b/library/Graphite/Graphing/Template.php index 25302aa..aaf967e 100644 --- a/library/Graphite/Graphing/Template.php +++ b/library/Graphite/Graphing/Template.php @@ -8,6 +8,7 @@ use Icinga\Module\Graphite\Util\MacroTemplate; use Icinga\Module\Graphite\Util\InternalProcessTracker as IPT; use Icinga\Module\Monitoring\Object\MonitoredObject; use InvalidArgumentException; +use ipl\Orm\Model; class Template { @@ -63,16 +64,16 @@ class Template * Get all charts based on this template and applicable to the metrics * from the given data source restricted by the given filter * - * @param MetricsDataSource $dataSource - * @param MonitoredObject $monitoredObject The monitored object to render the graphs of - * @param string[] $filter - * @param MacroTemplate[] $excludeMetrics + * @param MetricsDataSource $dataSource + * @param MonitoredObject|Model $object The object to render the graphs for + * @param string[] $filter + * @param MacroTemplate[] $excludeMetrics * * @return Chart[] */ public function getCharts( MetricsDataSource $dataSource, - MonitoredObject $monitoredObject, + $object, array $filter, array &$excludeMetrics = [] ) { @@ -83,7 +84,7 @@ class Template foreach ($this->getFullCurves() as $curveName => $curve) { $fullMetricTemplate = $curve[0]; - $query = $dataSource->select()->setMonitoredObject($monitoredObject)->from($fullMetricTemplate); + $query = $dataSource->select()->setObject($object)->from($fullMetricTemplate); foreach ($filter as $key => $value) { $query->where($key, $value); diff --git a/library/Graphite/Web/Widget/Graphs.php b/library/Graphite/Web/Widget/Graphs.php index 55a2d97..05691b2 100644 --- a/library/Graphite/Web/Widget/Graphs.php +++ b/library/Graphite/Web/Widget/Graphs.php @@ -20,31 +20,35 @@ use Icinga\Web\Request; use Icinga\Web\Url; use Icinga\Web\View; use Icinga\Web\Widget\AbstractWidget; +use ipl\Orm\Model; +use Icinga\Module\Icingadb\Model\Host as IcingadbHost; +use Icinga\Module\Graphite\Web\Widget\Graphs\Icingadb\IcingadbHost as IcingadbHostGraphs; +use Icinga\Module\Graphite\Web\Widget\Graphs\Icingadb\IcingadbService as IcingadbServiceGraphs; abstract class Graphs extends AbstractWidget { use GraphingTrait; /** - * The Icinga custom variable with the "real" check command (if any) of monitored objects we display graphs for + * The Icinga custom variable with the "real" check command (if any) of objects we display graphs for * * @var string */ protected static $obscuredCheckCommandCustomVar; /** - * The type of the monitored object to render the graphs of + * The type of the object to render the graphs for * * @var string */ - protected $monitoredObjectType; + protected $objectType; /** - * The monitored object to render the graphs of + * The object to render the graphs for * - * @var MonitoredObject + * @var MonitoredObject|Model */ - protected $monitoredObject; + protected $object; /** * Graph image width @@ -126,7 +130,7 @@ abstract class Graphs extends AbstractWidget protected $showNoGraphsFound; /** - * Factory, based on the given object + * Factory, based on the given monitoring object * * @param MonitoredObject $object * @@ -145,6 +149,22 @@ abstract class Graphs extends AbstractWidget } } + /** + * Factory, based on the given icingadb object + * + * @param Model $object + * + * @return static + */ + public static function forIcingadbObject(Model $object) + { + if ($object instanceof IcingadbHost) { + return new IcingadbHostGraphs($object); + } + + return new IcingadbServiceGraphs($object); + } + /** * Get the Icinga custom variable with the "real" check command (if any) of monitored objects we display graphs for * @@ -163,16 +183,22 @@ abstract class Graphs extends AbstractWidget /** * Constructor * - * @param MonitoredObject $monitoredObject The monitored object to render the graphs of + * @param MonitoredObject|Model $object The object to render the graphs for */ - public function __construct(MonitoredObject $monitoredObject) + public function __construct($object) { - $this->monitoredObject = $monitoredObject; - $this->checkCommand = $monitoredObject->{"{$this->monitoredObjectType}_check_command"}; + $this->object = $object; $this->renderInline = Url::fromRequest()->getParam('format') === 'pdf'; - $this->obscuredCheckCommand = $monitoredObject->{ - "_{$this->monitoredObjectType}_" . Graphs::getObscuredCheckCommandCustomVar() - }; + + if ($object instanceof Model) { + $this->checkCommand = $object->checkcommand; + $this->obscuredCheckCommand = $object->vars[Graphs::getObscuredCheckCommandCustomVar()] ?? null; + } else { + $this->checkCommand = $object->{"{$this->objectType}_check_command"}; + $this->obscuredCheckCommand = $object->{ + "_{$this->objectType}_" . Graphs::getObscuredCheckCommandCustomVar() + }; + } } /** @@ -235,13 +261,13 @@ abstract class Graphs extends AbstractWidget IPT::indent(); foreach ($templates as $templateName => $template) { - if ($this->designedForMyMonitoredObjectType($template)) { + if ($this->designedForObjectType($template)) { IPT::recordf('Applying template %s', $templateName); IPT::indent(); $charts = $template->getCharts( static::getMetricsDataSource(), - $this->monitoredObject, + $this->object, [], $excludeMetrics ); @@ -463,13 +489,13 @@ abstract class Graphs extends AbstractWidget abstract protected function filterImageUrl(Url $url); /** - * Return whether the given template is designed for the type of the monitored object we display graphs for + * Return whether the given template is designed for the type of the object we display graphs for * * @param Template $template * * @return bool */ - abstract protected function designedForMyMonitoredObjectType(Template $template); + abstract protected function designedForObjectType(Template $template); /** * Get {@link compact} diff --git a/library/Graphite/Web/Widget/Graphs/Host.php b/library/Graphite/Web/Widget/Graphs/Host.php index 408f587..2247bcc 100644 --- a/library/Graphite/Web/Widget/Graphs/Host.php +++ b/library/Graphite/Web/Widget/Graphs/Host.php @@ -9,14 +9,14 @@ use Icinga\Web\Url; class Host extends Graphs { - protected $monitoredObjectType = 'host'; + protected $objectType = 'host'; /** * The host to render the graphs of * * @var MonitoredHost */ - protected $monitoredObject; + protected $object; protected function getImageBaseUrl() { @@ -25,20 +25,20 @@ class Host extends Graphs protected function getGraphsListBaseUrl() { - return Url::fromPath('graphite/list/hosts', ['host' => $this->monitoredObject->getName()]); + return Url::fromPath('graphite/list/hosts', ['host' => $this->object->getName()]); } protected function filterImageUrl(Url $url) { - return $url->setParam('host.name', $this->monitoredObject->getName()); + return $url->setParam('host.name', $this->object->getName()); } protected function getMonitoredObjectIdentifier() { - return $this->monitoredObject->getName(); + return $this->object->getName(); } - protected function designedForMyMonitoredObjectType(Template $template) + protected function designedForObjectType(Template $template) { foreach ($template->getCurves() as $curve) { if (in_array('host_name_template', $curve[0]->getMacros())) { diff --git a/library/Graphite/Web/Widget/Graphs/Service.php b/library/Graphite/Web/Widget/Graphs/Service.php index c464c0a..5fc0143 100644 --- a/library/Graphite/Web/Widget/Graphs/Service.php +++ b/library/Graphite/Web/Widget/Graphs/Service.php @@ -9,14 +9,14 @@ use Icinga\Web\Url; class Service extends Graphs { - protected $monitoredObjectType = 'service'; + protected $objectType = 'service'; /** - * The service to render the graphs of + * The service to render the graphs for * * @var MonitoredService */ - protected $monitoredObject; + protected $object; protected function getImageBaseUrl() { @@ -27,23 +27,23 @@ class Service extends Graphs { return Url::fromPath( 'graphite/list/services', - ['host' => $this->monitoredObject->getHost()->getName(), 'service' => $this->monitoredObject->getName()] + ['host' => $this->object->getHost()->getName(), 'service' => $this->object->getName()] ); } protected function filterImageUrl(Url $url) { return $url - ->setParam('host.name', $this->monitoredObject->getHost()->getName()) - ->setParam('service.name', $this->monitoredObject->getName()); + ->setParam('host.name', $this->object->getHost()->getName()) + ->setParam('service.name', $this->object->getName()); } protected function getMonitoredObjectIdentifier() { - return $this->monitoredObject->getHost()->getName() . ':' . $this->monitoredObject->getName(); + return $this->object->getHost()->getName() . ':' . $this->object->getName(); } - protected function designedForMyMonitoredObjectType(Template $template) + protected function designedForObjectType(Template $template) { foreach ($template->getCurves() as $curve) { if (in_array('service_name_template', $curve[0]->getMacros())) {