mirror of
https://github.com/Icinga/icingaweb2-module-director.git
synced 2025-07-28 08:14:04 +02:00
parent
83dc9dc6c3
commit
f871e0bd7d
@ -12,6 +12,7 @@ use Icinga\Module\Director\Db;
|
|||||||
use Icinga\Module\Director\DirectorObject\Automation\Basket;
|
use Icinga\Module\Director\DirectorObject\Automation\Basket;
|
||||||
use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshot;
|
use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshot;
|
||||||
use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshotFieldResolver;
|
use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshotFieldResolver;
|
||||||
|
use Icinga\Module\Director\Forms\AddToBasketForm;
|
||||||
use Icinga\Module\Director\Forms\BasketCreateSnapshotForm;
|
use Icinga\Module\Director\Forms\BasketCreateSnapshotForm;
|
||||||
use Icinga\Module\Director\Forms\BasketForm;
|
use Icinga\Module\Director\Forms\BasketForm;
|
||||||
use Icinga\Module\Director\Forms\RestoreBasketForm;
|
use Icinga\Module\Director\Forms\RestoreBasketForm;
|
||||||
@ -64,6 +65,18 @@ class BasketController extends ActionController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addAction()
|
||||||
|
{
|
||||||
|
$this->addSingleTab($this->translate('Add to Basket'));
|
||||||
|
$this->addTitle($this->translate('Add chosen objects to a Configuration Basket'));
|
||||||
|
$form = new AddToBasketForm();
|
||||||
|
$form->setDb($this->db())
|
||||||
|
->setType($this->params->getRequired('type'))
|
||||||
|
->setNames($this->url()->getParams()->getValues('names'))
|
||||||
|
->handleRequest();
|
||||||
|
$this->content()->add($form);
|
||||||
|
}
|
||||||
|
|
||||||
public function createAction()
|
public function createAction()
|
||||||
{
|
{
|
||||||
$this->actions()->add(
|
$this->actions()->add(
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
namespace Icinga\Module\Director\Controllers;
|
namespace Icinga\Module\Director\Controllers;
|
||||||
|
|
||||||
|
use dipl\Web\Url;
|
||||||
use Icinga\Data\Filter\Filter;
|
use Icinga\Data\Filter\Filter;
|
||||||
use Icinga\Data\Filter\FilterChain;
|
use Icinga\Data\Filter\FilterChain;
|
||||||
use Icinga\Data\Filter\FilterExpression;
|
use Icinga\Data\Filter\FilterExpression;
|
||||||
|
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
|
||||||
use Icinga\Module\Director\Forms\IcingaAddServiceForm;
|
use Icinga\Module\Director\Forms\IcingaAddServiceForm;
|
||||||
use Icinga\Module\Director\Forms\IcingaAddServiceSetForm;
|
use Icinga\Module\Director\Forms\IcingaAddServiceSetForm;
|
||||||
use Icinga\Module\Director\Objects\IcingaHost;
|
use Icinga\Module\Director\Objects\IcingaHost;
|
||||||
@ -47,6 +49,31 @@ class HostsController extends ObjectsController
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function edittemplatesAction()
|
||||||
|
{
|
||||||
|
parent::editAction();
|
||||||
|
|
||||||
|
$objects = $this->loadMultiObjectsFromParams();
|
||||||
|
$names = [];
|
||||||
|
/** @var ExportInterface $object */
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$names[] = $object->getUniqueIdentifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = Url::fromPath('director/basket/add', [
|
||||||
|
'type' => 'HostTemplate',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$url->getParams()->addValues('names', $names);
|
||||||
|
|
||||||
|
$this->actions()->add(Link::create(
|
||||||
|
$this->translate('Add to Basket'),
|
||||||
|
$url,
|
||||||
|
null,
|
||||||
|
['class' => 'icon-tag']
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
public function addserviceAction()
|
public function addserviceAction()
|
||||||
{
|
{
|
||||||
$this->addSingleTab($this->translate('Add Service'));
|
$this->addSingleTab($this->translate('Add Service'));
|
||||||
|
@ -49,6 +49,17 @@ class ImportsourceController extends ActionController
|
|||||||
$this->actions(new AutomationObjectActionBar(
|
$this->actions(new AutomationObjectActionBar(
|
||||||
$this->getRequest()
|
$this->getRequest()
|
||||||
));
|
));
|
||||||
|
$source = $this->getImportSource();
|
||||||
|
|
||||||
|
$this->actions()->add(Link::create(
|
||||||
|
$this->translate('Add to Basket'),
|
||||||
|
'director/basket/add',
|
||||||
|
[
|
||||||
|
'type' => 'ImportSource',
|
||||||
|
'names' => $source->getUniqueIdentifier()
|
||||||
|
],
|
||||||
|
['class' => 'icon-tag']
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Icinga\Module\Director\Controllers;
|
namespace Icinga\Module\Director\Controllers;
|
||||||
|
|
||||||
|
use dipl\Html\Link;
|
||||||
use Icinga\Module\Director\Forms\DirectorJobForm;
|
use Icinga\Module\Director\Forms\DirectorJobForm;
|
||||||
use Icinga\Module\Director\Web\Controller\ActionController;
|
use Icinga\Module\Director\Web\Controller\ActionController;
|
||||||
use Icinga\Module\Director\Objects\DirectorJob;
|
use Icinga\Module\Director\Objects\DirectorJob;
|
||||||
@ -19,6 +20,7 @@ class JobController extends ActionController
|
|||||||
$this
|
$this
|
||||||
->addJobTabs($job, 'show')
|
->addJobTabs($job, 'show')
|
||||||
->addTitle($this->translate('Job: %s'), $job->get('job_name'))
|
->addTitle($this->translate('Job: %s'), $job->get('job_name'))
|
||||||
|
->addToBasketLink()
|
||||||
->content()->add(new JobDetails($job));
|
->content()->add(new JobDetails($job));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +52,7 @@ class JobController extends ActionController
|
|||||||
$this
|
$this
|
||||||
->addJobTabs($job, 'edit')
|
->addJobTabs($job, 'edit')
|
||||||
->addTitle($this->translate('Job: %s'), $job->get('job_name'))
|
->addTitle($this->translate('Job: %s'), $job->get('job_name'))
|
||||||
|
->addToBasketLink()
|
||||||
->content()->add($form);
|
->content()->add($form);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +66,27 @@ class JobController extends ActionController
|
|||||||
return DirectorJob::loadWithAutoIncId((int) $this->params->getRequired('id'), $this->db());
|
return DirectorJob::loadWithAutoIncId((int) $this->params->getRequired('id'), $this->db());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
* @throws \Icinga\Exception\MissingParameterException
|
||||||
|
* @throws \Icinga\Exception\NotFoundError
|
||||||
|
*/
|
||||||
|
protected function addToBasketLink()
|
||||||
|
{
|
||||||
|
$job = $this->requireJob();
|
||||||
|
$this->actions()->add(Link::create(
|
||||||
|
$this->translate('Add to Basket'),
|
||||||
|
'director/basket/add',
|
||||||
|
[
|
||||||
|
'type' => 'DirectorJob',
|
||||||
|
'names' => $job->getUniqueIdentifier()
|
||||||
|
],
|
||||||
|
['class' => 'icon-tag']
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function addJobTabs(DirectorJob $job, $active)
|
protected function addJobTabs(DirectorJob $job, $active)
|
||||||
{
|
{
|
||||||
$id = $job->get('id');
|
$id = $job->get('id');
|
||||||
|
@ -45,6 +45,15 @@ class SyncruleController extends ActionController
|
|||||||
$this->addPropertyHint($rule);
|
$this->addPropertyHint($rule);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
$this->actions()->add(Link::create(
|
||||||
|
$this->translate('Add to Basket'),
|
||||||
|
'director/basket/add',
|
||||||
|
[
|
||||||
|
'type' => 'SyncRule',
|
||||||
|
'names' => $rule->getUniqueIdentifier()
|
||||||
|
],
|
||||||
|
['class' => 'icon-tag']
|
||||||
|
));
|
||||||
|
|
||||||
if (! $run) {
|
if (! $run) {
|
||||||
$this->warning($this->translate('This Sync Rule has never been run before.'));
|
$this->warning($this->translate('This Sync Rule has never been run before.'));
|
||||||
@ -159,6 +168,15 @@ class SyncruleController extends ActionController
|
|||||||
['class' => 'icon-paste']
|
['class' => 'icon-paste']
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
$this->actions()->add(Link::create(
|
||||||
|
$this->translate('Add to Basket'),
|
||||||
|
'director/basket/add',
|
||||||
|
[
|
||||||
|
'type' => 'SyncRule',
|
||||||
|
'names' => $rule->getUniqueIdentifier()
|
||||||
|
],
|
||||||
|
['class' => 'icon-tag']
|
||||||
|
));
|
||||||
|
|
||||||
if (! $rule->hasSyncProperties()) {
|
if (! $rule->hasSyncProperties()) {
|
||||||
$this->addPropertyHint($rule);
|
$this->addPropertyHint($rule);
|
||||||
|
131
application/forms/AddToBasketForm.php
Normal file
131
application/forms/AddToBasketForm.php
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Module\Director\Forms;
|
||||||
|
|
||||||
|
use dipl\Html\Html;
|
||||||
|
use dipl\Html\HtmlDocument;
|
||||||
|
use dipl\Html\Link;
|
||||||
|
use Icinga\Exception\NotFoundError;
|
||||||
|
use Icinga\Module\Director\DirectorObject\Automation\Basket;
|
||||||
|
use Icinga\Module\Director\Web\Form\DirectorForm;
|
||||||
|
|
||||||
|
class AddToBasketForm extends DirectorForm
|
||||||
|
{
|
||||||
|
/** @var Basket */
|
||||||
|
private $basket;
|
||||||
|
|
||||||
|
private $type = '(has not been set)';
|
||||||
|
|
||||||
|
private $names = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Zend_Form_Exception
|
||||||
|
* @throws \Icinga\Exception\NotFoundError
|
||||||
|
*/
|
||||||
|
public function setup()
|
||||||
|
{
|
||||||
|
$baskets = Basket::loadAll($this->getDb());
|
||||||
|
$enum = [];
|
||||||
|
foreach ($baskets as $basket) {
|
||||||
|
$enum[$basket->get('basket_name')] = $basket->get('basket_name');
|
||||||
|
}
|
||||||
|
|
||||||
|
$names = [];
|
||||||
|
$basket = null;
|
||||||
|
if ($this->hasBeenSent()) {
|
||||||
|
$basketName = $this->getSentValue('basket');
|
||||||
|
if ($basketName) {
|
||||||
|
$basket = Basket::load($basketName, $this->getDb());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$count = 0;
|
||||||
|
$type = $this->type;
|
||||||
|
foreach ($this->names as $name) {
|
||||||
|
if (! empty($names)) {
|
||||||
|
$names[] = ', ';
|
||||||
|
}
|
||||||
|
if ($basket && $basket->hasObject($type, $name)) {
|
||||||
|
$names[] = Html::tag('span', [
|
||||||
|
'style' => 'text-decoration: line-through'
|
||||||
|
], $name);
|
||||||
|
} else {
|
||||||
|
$count++;
|
||||||
|
$names[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->addHtmlHint((new HtmlDocument())->add([
|
||||||
|
'The following objects will be added: ',
|
||||||
|
$names
|
||||||
|
]));
|
||||||
|
$this->addElement('select', 'basket', [
|
||||||
|
'label' => $this->translate('Basket'),
|
||||||
|
'multiOptions' => $this->optionalEnum($enum),
|
||||||
|
'required' => true,
|
||||||
|
'class' => 'autosubmit',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($count > 0) {
|
||||||
|
$this->setSubmitLabel(sprintf(
|
||||||
|
$this->translate('Add %s objects'),
|
||||||
|
$count
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
$this->setSubmitLabel($this->translate('Add'));
|
||||||
|
$this->addSubmitButtonIfSet();
|
||||||
|
$this->getElement($this->submitButtonName)->setAttrib('disabled', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setType($type)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNames($names)
|
||||||
|
{
|
||||||
|
$this->names = $names;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Icinga\Exception\NotFoundError
|
||||||
|
* @throws \Icinga\Module\Director\Exception\DuplicateKeyException
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
$type = $this->type;
|
||||||
|
$basket = Basket::load($this->getValue('basket'), $this->getDb());
|
||||||
|
$basketName = $basket->get('basket_name');
|
||||||
|
|
||||||
|
if (empty($this->names)) {
|
||||||
|
$this->getElement('basket')->addErrorMessage($this->translate(
|
||||||
|
'No object has been chosen'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if ($basket->supportsCustomSelectionFor($type)) {
|
||||||
|
$basket->addObjects($type, $this->names);
|
||||||
|
$basket->store();
|
||||||
|
$this->setSuccessMessage(sprintf($this->translate(
|
||||||
|
'Configuration objects have been added to the chosen basket "%s"'
|
||||||
|
), $basketName));
|
||||||
|
return parent::onSuccess();
|
||||||
|
} else {
|
||||||
|
$this->addHtmlHint(Html::tag('p', [
|
||||||
|
'class' => 'error'
|
||||||
|
], Html::sprintf($this->translate(
|
||||||
|
'Please check your Basket configuration, %s does not support'
|
||||||
|
. ' single "%s" configuration objects'
|
||||||
|
), Link::create(
|
||||||
|
$basketName,
|
||||||
|
'director/basket',
|
||||||
|
['name' => $basketName],
|
||||||
|
['data-base-target' => '_next']
|
||||||
|
), $type)));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,13 +8,13 @@ class BasketDashlet extends Dashlet
|
|||||||
|
|
||||||
public function getTitle()
|
public function getTitle()
|
||||||
{
|
{
|
||||||
return $this->translate('Object Basket');
|
return $this->translate('Configuration Baskets');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSummary()
|
public function getSummary()
|
||||||
{
|
{
|
||||||
return $this->translate(
|
return $this->translate(
|
||||||
'Preserve specific objects in a specific state'
|
'Preserve specific configuration objects in a specific state'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,16 @@ class Basket extends DbObject
|
|||||||
|
|
||||||
protected function onLoadFromDb()
|
protected function onLoadFromDb()
|
||||||
{
|
{
|
||||||
$this->chosenObjects = Json::decode($this->get('objects'));
|
$this->chosenObjects = (array) Json::decode($this->get('objects'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function supportsCustomSelectionFor($type)
|
||||||
|
{
|
||||||
|
if (! array_key_exists($type, $this->chosenObjects)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_array($this->chosenObjects[$type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setObjects($objects)
|
public function setObjects($objects)
|
||||||
@ -81,17 +90,28 @@ class Basket extends DbObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* This is a weird method, as it is required to deal with raw form data
|
||||||
|
*
|
||||||
* @param $type
|
* @param $type
|
||||||
* @param ExportInterface[]|bool $objects
|
* @param ExportInterface[]|bool $objects
|
||||||
*/
|
*/
|
||||||
public function addObjects($type, $objects = true)
|
public function addObjects($type, $objects = true)
|
||||||
{
|
{
|
||||||
|
BasketSnapshot::assertValidType($type);
|
||||||
|
|
||||||
// '1' -> from Form!
|
// '1' -> from Form!
|
||||||
if ($objects === 'ALL') {
|
if ($objects === 'ALL') {
|
||||||
$objects = true;
|
$objects = true;
|
||||||
} elseif ($objects === null || $objects === 'IGNORE') {
|
} elseif ($objects === null || $objects === 'IGNORE') {
|
||||||
return;
|
return;
|
||||||
} elseif ($objects === '[]') {
|
} elseif ($objects === '[]') {
|
||||||
|
if (isset($this->chosenObjects[$type])) {
|
||||||
|
if (! is_array($this->chosenObjects[$type])) {
|
||||||
|
$this->chosenObjects[$type] = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->chosenObjects[$type] = [];
|
||||||
|
}
|
||||||
$objects = [];
|
$objects = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,14 +132,42 @@ class Basket extends DbObject
|
|||||||
$this->reallySet('objects', Json::encode($this->chosenObjects));
|
$this->reallySet('objects', Json::encode($this->chosenObjects));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hasObject($type, $object)
|
||||||
|
{
|
||||||
|
if (! $this->hasType($type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->chosenObjects[$type] === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($object instanceof ExportInterface) {
|
||||||
|
$object = $object->getUniqueIdentifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($this->chosenObjects[$type])) {
|
||||||
|
return in_array($object, $this->chosenObjects[$type]);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $type
|
* @param $type
|
||||||
* @param string $object
|
* @param string $object
|
||||||
*/
|
*/
|
||||||
public function addObject($type, $object)
|
public function addObject($type, $object)
|
||||||
{
|
{
|
||||||
// TODO: make sure array exists - and is not boolean
|
if (is_array($this->chosenObjects[$type])) {
|
||||||
$this->chosenObjects[$type][] = $object;
|
$this->chosenObjects[$type][] = $object;
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException(sprintf(
|
||||||
|
'The Basket "%s" has not been configured for single objects of type "%s"',
|
||||||
|
$this->get('basket_name'),
|
||||||
|
$type
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasType($type)
|
public function hasType($type)
|
||||||
|
@ -8,11 +8,29 @@ use Icinga\Module\Director\Data\Db\DbObject;
|
|||||||
use Icinga\Module\Director\Objects\DirectorDatafield;
|
use Icinga\Module\Director\Objects\DirectorDatafield;
|
||||||
use Icinga\Module\Director\Objects\IcingaCommand;
|
use Icinga\Module\Director\Objects\IcingaCommand;
|
||||||
use Icinga\Module\Director\Objects\IcingaObject;
|
use Icinga\Module\Director\Objects\IcingaObject;
|
||||||
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use Zend_Db_Adapter_Abstract as ZfDbAdapter;
|
|
||||||
|
|
||||||
class BasketSnapshot extends DbObject
|
class BasketSnapshot extends DbObject
|
||||||
{
|
{
|
||||||
|
protected static $typeClasses = [
|
||||||
|
'Datafield' => '\\Icinga\\Module\\Director\\Objects\\DirectorDatafield',
|
||||||
|
'Command' => '\\Icinga\\Module\\Director\\Objects\\IcingaCommand',
|
||||||
|
'HostGroup' => '\\Icinga\\Module\\Director\\Objects\\IcingaHostGroup',
|
||||||
|
'IcingaTemplateChoiceHost' => '\\Icinga\\Module\\Director\\Objects\\IcingaTemplateChoiceHost',
|
||||||
|
'HostTemplate' => '\\Icinga\\Module\\Director\\Objects\\IcingaHost',
|
||||||
|
'ServiceGroup' => '\\Icinga\\Module\\Director\\Objects\\IcingaServiceGroup',
|
||||||
|
'IcingaTemplateChoiceService' => '\\Icinga\\Module\\Director\\Objects\\IcingaTemplateChoiceService',
|
||||||
|
'ServiceTemplate' => '\\Icinga\\Module\\Director\\Objects\\IcingaService',
|
||||||
|
'ServiceSet' => '\\Icinga\\Module\\Director\\Objects\\IcingaServiceSet',
|
||||||
|
'Notification' => '\\Icinga\\Module\\Director\\Objects\\IcingaNotification',
|
||||||
|
'Dependency' => '\\Icinga\\Module\\Director\\Objects\\IcingaDependency',
|
||||||
|
'ImportSource' => '\\Icinga\\Module\\Director\\Objects\\ImportSource',
|
||||||
|
'SyncRule' => '\\Icinga\\Module\\Director\\Objects\\SyncRule',
|
||||||
|
'DirectorJob' => '\\Icinga\\Module\\Director\\Objects\\DirectorJob',
|
||||||
|
'Basket' => '\\Icinga\\Module\\Director\\DirectorObject\\Automation\\Automation',
|
||||||
|
];
|
||||||
|
|
||||||
protected $objects = [];
|
protected $objects = [];
|
||||||
|
|
||||||
protected $content;
|
protected $content;
|
||||||
@ -47,27 +65,23 @@ class BasketSnapshot extends DbObject
|
|||||||
'ts_create' => null,
|
'ts_create' => null,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static function supports($type)
|
||||||
|
{
|
||||||
|
return isset(self::$typeClasses[$type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function assertValidType($type)
|
||||||
|
{
|
||||||
|
if (! static::supports($type)) {
|
||||||
|
throw new InvalidArgumentException("Basket does not support '$type'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static function getClassForType($type)
|
public static function getClassForType($type)
|
||||||
{
|
{
|
||||||
$types = [
|
static::assertValidType($type);
|
||||||
'Datafield' => '\\Icinga\\Module\\Director\\Objects\\DirectorDatafield',
|
|
||||||
'Command' => '\\Icinga\\Module\\Director\\Objects\\IcingaCommand',
|
|
||||||
'HostGroup' => '\\Icinga\\Module\\Director\\Objects\\IcingaHostGroup',
|
|
||||||
'IcingaTemplateChoiceHost' => '\\Icinga\\Module\\Director\\Objects\\IcingaTemplateChoiceHost',
|
|
||||||
'HostTemplate' => '\\Icinga\\Module\\Director\\Objects\\IcingaHost',
|
|
||||||
'ServiceGroup' => '\\Icinga\\Module\\Director\\Objects\\IcingaServiceGroup',
|
|
||||||
'IcingaTemplateChoiceService' => '\\Icinga\\Module\\Director\\Objects\\IcingaTemplateChoiceService',
|
|
||||||
'ServiceTemplate' => '\\Icinga\\Module\\Director\\Objects\\IcingaService',
|
|
||||||
'ServiceSet' => '\\Icinga\\Module\\Director\\Objects\\IcingaServiceSet',
|
|
||||||
'Notification' => '\\Icinga\\Module\\Director\\Objects\\IcingaNotification',
|
|
||||||
'Dependency' => '\\Icinga\\Module\\Director\\Objects\\IcingaDependency',
|
|
||||||
'ImportSource' => '\\Icinga\\Module\\Director\\Objects\\ImportSource',
|
|
||||||
'SyncRule' => '\\Icinga\\Module\\Director\\Objects\\SyncRule',
|
|
||||||
'DirectorJob' => '\\Icinga\\Module\\Director\\Objects\\DirectorJob',
|
|
||||||
'Basket' => '\\Icinga\\Module\\Director\\DirectorObject\\Automation\\Automation',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $types[$type];
|
return self::$typeClasses[$type];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,21 +203,36 @@ class BasketSnapshot extends DbObject
|
|||||||
$new = $class::import($object, $connection, $replace);
|
$new = $class::import($object, $connection, $replace);
|
||||||
if ($new->hasBeenModified()) {
|
if ($new->hasBeenModified()) {
|
||||||
if ($new instanceof IcingaObject && $new->supportsImports()) {
|
if ($new instanceof IcingaObject && $new->supportsImports()) {
|
||||||
$changed[$new->getObjectName()] = $new;
|
/** @var ExportInterface $new */
|
||||||
|
$changed[$new->getUniqueIdentifier()] = $new;
|
||||||
} else {
|
} else {
|
||||||
$new->store();
|
$new->store();
|
||||||
|
// Linking fields right now, as we're not in $changed
|
||||||
|
if ($new instanceof IcingaObject) {
|
||||||
|
$fieldResolver->relinkObjectFields($new, $object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No modification on the object, still, fields might have
|
||||||
|
// been changed
|
||||||
|
if ($new instanceof IcingaObject) {
|
||||||
|
$fieldResolver->relinkObjectFields($new, $object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$allObjects[spl_object_hash($new)] = $object;
|
||||||
if ($new instanceof IcingaObject) {
|
|
||||||
$fieldResolver->relinkObjectFields($new, $object);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var IcingaObject $object */
|
/** @var IcingaObject $object */
|
||||||
foreach ($changed as $object) {
|
foreach ($changed as $object) {
|
||||||
$this->recursivelyStore($object, $changed);
|
$this->recursivelyStore($object, $changed);
|
||||||
}
|
}
|
||||||
|
foreach ($changed as $key => $new) {
|
||||||
|
// Store related fields. As objects might have formerly been
|
||||||
|
// unstored, let's to it right here
|
||||||
|
if ($new instanceof IcingaObject) {
|
||||||
|
$fieldResolver->relinkObjectFields($new, $objects[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$db->commit();
|
$db->commit();
|
||||||
@ -302,9 +331,11 @@ class BasketSnapshot extends DbObject
|
|||||||
if ($dummy instanceof IcingaCommand) {
|
if ($dummy instanceof IcingaCommand) {
|
||||||
$select = $db->select()->from($dummy->getTableName())
|
$select = $db->select()->from($dummy->getTableName())
|
||||||
->where('object_type != ?', 'external_object');
|
->where('object_type != ?', 'external_object');
|
||||||
} else {
|
} elseif (! $dummy->isGroup()) {
|
||||||
$select = $db->select()->from($dummy->getTableName())
|
$select = $db->select()->from($dummy->getTableName())
|
||||||
->where('object_type = ?', 'template');
|
->where('object_type = ?', 'template');
|
||||||
|
} else {
|
||||||
|
$select = $db->select()->from($dummy->getTableName());
|
||||||
}
|
}
|
||||||
$all = $class::loadAll($this->getConnection(), $select);
|
$all = $class::loadAll($this->getConnection(), $select);
|
||||||
} else {
|
} else {
|
||||||
|
@ -6,6 +6,7 @@ use Icinga\Data\Db\DbConnection;
|
|||||||
use Icinga\Exception\NotFoundError;
|
use Icinga\Exception\NotFoundError;
|
||||||
use Icinga\Module\Director\Data\PropertiesFilter;
|
use Icinga\Module\Director\Data\PropertiesFilter;
|
||||||
use Icinga\Module\Director\Db;
|
use Icinga\Module\Director\Db;
|
||||||
|
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
|
||||||
use Icinga\Module\Director\Exception\DuplicateKeyException;
|
use Icinga\Module\Director\Exception\DuplicateKeyException;
|
||||||
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
||||||
use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1;
|
use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1;
|
||||||
@ -13,7 +14,7 @@ use Icinga\Module\Director\Objects\Extension\FlappingSupport;
|
|||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
|
||||||
class IcingaHost extends IcingaObject
|
class IcingaHost extends IcingaObject implements ExportInterface
|
||||||
{
|
{
|
||||||
use FlappingSupport;
|
use FlappingSupport;
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ use Icinga\Exception\IcingaException;
|
|||||||
use Icinga\Module\Director\Data\PropertiesFilter;
|
use Icinga\Module\Director\Data\PropertiesFilter;
|
||||||
use Icinga\Module\Director\Db;
|
use Icinga\Module\Director\Db;
|
||||||
use Icinga\Module\Director\Db\Cache\PrefetchCache;
|
use Icinga\Module\Director\Db\Cache\PrefetchCache;
|
||||||
|
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
|
||||||
use Icinga\Module\Director\Exception\DuplicateKeyException;
|
use Icinga\Module\Director\Exception\DuplicateKeyException;
|
||||||
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
||||||
use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
|
use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
|
||||||
@ -16,7 +17,7 @@ use Icinga\Module\Director\Resolver\HostServiceBlacklist;
|
|||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
|
||||||
class IcingaService extends IcingaObject
|
class IcingaService extends IcingaObject implements ExportInterface
|
||||||
{
|
{
|
||||||
use FlappingSupport;
|
use FlappingSupport;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use Icinga\Exception\IcingaException;
|
|||||||
use Icinga\Exception\InvalidPropertyException;
|
use Icinga\Exception\InvalidPropertyException;
|
||||||
use Icinga\Exception\NotFoundError;
|
use Icinga\Exception\NotFoundError;
|
||||||
use Icinga\Module\Director\Deployment\DeploymentInfo;
|
use Icinga\Module\Director\Deployment\DeploymentInfo;
|
||||||
|
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
|
||||||
use Icinga\Module\Director\Forms\DeploymentLinkForm;
|
use Icinga\Module\Director\Forms\DeploymentLinkForm;
|
||||||
use Icinga\Module\Director\Forms\IcingaCloneObjectForm;
|
use Icinga\Module\Director\Forms\IcingaCloneObjectForm;
|
||||||
use Icinga\Module\Director\Forms\IcingaObjectFieldForm;
|
use Icinga\Module\Director\Forms\IcingaObjectFieldForm;
|
||||||
@ -79,6 +80,9 @@ abstract class ObjectController extends ActionController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundError
|
||||||
|
*/
|
||||||
public function indexAction()
|
public function indexAction()
|
||||||
{
|
{
|
||||||
if (! $this->getRequest()->isApiRequest()) {
|
if (! $this->getRequest()->isApiRequest()) {
|
||||||
@ -111,6 +115,9 @@ abstract class ObjectController extends ActionController
|
|||||||
$this->content()->add($form);
|
$this->content()->add($form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundError
|
||||||
|
*/
|
||||||
public function editAction()
|
public function editAction()
|
||||||
{
|
{
|
||||||
$object = $this->requireObject();
|
$object = $this->requireObject();
|
||||||
@ -118,9 +125,14 @@ abstract class ObjectController extends ActionController
|
|||||||
$this->addObjectTitle()
|
$this->addObjectTitle()
|
||||||
->addObjectForm($object)
|
->addObjectForm($object)
|
||||||
->addActionClone()
|
->addActionClone()
|
||||||
->addActionUsage();
|
->addActionUsage()
|
||||||
|
->addActionBasket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundError
|
||||||
|
* @throws \Icinga\Security\SecurityException
|
||||||
|
*/
|
||||||
public function renderAction()
|
public function renderAction()
|
||||||
{
|
{
|
||||||
$this->assertTypePermission()
|
$this->assertTypePermission()
|
||||||
@ -133,6 +145,9 @@ abstract class ObjectController extends ActionController
|
|||||||
$preview->renderTo($this);
|
$preview->renderTo($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundError
|
||||||
|
*/
|
||||||
public function cloneAction()
|
public function cloneAction()
|
||||||
{
|
{
|
||||||
$this->assertTypePermission();
|
$this->assertTypePermission();
|
||||||
@ -151,6 +166,10 @@ abstract class ObjectController extends ActionController
|
|||||||
->content()->add($form);
|
->content()->add($form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundError
|
||||||
|
* @throws \Icinga\Security\SecurityException
|
||||||
|
*/
|
||||||
public function fieldsAction()
|
public function fieldsAction()
|
||||||
{
|
{
|
||||||
$this->assertPermission('director/admin');
|
$this->assertPermission('director/admin');
|
||||||
@ -187,6 +206,10 @@ abstract class ObjectController extends ActionController
|
|||||||
$table->renderTo($this);
|
$table->renderTo($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundError
|
||||||
|
* @throws \Icinga\Security\SecurityException
|
||||||
|
*/
|
||||||
public function historyAction()
|
public function historyAction()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
@ -206,6 +229,9 @@ abstract class ObjectController extends ActionController
|
|||||||
->renderTo($this);
|
->renderTo($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundError
|
||||||
|
*/
|
||||||
public function membershipAction()
|
public function membershipAction()
|
||||||
{
|
{
|
||||||
$object = $this->requireObject();
|
$object = $this->requireObject();
|
||||||
@ -224,6 +250,10 @@ abstract class ObjectController extends ActionController
|
|||||||
->renderTo($this);
|
->renderTo($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
* @throws NotFoundError
|
||||||
|
*/
|
||||||
protected function addObjectTitle()
|
protected function addObjectTitle()
|
||||||
{
|
{
|
||||||
$object = $this->requireObject();
|
$object = $this->requireObject();
|
||||||
@ -271,6 +301,37 @@ abstract class ObjectController extends ActionController
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function addActionBasket()
|
||||||
|
{
|
||||||
|
if ($this->hasBasketSupport()) {
|
||||||
|
$object = $this->object;
|
||||||
|
if ($object instanceof ExportInterface) {
|
||||||
|
if ($object->isTemplate()) {
|
||||||
|
$type = $this->getType() . 'Template';
|
||||||
|
} elseif ($object->isGroup()) {
|
||||||
|
$type = ucfirst($this->getType());
|
||||||
|
} else {
|
||||||
|
// Command? Sure?
|
||||||
|
$type = ucfirst($this->getType());
|
||||||
|
}
|
||||||
|
$this->actions()->add(Link::create(
|
||||||
|
$this->translate('Add to Basket'),
|
||||||
|
'director/basket/add',
|
||||||
|
[
|
||||||
|
'type' => $type,
|
||||||
|
'names' => $object->getUniqueIdentifier()
|
||||||
|
],
|
||||||
|
['class' => 'icon-tag']
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function addTemplate()
|
protected function addTemplate()
|
||||||
{
|
{
|
||||||
$this->assertPermission('director/admin');
|
$this->assertPermission('director/admin');
|
||||||
@ -450,10 +511,20 @@ abstract class ObjectController extends ActionController
|
|||||||
return $form;
|
return $form;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function hasBasketSupport()
|
||||||
|
{
|
||||||
|
return $this->object->isTemplate() || $this->object->isGroup();
|
||||||
|
}
|
||||||
|
|
||||||
protected function onObjectFormLoaded(DirectorObjectForm $form)
|
protected function onObjectFormLoaded(DirectorObjectForm $form)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return IcingaObject
|
||||||
|
* @throws NotFoundError
|
||||||
|
* @throws \Zend_Controller_Response_Exception
|
||||||
|
*/
|
||||||
protected function requireObject()
|
protected function requireObject()
|
||||||
{
|
{
|
||||||
if (! $this->object) {
|
if (! $this->object) {
|
||||||
|
@ -56,7 +56,6 @@ abstract class ObjectsController extends ActionController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return IcingaObjectsHandler
|
* @return IcingaObjectsHandler
|
||||||
* @throws \Icinga\Exception\ConfigurationError
|
|
||||||
* @throws NotFoundError
|
* @throws NotFoundError
|
||||||
*/
|
*/
|
||||||
protected function apiRequestHandler()
|
protected function apiRequestHandler()
|
||||||
@ -82,7 +81,6 @@ abstract class ObjectsController extends ActionController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws \Icinga\Exception\ConfigurationError
|
|
||||||
* @throws \Icinga\Exception\Http\HttpNotFoundException
|
* @throws \Icinga\Exception\Http\HttpNotFoundException
|
||||||
* @throws NotFoundError
|
* @throws NotFoundError
|
||||||
*/
|
*/
|
||||||
@ -124,7 +122,6 @@ abstract class ObjectsController extends ActionController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return ObjectsTable
|
* @return ObjectsTable
|
||||||
* @throws \Icinga\Exception\ConfigurationError
|
|
||||||
*/
|
*/
|
||||||
protected function getTable()
|
protected function getTable()
|
||||||
{
|
{
|
||||||
@ -134,9 +131,24 @@ abstract class ObjectsController extends ActionController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws NotFoundError
|
* @throws NotFoundError
|
||||||
* @throws \Icinga\Exception\ConfigurationError
|
*/
|
||||||
|
public function edittemplatesAction()
|
||||||
|
{
|
||||||
|
$this->commonForEdit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundError
|
||||||
*/
|
*/
|
||||||
public function editAction()
|
public function editAction()
|
||||||
|
{
|
||||||
|
$this->commonForEdit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws NotFoundError
|
||||||
|
*/
|
||||||
|
public function commonForEdit()
|
||||||
{
|
{
|
||||||
$type = ucfirst($this->getType());
|
$type = ucfirst($this->getType());
|
||||||
|
|
||||||
@ -293,7 +305,7 @@ abstract class ObjectsController extends ActionController
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
* @throws \Icinga\Exception\ConfigurationError
|
* @throws NotFoundError
|
||||||
*/
|
*/
|
||||||
protected function loadMultiObjectsFromParams()
|
protected function loadMultiObjectsFromParams()
|
||||||
{
|
{
|
||||||
@ -341,7 +353,6 @@ abstract class ObjectsController extends ActionController
|
|||||||
/**
|
/**
|
||||||
* @param ZfQueryBasedTable $table
|
* @param ZfQueryBasedTable $table
|
||||||
* @return ZfQueryBasedTable
|
* @return ZfQueryBasedTable
|
||||||
* @throws \Icinga\Exception\ConfigurationError
|
|
||||||
* @throws NotFoundError
|
* @throws NotFoundError
|
||||||
*/
|
*/
|
||||||
protected function eventuallyFilterCommand(ZfQueryBasedTable $table)
|
protected function eventuallyFilterCommand(ZfQueryBasedTable $table)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Icinga\Module\Director\Web\Controller;
|
namespace Icinga\Module\Director\Web\Controller;
|
||||||
|
|
||||||
|
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
|
||||||
use Icinga\Module\Director\Objects\IcingaObject;
|
use Icinga\Module\Director\Objects\IcingaObject;
|
||||||
use Icinga\Module\Director\Web\Controller\Extension\DirectorDb;
|
use Icinga\Module\Director\Web\Controller\Extension\DirectorDb;
|
||||||
use Icinga\Module\Director\Web\Table\ApplyRulesTable;
|
use Icinga\Module\Director\Web\Table\ApplyRulesTable;
|
||||||
@ -115,6 +116,18 @@ abstract class TemplateController extends CompatController
|
|||||||
['class' => 'icon-edit']
|
['class' => 'icon-edit']
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
|
if ($template instanceof ExportInterface) {
|
||||||
|
$this->actions()->add(Link::create(
|
||||||
|
$this->translate('Add to Basket'),
|
||||||
|
'director/basket/add',
|
||||||
|
[
|
||||||
|
'type' => ucfirst($this->getType()) . 'Template',
|
||||||
|
'names' => $template->getUniqueIdentifier()
|
||||||
|
],
|
||||||
|
['class' => 'icon-tag']
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
$list = new UnorderedList([], [
|
$list = new UnorderedList([], [
|
||||||
'class' => 'vertical-action-list'
|
'class' => 'vertical-action-list'
|
||||||
]);
|
]);
|
||||||
|
@ -29,8 +29,7 @@ class ObjectPreview
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ControlsAndContent $cc
|
* @param ControlsAndContent $cc
|
||||||
* @throws \Icinga\Exception\IcingaException
|
* @throws \Icinga\Exception\NotFoundError
|
||||||
* @throws \Icinga\Exception\ProgrammingError
|
|
||||||
*/
|
*/
|
||||||
public function renderTo(ControlsAndContent $cc)
|
public function renderTo(ControlsAndContent $cc)
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Icinga\Module\Director\Web\Table;
|
namespace Icinga\Module\Director\Web\Table;
|
||||||
|
|
||||||
|
use dipl\Web\Table\Extension\MultiSelect;
|
||||||
use Icinga\Authentication\Auth;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Data\Filter\Filter;
|
use Icinga\Data\Filter\Filter;
|
||||||
use Icinga\Module\Director\Db;
|
use Icinga\Module\Director\Db;
|
||||||
@ -17,6 +18,8 @@ use Zend_Db_Select as ZfSelect;
|
|||||||
|
|
||||||
class TemplatesTable extends ZfQueryBasedTable
|
class TemplatesTable extends ZfQueryBasedTable
|
||||||
{
|
{
|
||||||
|
use MultiSelect;
|
||||||
|
|
||||||
protected $searchColumns = ['o.object_name'];
|
protected $searchColumns = ['o.object_name'];
|
||||||
|
|
||||||
private $type;
|
private $type;
|
||||||
@ -28,6 +31,16 @@ class TemplatesTable extends ZfQueryBasedTable
|
|||||||
return $table;
|
return $table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function assemble()
|
||||||
|
{
|
||||||
|
$type = $this->type;
|
||||||
|
$this->enableMultiSelect(
|
||||||
|
"director/${type}s/edittemplates",
|
||||||
|
"director/${type}template",
|
||||||
|
['name']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function getType()
|
public function getType()
|
||||||
{
|
{
|
||||||
return $this->type;
|
return $this->type;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user