parent
6add437dce
commit
99ddb9266b
|
@ -2,13 +2,18 @@
|
|||
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use dipl\Html\Html;
|
||||
use Icinga\Module\Director\Forms\IcingaCommandArgumentForm;
|
||||
use Icinga\Module\Director\Objects\IcingaCommand;
|
||||
use Icinga\Module\Director\Resolver\CommandUsage;
|
||||
use Icinga\Module\Director\Web\Controller\ObjectController;
|
||||
use Icinga\Module\Director\Web\Table\IcingaCommandArgumentTable;
|
||||
|
||||
class CommandController extends ObjectController
|
||||
{
|
||||
/**
|
||||
* @throws \Icinga\Exception\ProgrammingError
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
@ -22,6 +27,56 @@ class CommandController extends ObjectController
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Icinga\Exception\ProgrammingError
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$this->showUsage();
|
||||
parent::indexAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Icinga\Exception\ProgrammingError
|
||||
*/
|
||||
public function renderAction()
|
||||
{
|
||||
if ($this->object->isExternal()) {
|
||||
$this->showUsage();
|
||||
}
|
||||
|
||||
parent::renderAction();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Icinga\Exception\ProgrammingError
|
||||
*/
|
||||
protected function showUsage()
|
||||
{
|
||||
/** @var IcingaCommand $command */
|
||||
$command = $this->object;
|
||||
if ($command->isInUse()) {
|
||||
$usage = new CommandUsage($command);
|
||||
$this->content()->add(Html::tag('p', [
|
||||
'class' => 'information',
|
||||
'data-base-target' => '_next'
|
||||
], Html::sprintf(
|
||||
$this->translate('This Command is currently being used by %s'),
|
||||
Html::tag('span', null, $usage->getLinks())->setSeparator(', ')
|
||||
)));
|
||||
} else {
|
||||
$this->content()->add(Html::tag(
|
||||
'p',
|
||||
['class' => 'warning'],
|
||||
$this->translate('This Command is currently not in use')
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Icinga\Exception\Http\HttpNotFoundException
|
||||
* @throws \Icinga\Exception\ProgrammingError
|
||||
*/
|
||||
public function argumentsAction()
|
||||
{
|
||||
$p = $this->params;
|
||||
|
|
|
@ -23,6 +23,7 @@ before switching to a new version.
|
|||
* FEATURE: Users equipped with related permissions can toggle "Show SQL" in the GUI
|
||||
* FEATURE: A Service Set can now be assigned to multiple hosts at once #1281
|
||||
* FEATURE: Commands can now be filtered by usage (#1480)
|
||||
* FEATURE: Show usage of Commands over templates and objects (#335)
|
||||
* FIX: Don't suggest Command templates where Commands are required (#1414)
|
||||
* FIX: Do not allow to delete Commands being used by other objects (#1443)
|
||||
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\Resolver;
|
||||
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Module\Director\Objects\IcingaCommand;
|
||||
use dipl\Html\Link;
|
||||
use dipl\Translation\TranslationHelper;
|
||||
|
||||
class CommandUsage
|
||||
{
|
||||
use TranslationHelper;
|
||||
|
||||
/** @var IcingaCommand */
|
||||
protected $command;
|
||||
|
||||
/** @var \Zend_Db_Adapter_Abstract */
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* CommandUsageTable constructor.
|
||||
* @param IcingaCommand $command
|
||||
* @throws ProgrammingError
|
||||
*/
|
||||
public function __construct(IcingaCommand $command)
|
||||
{
|
||||
if ($command->isTemplate()) {
|
||||
throw new ProgrammingError(
|
||||
'CommandUsageTable expects object or external_object, got a template'
|
||||
);
|
||||
}
|
||||
|
||||
$this->command = $command;
|
||||
$this->db = $command->getDb();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws ProgrammingError
|
||||
*/
|
||||
public function getLinks()
|
||||
{
|
||||
$name = $this->command->getObjectName();
|
||||
$links = [];
|
||||
$map = [
|
||||
'host' => ['check_command', 'event_command'],
|
||||
'service' => ['check_command', 'event_command'],
|
||||
'notification' => ['command'],
|
||||
];
|
||||
$types = [
|
||||
'host' => [
|
||||
'object' => $this->translate('%d Host(s)'),
|
||||
'template' => $this->translate('%d Host Template(s)'),
|
||||
],
|
||||
'service' => [
|
||||
'object' => $this->translate('%d Service(s)'),
|
||||
'template' => $this->translate('%d Service Template(s)'),
|
||||
'apply' => $this->translate('%d Service Apply Rule(s)'),
|
||||
],
|
||||
'notification' => [
|
||||
'object' => $this->translate('%d Notification(s)'),
|
||||
'template' => $this->translate('%d Notification Template(s)'),
|
||||
'apply' => $this->translate('%d Notification Apply Rule(s)'),
|
||||
],
|
||||
];
|
||||
|
||||
$urlSuffix = [
|
||||
'object' => '',
|
||||
'template' => '/templates',
|
||||
'apply' => '/applyrules',
|
||||
];
|
||||
|
||||
foreach ($map as $type => $relations) {
|
||||
$res = $this->fetchFor($type, $relations, array_keys($types[$type]));
|
||||
foreach ($types[$type] as $objectType => $caption) {
|
||||
if ($res->$objectType > 0) {
|
||||
$suffix = $urlSuffix[$objectType];
|
||||
$links[] = Link::create(
|
||||
sprintf($caption, $res->$objectType),
|
||||
"director/${type}s$suffix",
|
||||
['command' => $name]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
protected function fetchFor($table, $rels, $objectTypes)
|
||||
{
|
||||
$id = $this->command->getAutoincId();
|
||||
|
||||
$columns = [];
|
||||
foreach ($objectTypes as $type) {
|
||||
$columns[$type] = "COALESCE(SUM(CASE WHEN object_type = '$type' THEN 1 ELSE 0 END), 0)";
|
||||
}
|
||||
$query = $this->db->select()->from("icinga_$table", $columns);
|
||||
|
||||
foreach ($rels as $rel) {
|
||||
$query->orWhere("${rel}_id = ?", $id);
|
||||
}
|
||||
|
||||
return $this->db->fetchRow($query);
|
||||
}
|
||||
}
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
namespace Icinga\Module\Director\Web\Controller;
|
||||
|
||||
use dipl\Web\Table\ZfQueryBasedTable;
|
||||
use Icinga\Data\Filter\FilterChain;
|
||||
use Icinga\Data\Filter\FilterExpression;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Module\Director\Forms\IcingaMultiEditForm;
|
||||
use Icinga\Module\Director\Objects\IcingaCommand;
|
||||
use Icinga\Module\Director\Objects\IcingaHost;
|
||||
use Icinga\Module\Director\Objects\IcingaObject;
|
||||
use Icinga\Module\Director\RestApi\IcingaObjectsHandler;
|
||||
|
@ -112,7 +114,8 @@ abstract class ObjectsController extends ActionController
|
|||
}
|
||||
|
||||
// Hint: might be used in controllers extending this
|
||||
$this->table = $this->getTable();
|
||||
$this->table = $this->eventuallyFilterCommand($this->getTable());
|
||||
|
||||
$this->table->renderTo($this);
|
||||
(new AdditionalTableActions($this->getAuth(), $this->url(), $this->table))
|
||||
->appendTo($this->actions());
|
||||
|
@ -187,9 +190,13 @@ abstract class ObjectsController extends ActionController
|
|||
)
|
||||
->actions(new TemplateActionBar($shortType, $this->url()));
|
||||
|
||||
$this->params->get('render') === 'tree'
|
||||
? TemplateTreeRenderer::showType($shortType, $this, $this->db())
|
||||
: TemplatesTable::create($shortType, $this->db())->renderTo($this);
|
||||
if ($this->params->get('render') === 'tree') {
|
||||
TemplateTreeRenderer::showType($shortType, $this, $this->db());
|
||||
} else {
|
||||
$table = TemplatesTable::create($shortType, $this->db());
|
||||
$this->eventuallyFilterCommand($table);
|
||||
$table->renderTo($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -239,6 +246,7 @@ abstract class ObjectsController extends ActionController
|
|||
|
||||
$table = new ApplyRulesTable($this->db());
|
||||
$table->setType($this->getType());
|
||||
$this->eventuallyFilterCommand($table);
|
||||
$table->renderTo($this);
|
||||
}
|
||||
|
||||
|
@ -311,6 +319,37 @@ abstract class ObjectsController extends ActionController
|
|||
return $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ZfQueryBasedTable $table
|
||||
* @return ZfQueryBasedTable
|
||||
* @throws \Icinga\Exception\ConfigurationError
|
||||
*/
|
||||
protected function eventuallyFilterCommand(ZfQueryBasedTable $table)
|
||||
{
|
||||
if ($this->params->get('command')) {
|
||||
$command = IcingaCommand::load($this->params->get('command'), $this->db());
|
||||
switch ($this->getBaseType()) {
|
||||
case 'host':
|
||||
case 'service':
|
||||
$table->getQuery()->where(
|
||||
$this->db()->getDbAdapter()->quoteInto(
|
||||
'(o.check_command_id = ? OR o.event_command_id = ?)',
|
||||
$command->getAutoincId()
|
||||
)
|
||||
);
|
||||
break;
|
||||
case 'notification':
|
||||
$table->getQuery()->where(
|
||||
'o.command_id = ?',
|
||||
$command->getAutoincId()
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $feature
|
||||
* @return $this
|
||||
|
|
|
@ -1041,6 +1041,18 @@ p.warning {
|
|||
}
|
||||
}
|
||||
|
||||
p.information {
|
||||
color: white;
|
||||
padding: 1em 2em;
|
||||
background-color: @colorOk;
|
||||
font-weight: bold;
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
table.tinystats {
|
||||
font-size: 0.7em;
|
||||
float: right;
|
||||
|
|
Loading…
Reference in New Issue