ServiceFinder: replace HostServiceRedirector

This commit is contained in:
Thomas Gelf 2021-01-16 15:04:29 +01:00
parent 958b19758c
commit e4e96206b4
9 changed files with 495 additions and 270 deletions

View File

@ -10,6 +10,7 @@ use gipfl\IcingaWeb2\Widget\Tabs;
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;
use Icinga\Module\Director\DirectorObject\Lookup\ServiceFinder;
use Icinga\Module\Director\Forms\IcingaAddServiceForm; use Icinga\Module\Director\Forms\IcingaAddServiceForm;
use Icinga\Module\Director\Forms\IcingaServiceForm; use Icinga\Module\Director\Forms\IcingaServiceForm;
use Icinga\Module\Director\Forms\IcingaServiceSetForm; use Icinga\Module\Director\Forms\IcingaServiceSetForm;
@ -24,7 +25,6 @@ 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;
class HostController extends ObjectController class HostController extends ObjectController
{ {
@ -100,15 +100,12 @@ class HostController extends ObjectController
)); ));
} }
/**
* @throws \Icinga\Exception\NotFoundError
*/
public function findserviceAction() public function findserviceAction()
{ {
$host = $this->getHostObject(); $host = $this->getHostObject();
$redirector = new HostServiceRedirector($host, $this->getAuth());
$this->redirectNow( $this->redirectNow(
$redirector->getRedirectionUrl($this->params->get('service')) (new ServiceFinder($host, $this->getAuth()))
->getRedirectionUrl($this->params->get('service'))
); );
} }

View File

@ -0,0 +1,87 @@
<?php
namespace Icinga\Module\Director\DirectorObject\Lookup;
use gipfl\IcingaWeb2\Url;
use Icinga\Data\Filter\Filter;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\HostApplyMatches;
use Icinga\Module\Director\Objects\IcingaHost;
class AppliedServiceInfo implements ServiceInfo
{
/** @var string */
protected $hostName;
/** @var string */
protected $serviceName;
/** @var int */
protected $serviceApplyRuleId;
public function __construct($hostName, $serviceName, $serviceApplyRuleId)
{
$this->hostName = $hostName;
$this->serviceName= $serviceName;
$this->serviceApplyRuleId = $serviceApplyRuleId;
}
public static function find(IcingaHost $host, $serviceName)
{
$matcher = HostApplyMatches::prepare($host);
$connection = $host->getConnection();
foreach (static::fetchApplyRulesByServiceName($connection, $serviceName) as $rule) {
if ($matcher->matchesFilter($rule->filter)) {
return new static($host->getObjectName(), $serviceName, (int) $rule->id);
}
}
return null;
}
public function getHostName()
{
return $this->hostName;
}
/**
* @return int
*/
public function getServiceApplyRuleId()
{
return $this->serviceApplyRuleId;
}
public function getName()
{
return $this->serviceName;
}
public function getUrl()
{
return Url::fromPath('director/host/appliedservice', [
'name' => $this->hostName,
'service_id' => $this->serviceApplyRuleId,
]);
}
protected static function fetchApplyRulesByServiceName(Db $connection, $serviceName)
{
$db = $connection->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;
}
}

View File

@ -0,0 +1,94 @@
<?php
namespace Icinga\Module\Director\DirectorObject\Lookup;
use gipfl\IcingaWeb2\Url;
use Icinga\Data\Filter\Filter;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\HostApplyMatches;
use Icinga\Module\Director\Objects\IcingaHost;
class AppliedServiceSetServiceInfo implements ServiceInfo
{
/** @var string */
protected $hostName;
/** @var string */
protected $serviceName;
/** @var string */
protected $serviceSetName;
public function __construct($hostName, $serviceName, $serviceSetName)
{
$this->hostName = $hostName;
$this->serviceName = $serviceName;
$this->serviceSetName = $serviceSetName;
}
public static function find(IcingaHost $host, $serviceName)
{
$matcher = HostApplyMatches::prepare($host);
$connection = $host->getConnection();
foreach (static::fetchServiceSetApplyRulesByServiceName($connection, $serviceName) as $rule) {
if ($matcher->matchesFilter($rule->filter)) {
return new static($host->getObjectName(), $serviceName, $rule->service_set_name);
}
}
return null;
}
public function getHostName()
{
return $this->hostName;
}
/**
* @return string
*/
public function getServiceSetName()
{
return $this->serviceSetName;
}
public function getName()
{
return $this->serviceName;
}
public function getUrl()
{
return Url::fromPath('director/host/servicesetservice', [
'name' => $this->hostName,
'service' => $this->serviceName,
'set' => $this->serviceSetName,
]);
}
protected static function fetchServiceSetApplyRulesByServiceName(Db $connection, $serviceName)
{
$db = $connection->getDbAdapter();
$query = $db->select()
->from(['s' => 'icinga_service'], [
'id' => 's.id',
'name' => 's.object_name',
'assign_filter' => 'ss.assign_filter',
'service_set_name' => 'ss.object_name',
])
->join(
['ss' => 'icinga_service_set'],
's.service_set_id = ss.id',
[]
)
->where('s.object_name = ?', $serviceName)
->where('ss.assign_filter IS NOT NULL');
$allRules = $db->fetchAll($query);
foreach ($allRules as $rule) {
$rule->filter = Filter::fromQueryString($rule->assign_filter);
}
return $allRules;
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace Icinga\Module\Director\DirectorObject\Lookup;
use gipfl\IcingaWeb2\Url;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaService;
use Icinga\Module\Director\Repository\IcingaTemplateRepository;
class InheritedServiceInfo implements ServiceInfo
{
/** @var string */
protected $hostName;
/** @var string */
protected $hostTemplateName;
/** @var string */
protected $serviceName;
public function __construct($hostName, $hostTemplateName, $serviceName)
{
$this->hostName = $hostName;
$this->hostTemplateName = $hostTemplateName;
$this->serviceName= $serviceName;
}
public static function find(IcingaHost $host, $serviceName)
{
foreach (IcingaTemplateRepository::instanceByObject($host)->getTemplatesFor($host, true) as $parent) {
if (IcingaService::exists([
'host_id' => $parent->get('id'),
'object_name' => $serviceName
], $host->getConnection())) {
return new static(
$host->getObjectName(),
$parent->getObjectName(),
$serviceName
);
}
}
return false;
}
public function getHostName()
{
return $this->hostName;
}
/**
* @return string
*/
public function getHostTemplateName()
{
return $this->hostTemplateName;
}
public function getName()
{
return $this->serviceName;
}
public function getUrl()
{
return Url::fromPath('director/host/inheritedservice', [
'name' => $this->hostName,
'service' => $this->serviceName,
'inheritedFrom' => $this->hostTemplateName
]);
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace Icinga\Module\Director\DirectorObject\Lookup;
use gipfl\IcingaWeb2\Url;
use Icinga\Authentication\Auth;
use Icinga\Module\Director\Objects\HostApplyMatches;
use Icinga\Module\Director\Objects\IcingaHost;
class ServiceFinder
{
/** @var IcingaHost */
protected $host;
/** @var Auth */
protected $auth;
/** @var IcingaHost[] */
protected $parents;
/** @var HostApplyMatches */
protected $applyMatcher;
/** @var \Icinga\Module\Director\Db */
protected $db;
public function __construct(IcingaHost $host, Auth $auth)
{
$this->host = $host;
$this->auth = $auth;
$this->db = $host->getConnection();
}
/**
* @param $serviceName
* @return Url
*/
public function getRedirectionUrl($serviceName)
{
if ($this->auth->hasPermission('director/host')) {
foreach ([
SingleServiceInfo::class,
InheritedServiceInfo::class,
ServiceSetServiceInfo::class,
AppliedServiceInfo::class,
AppliedServiceSetServiceInfo::class,
] as $class) {
/** @var ServiceInfo $class */
if ($info = $class::find($this->host, $serviceName)) {
return $info->getUrl();
}
}
}
if ($this->auth->hasPermission('director/monitoring/services-ro')) {
return Url::fromPath('director/host/servicesro', [
'name' => $this->host->getObjectName(),
'service' => $serviceName
]);
}
return Url::fromPath('director/host/invalidservice', [
'name' => $this->host->getObjectName(),
'service' => $serviceName,
]);
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Icinga\Module\Director\DirectorObject\Lookup;
use gipfl\IcingaWeb2\Url;
use Icinga\Module\Director\Objects\IcingaHost;
interface ServiceInfo
{
/**
* The final Service name
*
* @return string
*/
public function getName();
/**
* The host the final (rendered, processed) Service belongs to
*
* @return string
*/
public function getHostName();
/**
* @return Url
*/
public function getUrl();
/**
* @param IcingaHost $host
* @param $serviceName
* @return ServiceInfo|false
*/
public static function find(IcingaHost $host, $serviceName);
}

View File

@ -0,0 +1,88 @@
<?php
namespace Icinga\Module\Director\DirectorObject\Lookup;
use gipfl\IcingaWeb2\Url;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Repository\IcingaTemplateRepository;
class ServiceSetServiceInfo implements ServiceInfo
{
/** @var string */
protected $hostName;
/** @var string */
protected $serviceName;
/** @var string */
protected $serviceSetName;
public function __construct($hostName, $serviceName, $serviceSetName)
{
$this->hostName = $hostName;
$this->serviceName = $serviceName;
$this->serviceSetName = $serviceSetName;
}
public static function find(IcingaHost $host, $serviceName)
{
$ids = [$host->get('id')];
foreach (IcingaTemplateRepository::instanceByObject($host)->getTemplatesFor($host, true) as $parent) {
$ids[] = $parent->get('id');
}
$db = $host->getConnection()->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 new static($host->getObjectName(), $serviceName, $row->service_set_name);
}
return null;
}
public function getHostName()
{
return $this->hostName;
}
public function getName()
{
return $this->serviceName;
}
/**
* @return string
*/
public function getServiceSetName()
{
return $this->serviceSetName;
}
public function getUrl()
{
return Url::fromPath('director/host/servicesetservice', [
'name' => $this->hostName,
'service' => $this->serviceName,
'set' => $this->serviceSetName,
]);
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace Icinga\Module\Director\DirectorObject\Lookup;
use gipfl\IcingaWeb2\Url;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaService;
class SingleServiceInfo implements ServiceInfo
{
protected $hostName;
protected $serviceName;
public function __construct($hostName, $serviceName)
{
$this->hostName = $hostName;
$this->serviceName= $serviceName;
}
public static function find(IcingaHost $host, $serviceName)
{
if (IcingaService::exists([
'host_id' => $host->get('id'),
'object_name' => $serviceName
], $host->getConnection())) {
return new static($host->getObjectName(), $serviceName);
}
return false;
}
public function getHostName()
{
return $this->hostName;
}
public function getName()
{
return $this->serviceName;
}
public function getUrl()
{
return Url::fromPath('director/host/service', [
'name' => $this->hostName,
'service' => $this->serviceName,
]);
}
}

View File

@ -1,264 +0,0 @@
<?php
namespace Icinga\Module\Director\Web\Widget;
use gipfl\IcingaWeb2\Url;
use Icinga\Authentication\Auth;
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 Auth */
protected $auth;
/** @var IcingaHost[] */
protected $parents;
/** @var HostApplyMatches */
protected $applyMatcher;
/** @var \Icinga\Module\Director\Db */
protected $db;
public function __construct(IcingaHost $host, Auth $auth)
{
$this->host = $host;
$this->auth = $auth;
$this->db = $host->getConnection();
}
/**
* @param $serviceName
* @return Url
* @throws \Icinga\Exception\NotFoundError
*/
public function getRedirectionUrl($serviceName)
{
if ($this->auth->hasPermission('director/host')) {
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;
} elseif ($url = $this->getAppliedServiceSetUrl($serviceName)) {
return $url;
}
} elseif ($this->auth->hasPermission('director/monitoring/services-ro')) {
return Url::fromPath('director/host/servicesro', [
'name' => $this->host->getObjectName(),
'service' => $serviceName
]);
}
return Url::fromPath('director/host/invalidservice', [
'name' => $this->host->getObjectName(),
'service' => $serviceName,
]);
}
/**
* @return IcingaHost[]
* @throws \Icinga\Exception\NotFoundError
*/
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
*/
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\NotFoundError
*/
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\NotFoundError
*/
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
*/
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;
}
/**
* @param $serviceName
* @return Url|null
*/
protected function getAppliedServiceSetUrl($serviceName)
{
$matcher = $this->getHostApplyMatcher();
foreach ($this->fetchAllServiceSetApplyRulesForService($serviceName) as $rule) {
if ($matcher->matchesFilter($rule->filter)) {
return Url::fromPath('director/host/servicesetservice', [
'name' => $this->host->getObjectName(),
'service' => $serviceName,
'set' => $rule->service_set_name
]);
}
}
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;
}
protected function fetchAllServiceSetApplyRulesForService($serviceName)
{
$db = $this->db->getDbAdapter();
$query = $db->select()->from(
['s' => 'icinga_service'],
[
'id' => 's.id',
'name' => 's.object_name',
'assign_filter' => 'ss.assign_filter',
'service_set_name' => 'ss.object_name',
]
)->join(
['ss' => 'icinga_service_set'],
's.service_set_id = ss.id',
[]
)->where('s.object_name = ?', $serviceName)
->where('ss.assign_filter IS NOT NULL');
$allRules = $db->fetchAll($query);
foreach ($allRules as $rule) {
$rule->filter = Filter::fromQueryString($rule->assign_filter);
}
return $allRules;
}
}