IcingaServiceForm: add blacklist/delete button...

...and a lot of related boilerplate to get the "blacklist" feature working
This commit is contained in:
Thomas Gelf 2018-05-25 17:03:33 +02:00
parent ba5e595fd0
commit 8073128d0e
7 changed files with 271 additions and 9 deletions

View File

@ -3,6 +3,7 @@
namespace Icinga\Module\Director\Forms; namespace Icinga\Module\Director\Forms;
use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\Filter;
use Icinga\Exception\IcingaException;
use Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
use Icinga\Module\Director\Data\PropertiesFilter\ArrayCustomVariablesFilter; use Icinga\Module\Director\Data\PropertiesFilter\ArrayCustomVariablesFilter;
use Icinga\Module\Director\Exception\NestingError; use Icinga\Module\Director\Exception\NestingError;
@ -43,6 +44,11 @@ class IcingaServiceForm extends DirectorObjectForm
return $this; return $this;
} }
/**
* @throws IcingaException
* @throws ProgrammingError
* @throws \Zend_Form_Exception
*/
public function setup() public function setup()
{ {
if ($this->providesOverrides()) { if ($this->providesOverrides()) {
@ -79,6 +85,27 @@ class IcingaServiceForm extends DirectorObjectForm
|| ($this->object && $this->object->usesVarOverrides()); || ($this->object && $this->object->usesVarOverrides());
} }
/**
* @throws IcingaException
* @throws ProgrammingError
* @throws \Zend_Form_Exception
*/
protected function addFields()
{
if ($this->providesOverrides() && $this->hasBeenBlacklisted()) {
$this->onAddedFields();
return;
} else {
parent::addFields();
}
}
/**
* @throws IcingaException
* @throws ProgrammingError
* @throws \Zend_Form_Exception
*/
protected function onAddedFields() protected function onAddedFields()
{ {
if (! $this->providesOverrides()) { if (! $this->providesOverrides()) {
@ -106,8 +133,140 @@ class IcingaServiceForm extends DirectorObjectForm
$this->setSubmitLabel(false); $this->setSubmitLabel(false);
} }
if ($this->hasBeenBlacklisted()) {
$this->addDeleteButton($this->translate('Restore'));
} else {
$this->addDeleteButton($this->translate('Blacklist'));
}
if (! $this->hasSubmitButton()) {
$this->addDisplayGroup([$this->deleteButtonName], 'buttons', [
'decorators' => [
'FormElements',
['HtmlTag', ['tag' => 'dl']],
'DtDdWrapper',
],
'order' => 1000,
]);
}
} }
/**
* @param IcingaService $service
* @return IcingaService
* @throws ProgrammingError
*/
protected function getFirstParent(IcingaService $service)
{
$objects = $service->imports()->getObjects();
if (empty($objects)) {
throw new ProgrammingError('Something went wrong, got no parent');
}
reset($objects);
return current($objects);
}
/**
* @return bool
* @throws IcingaException
* @throws ProgrammingError
*/
protected function hasBeenBlacklisted()
{
if (! $this->providesOverrides() || $this->object === null) {
return false;
}
$host = $this->host;
$service = $this->getFirstParent($this->object);
$db = $this->db->getDbAdapter();
if ($this->providesOverrides()) {
return 1 === (int) $db->fetchOne(
$db->select()->from('icinga_host_service_blacklist', 'COUNT(*)')
->where('host_id = ?', $host->get('id'))
->where('service_id = ?', $service->get('id'))
);
} else {
return false;
}
}
/**
* @param $object
* @throws IcingaException
* @throws ProgrammingError
* @throws \Zend_Db_Adapter_Exception
*/
protected function deleteObject($object)
{
/** @var IcingaService $object */
if ($this->providesOverrides()) {
if ($this->hasBeenBlacklisted()) {
$this->removeFromBlacklist();
} else {
$this->blacklist();
}
} else {
parent::deleteObject($object);
}
}
/**
* @throws IcingaException
* @throws ProgrammingError
* @throws \Zend_Db_Adapter_Exception
*/
protected function blacklist()
{
$host = $this->host;
$service = $this->getFirstParent($this->object);
$db = $this->db->getDbAdapter();
$host->unsetOverriddenServiceVars($service)->store();
if ($db->insert('icinga_host_service_blacklist', [
'host_id' => $host->get('id'),
'service_id' => $service->get('id')
])) {
$msg = sprintf(
$this->translate('%s has been blacklisted on %s'),
$service->getObjectName(),
$host->getObjectName()
);
$this->redirectOnSuccess($msg);
}
}
/**
* @throws IcingaException
* @throws ProgrammingError
*/
protected function removeFromBlacklist()
{
$host = $this->host;
$service = $this->getFirstParent($this->object);
$db = $this->db->getDbAdapter();
$where = implode(' AND ', [
$db->quoteInto('host_id = ?', $host->get('id')),
$db->quoteInto('service_id = ?', $service->get('id')),
]);
if ($db->delete('icinga_host_service_blacklist', $where)) {
$msg = sprintf(
$this->translate('%s has been removed from blacklist %s'),
$service->getObjectName(),
$host->getObjectName()
);
$this->redirectOnSuccess($msg);
}
}
/**
* @param IcingaService $service
* @return $this
* @throws ProgrammingError
*/
public function createApplyRuleFor(IcingaService $service) public function createApplyRuleFor(IcingaService $service)
{ {
$this->apply = $service; $this->apply = $service;
@ -118,6 +277,9 @@ class IcingaServiceForm extends DirectorObjectForm
return $this; return $this;
} }
/**
* @throws \Zend_Form_Exception
*/
protected function setupServiceElements() protected function setupServiceElements()
{ {
if ($this->object) { if ($this->object) {
@ -144,6 +306,10 @@ class IcingaServiceForm extends DirectorObjectForm
->setButtons(); ->setButtons();
} }
/**
* @throws IcingaException
* @throws ProgrammingError
*/
protected function addOverrideHint() protected function addOverrideHint()
{ {
if ($this->object && $this->object->usesVarOverrides()) { if ($this->object && $this->object->usesVarOverrides()) {
@ -204,6 +370,10 @@ class IcingaServiceForm extends DirectorObjectForm
$this->addHtmlHint($hint, ['name' => 'inheritance_hint']); $this->addHtmlHint($hint, ['name' => 'inheritance_hint']);
} }
/**
* @throws IcingaException
* @throws ProgrammingError
*/
protected function setupOnHostForSet() protected function setupOnHostForSet()
{ {
$msg = $this->translate( $msg = $this->translate(
@ -248,6 +418,9 @@ class IcingaServiceForm extends DirectorObjectForm
return $this; return $this;
} }
/**
* @throws \Zend_Form_Exception
*/
protected function setupHostRelatedElements() protected function setupHostRelatedElements()
{ {
$this->addHidden('host_id', $this->host->id); $this->addHidden('host_id', $this->host->id);
@ -291,6 +464,9 @@ class IcingaServiceForm extends DirectorObjectForm
return $this; return $this;
} }
/**
* @throws \Zend_Form_Exception
*/
protected function setupSetRelatedElements() protected function setupSetRelatedElements()
{ {
$this->addHidden('service_set_id', $this->set->id); $this->addHidden('service_set_id', $this->set->id);
@ -333,6 +509,10 @@ class IcingaServiceForm extends DirectorObjectForm
return $this; return $this;
} }
/**
* @return $this
* @throws \Zend_Form_Exception
*/
protected function addNameElement() protected function addNameElement()
{ {
$this->addElement('text', 'object_name', array( $this->addElement('text', 'object_name', array(
@ -350,6 +530,10 @@ class IcingaServiceForm extends DirectorObjectForm
return $this; return $this;
} }
/**
* @return $this
* @throws \Zend_Form_Exception
*/
protected function addHostObjectElement() protected function addHostObjectElement()
{ {
if ($this->isObject()) { if ($this->isObject()) {
@ -366,6 +550,10 @@ class IcingaServiceForm extends DirectorObjectForm
return $this; return $this;
} }
/**
* @return $this
* @throws \Zend_Form_Exception
*/
protected function addApplyForElement() protected function addApplyForElement()
{ {
if ($this->object->isApplyRule()) { if ($this->object->isApplyRule()) {
@ -392,6 +580,10 @@ class IcingaServiceForm extends DirectorObjectForm
return $this; return $this;
} }
/**
* @return $this
* @throws \Zend_Form_Exception
*/
protected function addGroupsElement() protected function addGroupsElement()
{ {
$groups = $this->enumServicegroups(); $groups = $this->enumServicegroups();
@ -415,6 +607,10 @@ class IcingaServiceForm extends DirectorObjectForm
return $this; return $this;
} }
/**
* @return $this
* @throws \Zend_Form_Exception
*/
protected function addAgentAndZoneElements() protected function addAgentAndZoneElements()
{ {
if (!$this->isTemplate()) { if (!$this->isTemplate()) {
@ -470,6 +666,10 @@ class IcingaServiceForm extends DirectorObjectForm
return $db->fetchPairs($select); return $db->fetchPairs($select);
} }
/**
* @throws IcingaException
* @throws ProgrammingError
*/
protected function succeedForOverrides() protected function succeedForOverrides()
{ {
$vars = array(); $vars = array();
@ -502,6 +702,10 @@ class IcingaServiceForm extends DirectorObjectForm
$this->redirectOnSuccess($msg); $this->redirectOnSuccess($msg);
} }
/**
* @throws IcingaException
* @throws ProgrammingError
*/
public function onSuccess() public function onSuccess()
{ {
if ($this->providesOverrides()) { if ($this->providesOverrides()) {

View File

@ -6,6 +6,7 @@ use Icinga\Exception\ProgrammingError;
use Icinga\Module\Director\CustomVariable\CustomVariable; use Icinga\Module\Director\CustomVariable\CustomVariable;
use Icinga\Module\Director\Db; use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Objects\IcingaObject;
use Icinga\Module\Director\Resolver\HostServiceBlacklist;
use Icinga\Module\Director\Resolver\TemplateTree; use Icinga\Module\Director\Resolver\TemplateTree;
/** /**
@ -31,6 +32,8 @@ class PrefetchCache
protected $templateTrees = array(); protected $templateTrees = array();
protected $hostServiceBlacklist;
public static function initialize(Db $db) public static function initialize(Db $db)
{ {
self::$instance = new static($db); self::$instance = new static($db);
@ -101,6 +104,15 @@ class PrefetchCache
} }
} }
public function hostServiceBlacklist()
{
if ($this->hostServiceBlacklist === null) {
$this->hostServiceBlacklist = new HostServiceBlacklist($this->db);
}
return $this->hostServiceBlacklist;
}
/** /**
* @param IcingaObject $object * @param IcingaObject $object
* @return CustomVariableCache * @return CustomVariableCache

View File

@ -412,7 +412,7 @@ class IcingaService extends IcingaObject
$blacklist = $this->getBlacklistedHostnames(); $blacklist = $this->getBlacklistedHostnames();
if (! empty($blacklist)) { if (! empty($blacklist)) {
$output .= sprintf( $output .= sprintf(
" ignore where host.name IN %s\n", " ignore where host.name in %s\n",
c::renderArray($blacklist) c::renderArray($blacklist)
); );
} }

View File

@ -781,14 +781,15 @@ abstract class DirectorObjectForm extends DirectorForm
} catch (Exception $e) { } catch (Exception $e) {
$this->addUniqueException($e); $this->addUniqueException($e);
} }
if ($this->shouldBeDeleted()) {
$this->deleteObject($this->object());
}
} }
protected function handlePost() protected function handlePost()
{ {
$object = $this->object(); $object = $this->object();
if ($this->shouldBeDeleted()) {
$this->deleteObject($object);
}
$post = $this->getRequest()->getPost(); $post = $this->getRequest()->getPost();
$this->populate($post); $this->populate($post);

View File

@ -52,6 +52,12 @@ class IcingaHostAppliedServicesTable extends SimpleQueryBasedTable
public function renderRow($row) public function renderRow($row)
{ {
if ($row->blacklisted === 'y') {
$attributes = ['class' => 'strike-links'];
} else {
$attributes = null;
}
return $this::row([ return $this::row([
Link::create( Link::create(
sprintf( sprintf(
@ -65,7 +71,7 @@ class IcingaHostAppliedServicesTable extends SimpleQueryBasedTable
'service_id' => $row->id, 'service_id' => $row->id,
] ]
) )
]); ], $attributes);
} }
public function prepareQuery() public function prepareQuery()
@ -82,7 +88,8 @@ class IcingaHostAppliedServicesTable extends SimpleQueryBasedTable
return $ds->select()->columns([ return $ds->select()->columns([
'id' => 'id', 'id' => 'id',
'name' => 'name', 'name' => 'name',
'filter' => 'filter', 'filter' => 'filter',
'blacklisted' => 'blacklisted',
'assign_filter' => 'assign_filter', 'assign_filter' => 'assign_filter',
]); ]);
} }
@ -108,8 +115,13 @@ class IcingaHostAppliedServicesTable extends SimpleQueryBasedTable
'id' => 's.id', 'id' => 's.id',
'name' => 's.object_name', 'name' => 's.object_name',
'assign_filter' => 's.assign_filter', 'assign_filter' => 's.assign_filter',
'blacklisted' => "CASE WHEN hsb.service_id IS NULL THEN 'n' ELSE 'y' END",
] ]
)->where('object_type = ? AND assign_filter IS NOT NULL', 'apply'); )->joinLeft(
['hsb' => 'icinga_host_service_blacklist'],
's.id = hsb.service_id',
[]
)->group('s.id')->where('object_type = ? AND assign_filter IS NOT NULL', 'apply');
return $db->fetchAll($query); return $db->fetchAll($query);
} }

View File

@ -78,6 +78,12 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable
return $parent; return $parent;
} }
/**
* @param $row
* @return Link
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
protected function getServiceLink($row) protected function getServiceLink($row)
{ {
if ($this->affectedHost) { if ($this->affectedHost) {
@ -111,6 +117,9 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable
if ($row->disabled === 'y') { if ($row->disabled === 'y') {
$tr->getAttributes()->add('class', 'disabled'); $tr->getAttributes()->add('class', 'disabled');
} }
if ($row->blacklisted === 'y') {
$tr->getAttributes()->add('class', 'strike-links');
}
return $tr; return $tr;
} }
@ -125,6 +134,11 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable
return $this->title ?: $this->translate('Servicename'); return $this->title ?: $this->translate('Servicename');
} }
/**
* @param HtmlElement $parent
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\ProgrammingError
*/
protected function addHostHeaderTo(HtmlElement $parent) protected function addHostHeaderTo(HtmlElement $parent)
{ {
if (! $this->host) { if (! $this->host) {
@ -164,9 +178,14 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable
$parent->add($this::th([$this->getTitle(), $deleteLink])); $parent->add($this::th([$this->getTitle(), $deleteLink]));
} }
/**
* @return \Zend_Db_Select
* @throws \Icinga\Exception\IcingaException
* @throws \Zend_Db_Select_Exception
*/
public function prepareQuery() public function prepareQuery()
{ {
return $this->db()->select()->from( $query = $this->db()->select()->from(
['s' => 'icinga_service'], ['s' => 'icinga_service'],
[ [
'id' => 's.id', 'id' => 's.id',
@ -185,5 +204,19 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable
's.service_set_id = ?', 's.service_set_id = ?',
$this->set->get('id') $this->set->get('id')
)->order('s.object_name'); )->order('s.object_name');
if ($this->affectedHost) {
$query->joinLeft(
['hsb' => 'icinga_host_service_blacklist'],
's.id = hsb.service_id',
[]
)->group('s.id')->columns([
'blacklisted' => "CASE WHEN hsb.service_id IS NULL THEN 'n' ELSE 'y' END",
]);
} else {
$query->columns(['blacklisted' => "'n'"]);
}
return $query;
} }
} }

View File

@ -380,7 +380,7 @@ form dl {
padding: 0; padding: 0;
} }
.strike-links a { .strike-links a, table.common-table .strike-links a {
text-decoration: line-through; text-decoration: line-through;
&:hover { &:hover {
text-decoration: line-through; text-decoration: line-through;