HostServiceRedirector: new implementation for...

...service links. Fallback route and more

fixes #689
This commit is contained in:
Thomas Gelf 2018-05-22 20:34:57 +02:00
parent d5807495a0
commit 0f4fd471e2
3 changed files with 338 additions and 14 deletions

View File

@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Controllers; namespace Icinga\Module\Director\Controllers;
use dipl\Html\Html;
use Exception; use Exception;
use Icinga\Module\Director\CustomVariable\CustomVariableDictionary; use Icinga\Module\Director\CustomVariable\CustomVariableDictionary;
use Icinga\Module\Director\Db\AppliedServiceSetLoader; use Icinga\Module\Director\Db\AppliedServiceSetLoader;
@ -19,6 +20,7 @@ use Icinga\Module\Director\Web\Table\IcingaHostAppliedForServiceTable;
use Icinga\Module\Director\Web\Table\IcingaHostAppliedServicesTable; use Icinga\Module\Director\Web\Table\IcingaHostAppliedServicesTable;
use Icinga\Module\Director\Web\Table\IcingaHostServiceTable; use Icinga\Module\Director\Web\Table\IcingaHostServiceTable;
use Icinga\Module\Director\Web\Table\IcingaServiceSetServiceTable; use Icinga\Module\Director\Web\Table\IcingaServiceSetServiceTable;
use Icinga\Module\Director\Web\Widget\HostServiceRedirector;
use Icinga\Web\Url; use Icinga\Web\Url;
use dipl\Html\Link; use dipl\Html\Link;
@ -29,6 +31,10 @@ class HostController extends ObjectController
$this->assertPermission('director/hosts'); $this->assertPermission('director/hosts');
} }
/**
* @return HostgroupRestriction
* @throws \Icinga\Exception\ConfigurationError
*/
protected function getHostgroupRestriction() protected function getHostgroupRestriction()
{ {
return new HostgroupRestriction($this->db(), $this->Auth()); return new HostgroupRestriction($this->db(), $this->Auth());
@ -40,6 +46,12 @@ class HostController extends ObjectController
$this->addOptionalMonitoringLink(); $this->addOptionalMonitoringLink();
} }
/**
* @throws \Icinga\Exception\ConfigurationError
* @throws \Icinga\Exception\Http\HttpNotFoundException
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
public function serviceAction() public function serviceAction()
{ {
$host = $this->getHostObject(); $host = $this->getHostObject();
@ -53,6 +65,12 @@ class HostController extends ObjectController
); );
} }
/**
* @throws \Icinga\Exception\ConfigurationError
* @throws \Icinga\Exception\Http\HttpNotFoundException
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
public function servicesetAction() public function servicesetAction()
{ {
$host = $this->getHostObject(); $host = $this->getHostObject();
@ -66,6 +84,11 @@ class HostController extends ObjectController
); );
} }
/**
* @throws \Icinga\Exception\Http\HttpNotFoundException
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
protected function addServicesHeader() protected function addServicesHeader()
{ {
$host = $this->getHostObject(); $host = $this->getHostObject();
@ -85,6 +108,40 @@ class HostController extends ObjectController
)); ));
} }
/**
* @throws \Icinga\Exception\ConfigurationError
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
public function findserviceAction()
{
$host = $this->getHostObject();
$redirector = new HostServiceRedirector($host);
$this->redirectNow(
$redirector->getRedirectionUrl($this->params->get('service'))
);
}
/**
* @throws \Icinga\Exception\IcingaException
*/
public function invalidserviceAction()
{
$this->content()->add(
Html::tag('p', ['class' => 'error'], sprintf(
$this->translate('No such service: %s'),
$this->params->get('service')
))
);
$this->servicesAction();
}
/**
* @throws \Icinga\Exception\ConfigurationError
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
public function servicesAction() public function servicesAction()
{ {
$this->addServicesHeader(); $this->addServicesHeader();
@ -149,6 +206,12 @@ class HostController extends ObjectController
} }
} }
/**
* @param IcingaHost $host
* @param IcingaHost|null $affectedHost
* @throws \Icinga\Exception\ConfigurationError
* @throws \Icinga\Exception\IcingaException
*/
protected function addHostServiceSetTables(IcingaHost $host, IcingaHost $affectedHost = null) protected function addHostServiceSetTables(IcingaHost $host, IcingaHost $affectedHost = null)
{ {
$db = $this->db(); $db = $this->db();
@ -183,6 +246,12 @@ class HostController extends ObjectController
} }
} }
/**
* @throws \Icinga\Exception\ConfigurationError
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\NotFoundError
* @throws \Icinga\Exception\ProgrammingError
*/
public function appliedserviceAction() public function appliedserviceAction()
{ {
$db = $this->db(); $db = $this->db();
@ -216,6 +285,12 @@ class HostController extends ObjectController
$this->commonForServices(); $this->commonForServices();
} }
/**
* @throws \Icinga\Exception\ConfigurationError
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\NotFoundError
* @throws \Icinga\Exception\ProgrammingError
*/
public function inheritedserviceAction() public function inheritedserviceAction()
{ {
$db = $this->db(); $db = $this->db();
@ -252,6 +327,12 @@ class HostController extends ObjectController
$this->commonForServices(); $this->commonForServices();
} }
/**
* @throws \Icinga\Exception\ConfigurationError
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\NotFoundError
* @throws \Icinga\Exception\ProgrammingError
*/
public function removesetAction() public function removesetAction()
{ {
// TODO: clean this up, use POST // TODO: clean this up, use POST
@ -276,6 +357,13 @@ class HostController extends ObjectController
); );
} }
/**
* @throws \Icinga\Exception\ConfigurationError
* @throws \Icinga\Exception\Http\HttpNotFoundException
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\NotFoundError
* @throws \Icinga\Exception\ProgrammingError
*/
public function servicesetserviceAction() public function servicesetserviceAction()
{ {
$db = $this->db(); $db = $this->db();
@ -314,6 +402,11 @@ class HostController extends ObjectController
$this->commonForServices(); $this->commonForServices();
} }
/**
* @throws \Icinga\Exception\Http\HttpNotFoundException
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
protected function commonForServices() protected function commonForServices()
{ {
$host = $this->object; $host = $this->object;
@ -326,6 +419,12 @@ class HostController extends ObjectController
$this->tabs()->activate('services'); $this->tabs()->activate('services');
} }
/**
* @throws \Icinga\Exception\Http\HttpNotFoundException
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\NotFoundError
* @throws \Icinga\Exception\ProgrammingError
*/
public function agentAction() public function agentAction()
{ {
$selfService = new SelfService($this->getHostObject(), $this->api()); $selfService = new SelfService($this->getHostObject(), $this->api());
@ -365,6 +464,10 @@ class HostController extends ObjectController
} }
} }
/**
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
protected function addOptionalInspectLink() protected function addOptionalInspectLink()
{ {
if (! $this->hasPermission('director/inspect')) { if (! $this->hasPermission('director/inspect')) {

View File

@ -5,6 +5,7 @@ namespace Icinga\Module\Director\ProvidedHook\Monitoring;
use Exception; use Exception;
use Icinga\Application\Config; use Icinga\Application\Config;
use Icinga\Module\Director\Db; use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Util; use Icinga\Module\Director\Util;
use Icinga\Module\Monitoring\Hook\ServiceActionsHook; use Icinga\Module\Monitoring\Hook\ServiceActionsHook;
use Icinga\Module\Monitoring\Object\Service; use Icinga\Module\Monitoring\Object\Service;
@ -17,31 +18,41 @@ class ServiceActions extends ServiceActionsHook
try { try {
return $this->getThem($service); return $this->getThem($service);
} catch (Exception $e) { } catch (Exception $e) {
return array(); return [];
} }
} }
/**
* @param Service $service
* @return array
* @throws \Icinga\Exception\ProgrammingError
*/
protected function getThem(Service $service) protected function getThem(Service $service)
{ {
$actions = array(); $actions = [];
$db = $this->db(); $db = $this->db();
if (! $db) { if (! $db) {
return array(); return [];
} }
$hostname = $service->host_name;
if (Util::hasPermission('director/inspect')) { if (Util::hasPermission('director/inspect')) {
$actions['Inspect'] = Url::fromPath( $actions['Inspect'] = Url::fromPath('director/inspect/object', [
'director/inspect/object',
array(
'type' => 'service', 'type' => 'service',
'plural' => 'services', 'plural' => 'services',
'name' => sprintf( 'name' => sprintf(
'%s!%s', '%s!%s',
$service->host_name, $hostname,
$service->service_description $service->service_description
) )
) ]);
); }
if (IcingaHost::exists($hostname, $db)) {
$actions['Modify'] = Url::fromPath('director/host/findservice', [
'name' => $hostname,
'service' => $service->service_description
]);
} }
return $actions; return $actions;

View File

@ -0,0 +1,210 @@
<?php
namespace Icinga\Module\Director\Web\Widget;
use dipl\Web\Url;
use Icinga\Data\Filter\Filter;
use Icinga\Module\Director\Objects\HostApplyMatches;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaService;
use Icinga\Module\Director\Repository\IcingaTemplateRepository;
class HostServiceRedirector
{
/** @var IcingaHost */
protected $host;
/** @var IcingaHost[] */
protected $parents;
/** @var HostApplyMatches */
protected $applyMatcher;
/** @var \Icinga\Module\Director\Db */
protected $db;
public function __construct(IcingaHost $host)
{
$this->host = $host;
$this->db = $host->getConnection();
}
/**
* @param $serviceName
* @return Url
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
public function getRedirectionUrl($serviceName)
{
if ($url = $this->getSingleServiceUrl($serviceName)) {
return $url;
} elseif ($url = $this->getParentServiceUrl($serviceName)) {
return $url;
} elseif ($url = $this->getAppliedServiceUrl($serviceName)) {
return $url;
} elseif ($url = $this->getServiceSetServiceUrl($serviceName)) {
return $url;
}
return Url::fromPath('director/host/invalidservice', [
'name' => $this->host->getObjectName(),
'service' => $serviceName,
]);
}
/**
* @return IcingaHost[]
* @throws \Icinga\Exception\ProgrammingError
*/
protected function getParents()
{
if ($this->parents === null) {
$this->parents = IcingaTemplateRepository::instanceByObject(
$this->host
)->getTemplatesFor($this->host, true);
}
return $this->parents;
}
/**
* @param $serviceName
* @return Url|null
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
protected function getSingleServiceUrl($serviceName)
{
if (IcingaService::exists([
'host_id' => $this->host->get('id'),
'object_name' => $serviceName
], $this->db)) {
return Url::fromPath('director/service/edit', [
'name' => $serviceName,
'host' => $this->host->getObjectName()
]);
}
return null;
}
/**
* @param $serviceName
* @return Url|null
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
protected function getParentServiceUrl($serviceName)
{
foreach ($this->getParents() as $parent) {
if (IcingaService::exists([
'host_id' => $parent->get('id'),
'object_name' => $serviceName
], $this->db)) {
return Url::fromPath('director/host/inheritedservice', [
'name' => $this->host->getObjectName(),
'service' => $serviceName,
'inheritedFrom' => $parent->getObjectName()
]);
}
}
return null;
}
/**
* @param $serviceName
* @return Url|null
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
protected function getServiceSetServiceUrl($serviceName)
{
$ids = [$this->host->get('id')];
foreach ($this->getParents() as $parent) {
$ids[] = $parent->get('id');
}
$db = $this->db->getDbAdapter();
$query = $db->select()
->from(
['s' => 'icinga_service'],
['service_set_name' => 'ss.object_name',]
)->join(
['ss' => 'icinga_service_set'],
's.service_set_id = ss.id',
[]
)->join(
['hsi' => 'icinga_service_set_inheritance'],
'hsi.parent_service_set_id = ss.id',
[]
)->join(
['hs' => 'icinga_service_set'],
'hs.id = hsi.service_set_id',
[]
)->where('hs.host_id IN (?)', $ids)
->where('s.object_name = ?', $serviceName);
if ($row = $db->fetchRow($query)) {
return Url::fromPath('director/host/servicesetservice', [
'name' => $this->host->getObjectName(),
'service' => $serviceName,
'set' => $row->service_set_name
]);
}
return null;
}
/**
* @param $serviceName
* @return Url|null
* @throws \Icinga\Exception\ProgrammingError
*/
protected function getAppliedServiceUrl($serviceName)
{
$matcher = $this->getHostApplyMatcher();
foreach ($this->fetchAllApplyRulesForService($serviceName) as $rule) {
if ($matcher->matchesFilter($rule->filter)) {
return Url::fromPath('director/host/appliedservice', [
'name' => $this->host->getObjectName(),
'service_id' => $rule->id,
]);
}
}
return null;
}
protected function getHostApplyMatcher()
{
if ($this->applyMatcher === null) {
$this->applyMatcher = HostApplyMatches::prepare($this->host);
}
return $this->applyMatcher;
}
protected function fetchAllApplyRulesForService($serviceName)
{
$db = $this->db->getDbAdapter();
$query = $db->select()->from(
['s' => 'icinga_service'],
[
'id' => 's.id',
'name' => 's.object_name',
'assign_filter' => 's.assign_filter',
]
)->where('object_name = ?', $serviceName)
->where('object_type = ? AND assign_filter IS NOT NULL', 'apply');
$allRules = $db->fetchAll($query);
foreach ($allRules as $rule) {
$rule->filter = Filter::fromQueryString($rule->assign_filter);
}
return $allRules;
}
}