2015-06-30 05:19:31 -04:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Icinga\Module\Director\Web\Controller;
|
|
|
|
|
|
2020-10-26 13:50:13 -04:00
|
|
|
use gipfl\Web\Widget\Hint;
|
2017-10-20 04:23:23 -04:00
|
|
|
use Icinga\Exception\IcingaException;
|
2016-03-06 08:20:49 -05:00
|
|
|
use Icinga\Exception\InvalidPropertyException;
|
2016-02-17 13:22:36 -05:00
|
|
|
use Icinga\Exception\NotFoundError;
|
2021-08-16 01:12:06 -04:00
|
|
|
use Icinga\Exception\ProgrammingError;
|
2026-02-17 09:52:50 -05:00
|
|
|
use Icinga\Module\Director\Dashboard\Dashlet\DeploymentDashlet;
|
2021-10-05 17:10:50 -04:00
|
|
|
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
|
2021-08-16 05:43:09 -04:00
|
|
|
use Icinga\Module\Director\Db\Branch\Branch;
|
2021-10-05 17:10:50 -04:00
|
|
|
use Icinga\Module\Director\Db\Branch\BranchedObject;
|
2022-12-16 08:16:02 -05:00
|
|
|
use Icinga\Module\Director\Db\Branch\BranchSupport;
|
2021-10-05 17:10:50 -04:00
|
|
|
use Icinga\Module\Director\Db\Branch\UuidLookup;
|
2017-07-20 02:31:53 -04:00
|
|
|
use Icinga\Module\Director\Deployment\DeploymentInfo;
|
2018-10-15 08:49:47 -04:00
|
|
|
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
|
2019-02-13 15:41:46 -05:00
|
|
|
use Icinga\Module\Director\Exception\NestingError;
|
2017-07-20 02:31:53 -04:00
|
|
|
use Icinga\Module\Director\Forms\DeploymentLinkForm;
|
2017-07-25 04:16:15 -04:00
|
|
|
use Icinga\Module\Director\Forms\IcingaCloneObjectForm;
|
2017-07-06 03:04:32 -04:00
|
|
|
use Icinga\Module\Director\Forms\IcingaObjectFieldForm;
|
2026-03-26 04:28:03 -04:00
|
|
|
use Icinga\Module\Director\Objects\DirectorDeploymentLog;
|
2019-05-27 11:27:18 -04:00
|
|
|
use Icinga\Module\Director\Objects\IcingaCommand;
|
2015-08-02 09:01:07 -04:00
|
|
|
use Icinga\Module\Director\Objects\IcingaObject;
|
2017-07-20 02:31:53 -04:00
|
|
|
use Icinga\Module\Director\Objects\IcingaObjectGroup;
|
2019-03-19 10:29:08 -04:00
|
|
|
use Icinga\Module\Director\Objects\IcingaService;
|
2018-10-25 02:38:24 -04:00
|
|
|
use Icinga\Module\Director\Objects\IcingaServiceSet;
|
2017-08-16 17:53:37 -04:00
|
|
|
use Icinga\Module\Director\RestApi\IcingaObjectHandler;
|
2017-06-21 18:44:31 -04:00
|
|
|
use Icinga\Module\Director\Web\Controller\Extension\ObjectRestrictions;
|
2016-11-16 10:02:28 -05:00
|
|
|
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
|
2017-08-16 17:53:37 -04:00
|
|
|
use Icinga\Module\Director\Web\ObjectPreview;
|
2017-07-20 02:31:53 -04:00
|
|
|
use Icinga\Module\Director\Web\Table\ActivityLogTable;
|
2021-10-05 17:10:50 -04:00
|
|
|
use Icinga\Module\Director\Web\Table\BranchActivityTable;
|
2017-07-11 02:33:03 -04:00
|
|
|
use Icinga\Module\Director\Web\Table\GroupMemberTable;
|
2017-08-16 17:53:37 -04:00
|
|
|
use Icinga\Module\Director\Web\Table\IcingaObjectDatafieldTable;
|
2017-07-03 01:04:31 -04:00
|
|
|
use Icinga\Module\Director\Web\Tabs\ObjectTabs;
|
2021-10-05 13:13:57 -04:00
|
|
|
use Icinga\Module\Director\Web\Widget\BranchedObjectHint;
|
2019-05-02 07:23:06 -04:00
|
|
|
use gipfl\IcingaWeb2\Link;
|
2021-10-05 17:10:50 -04:00
|
|
|
use ipl\Html\Html;
|
|
|
|
|
use Ramsey\Uuid\Uuid;
|
|
|
|
|
use Ramsey\Uuid\UuidInterface;
|
2015-06-30 05:19:31 -04:00
|
|
|
|
|
|
|
|
abstract class ObjectController extends ActionController
|
|
|
|
|
{
|
2017-06-21 18:44:31 -04:00
|
|
|
use ObjectRestrictions;
|
2021-08-16 05:43:09 -04:00
|
|
|
use BranchHelper;
|
2017-06-21 18:44:31 -04:00
|
|
|
|
2017-02-08 06:38:14 -05:00
|
|
|
/** @var IcingaObject */
|
2015-06-30 05:19:31 -04:00
|
|
|
protected $object;
|
|
|
|
|
|
2017-08-16 02:08:08 -04:00
|
|
|
/** @var bool This controller handles REST API requests */
|
2015-12-10 07:11:21 -05:00
|
|
|
protected $isApified = true;
|
|
|
|
|
|
2017-08-16 02:08:08 -04:00
|
|
|
/** @var array Allowed object types we are allowed to edit anyways */
|
2016-03-22 13:19:13 -04:00
|
|
|
protected $allowedExternals = array(
|
|
|
|
|
'apiuser',
|
|
|
|
|
'endpoint'
|
|
|
|
|
);
|
|
|
|
|
|
2017-08-16 17:53:37 -04:00
|
|
|
protected $type;
|
|
|
|
|
|
2020-11-30 04:17:44 -05:00
|
|
|
/** @var string|null */
|
|
|
|
|
protected $objectBaseUrl;
|
|
|
|
|
|
2015-06-30 05:19:31 -04:00
|
|
|
public function init()
|
|
|
|
|
{
|
2021-12-17 05:46:55 -05:00
|
|
|
$this->enableStaticObjectLoader($this->getTableName());
|
2023-02-22 05:46:24 -05:00
|
|
|
if (! $this->getRequest()->isApiRequest()) {
|
|
|
|
|
$this->loadOptionalObject();
|
|
|
|
|
}
|
|
|
|
|
parent::init();
|
2016-12-16 06:07:01 -05:00
|
|
|
if ($this->getRequest()->isApiRequest()) {
|
2022-07-20 03:59:22 -04:00
|
|
|
$this->initializeRestApi();
|
|
|
|
|
} else {
|
|
|
|
|
$this->initializeWebRequest();
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-22 10:47:57 -04:00
|
|
|
|
2022-07-20 03:59:22 -04:00
|
|
|
protected function initializeRestApi()
|
|
|
|
|
{
|
|
|
|
|
$handler = new IcingaObjectHandler($this->getRequest(), $this->getResponse(), $this->db());
|
|
|
|
|
try {
|
|
|
|
|
$this->loadOptionalObject();
|
|
|
|
|
} catch (NotFoundError $e) {
|
|
|
|
|
// Silently ignore the error, the handler will complain
|
|
|
|
|
$handler->sendJsonError($e, 404);
|
|
|
|
|
// TODO: nice shutdown
|
2018-09-05 16:27:07 -04:00
|
|
|
exit;
|
2022-07-20 03:59:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$handler->setApi($this->api());
|
|
|
|
|
if ($this->object) {
|
|
|
|
|
$handler->setObject($this->object);
|
|
|
|
|
}
|
|
|
|
|
$handler->dispatch();
|
|
|
|
|
// Hint: also here, hard exit. There is too much magic going on.
|
|
|
|
|
// Letting this bubble up smoothly would be "correct", but proved
|
|
|
|
|
// to be too fragile. Web 2, all kinds of pre/postDispatch magic,
|
|
|
|
|
// different view renderers - hard exit is the only safe bet right
|
|
|
|
|
// now.
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function initializeWebRequest()
|
|
|
|
|
{
|
|
|
|
|
if ($this->getRequest()->getActionName() === 'add') {
|
|
|
|
|
$this->addSingleTab(
|
|
|
|
|
sprintf($this->translate('Add %s'), ucfirst($this->getType())),
|
|
|
|
|
null,
|
|
|
|
|
'add'
|
|
|
|
|
);
|
2017-08-16 02:08:08 -04:00
|
|
|
} else {
|
2022-07-20 03:59:22 -04:00
|
|
|
$this->tabs(new ObjectTabs(
|
|
|
|
|
$this->getRequest()->getControllerName(),
|
|
|
|
|
$this->getAuth(),
|
|
|
|
|
$this->object
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
if ($this->object !== null) {
|
|
|
|
|
$this->addDeploymentLink();
|
2016-12-16 06:07:01 -05:00
|
|
|
}
|
2015-06-30 05:19:31 -04:00
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
/**
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
*/
|
2015-06-30 05:19:31 -04:00
|
|
|
public function indexAction()
|
2015-07-30 04:04:12 -04:00
|
|
|
{
|
2017-08-16 02:08:08 -04:00
|
|
|
if (! $this->getRequest()->isApiRequest()) {
|
|
|
|
|
$this->redirectToPreviewForExternals()
|
|
|
|
|
->editAction();
|
2016-03-18 09:58:46 -04:00
|
|
|
}
|
2015-06-30 05:19:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function addAction()
|
|
|
|
|
{
|
2017-07-03 01:04:31 -04:00
|
|
|
$this->tabs()->activate('add');
|
2017-08-16 17:53:37 -04:00
|
|
|
$url = sprintf('director/%ss', $this->getPluralType());
|
2015-06-30 05:19:31 -04:00
|
|
|
|
2017-08-21 03:07:20 -04:00
|
|
|
$imports = $this->params->get('imports');
|
2017-08-16 17:53:37 -04:00
|
|
|
$form = $this->loadObjectForm()
|
2017-07-28 12:46:11 -04:00
|
|
|
->presetImports($imports)
|
2015-06-30 05:19:31 -04:00
|
|
|
->setSuccessUrl($url);
|
|
|
|
|
|
2017-08-21 03:07:20 -04:00
|
|
|
if ($oType = $this->params->get('type', 'object')) {
|
2017-07-03 01:04:31 -04:00
|
|
|
$form->setPreferredObjectType($oType);
|
2016-10-13 07:53:01 -04:00
|
|
|
}
|
2017-07-03 01:04:31 -04:00
|
|
|
if ($oType === 'template') {
|
2021-12-14 04:46:52 -05:00
|
|
|
if ($this->showNotInBranch($this->translate('Creating Templates'))) {
|
|
|
|
|
$this->addTitle($this->translate('Create a new Template'));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-16 17:53:37 -04:00
|
|
|
$this->addTemplate();
|
2016-10-13 07:53:01 -04:00
|
|
|
} else {
|
2017-08-16 17:53:37 -04:00
|
|
|
$this->addObject();
|
2016-10-13 07:53:01 -04:00
|
|
|
}
|
2022-09-20 06:06:52 -04:00
|
|
|
$branch = $this->getBranch();
|
2022-12-16 08:16:02 -05:00
|
|
|
if (! $this->getRequest()->isApiRequest()) {
|
|
|
|
|
$hasPreferred = $this->hasPreferredBranch();
|
|
|
|
|
if ($branch->isBranch() || $hasPreferred) {
|
|
|
|
|
$this->content()->add(new BranchedObjectHint($branch, $this->Auth(), null, $hasPreferred));
|
|
|
|
|
}
|
2022-09-20 06:06:52 -04:00
|
|
|
}
|
2015-07-30 03:26:02 -04:00
|
|
|
|
|
|
|
|
$form->handleRequest();
|
2017-07-03 01:04:31 -04:00
|
|
|
$this->content()->add($form);
|
2015-12-10 07:19:16 -05:00
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
/**
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
*/
|
2017-08-16 17:53:37 -04:00
|
|
|
public function editAction()
|
2016-03-29 13:32:50 -04:00
|
|
|
{
|
2017-08-16 17:53:37 -04:00
|
|
|
$object = $this->requireObject();
|
|
|
|
|
$this->tabs()->activate('modify');
|
2021-12-14 04:46:52 -05:00
|
|
|
$this->addObjectTitle();
|
2022-09-20 06:48:26 -04:00
|
|
|
// Hint: Service Sets are 'templates' (as long as not being assigned to a host
|
2024-10-22 08:31:14 -04:00
|
|
|
if (
|
|
|
|
|
$this->getTableName() !== 'icinga_service_set'
|
2022-09-20 06:48:26 -04:00
|
|
|
&& $object->isTemplate()
|
|
|
|
|
&& $this->showNotInBranch($this->translate('Modifying Templates'))
|
|
|
|
|
) {
|
2021-12-14 04:46:52 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ($object->isApplyRule() && $this->showNotInBranch($this->translate('Modifying Apply Rules'))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->addObjectForm($object)
|
2017-08-16 17:53:37 -04:00
|
|
|
->addActionClone()
|
2018-10-15 08:49:47 -04:00
|
|
|
->addActionUsage()
|
|
|
|
|
->addActionBasket();
|
2016-03-29 13:32:50 -04:00
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
/**
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
* @throws \Icinga\Security\SecurityException
|
|
|
|
|
*/
|
2017-08-16 17:53:37 -04:00
|
|
|
public function renderAction()
|
2017-07-25 04:18:07 -04:00
|
|
|
{
|
2017-10-12 10:26:50 -04:00
|
|
|
$this->assertTypePermission()
|
|
|
|
|
->assertPermission('director/showconfig');
|
2017-08-16 17:53:37 -04:00
|
|
|
$this->tabs()->activate('render');
|
|
|
|
|
$preview = new ObjectPreview($this->requireObject(), $this->getRequest());
|
2017-08-18 10:13:09 -04:00
|
|
|
if ($this->object->isExternal()) {
|
|
|
|
|
$this->addActionClone();
|
|
|
|
|
}
|
2019-05-27 11:27:18 -04:00
|
|
|
$this->addActionBasket();
|
2017-08-16 17:53:37 -04:00
|
|
|
$preview->renderTo($this);
|
2017-07-25 04:18:07 -04:00
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
/**
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
*/
|
2015-12-10 07:19:16 -05:00
|
|
|
public function cloneAction()
|
|
|
|
|
{
|
2017-10-12 10:26:50 -04:00
|
|
|
$this->assertTypePermission();
|
2017-08-16 17:53:37 -04:00
|
|
|
$object = $this->requireObject();
|
2021-12-14 04:46:52 -05:00
|
|
|
$this->addTitle($this->translate('Clone: %s'), $object->getObjectName())
|
|
|
|
|
->addBackToObjectLink();
|
|
|
|
|
|
2024-07-23 05:21:48 -04:00
|
|
|
if (! $object instanceof IcingaServiceSet) {
|
|
|
|
|
if ($object->isTemplate() && $this->showNotInBranch($this->translate('Cloning Templates'))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-12-14 04:46:52 -05:00
|
|
|
|
2024-07-23 05:21:48 -04:00
|
|
|
if ($object->isTemplate() && $this->showNotInBranch($this->translate('Cloning Apply Rules'))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-12-14 04:46:52 -05:00
|
|
|
}
|
|
|
|
|
|
2017-07-25 04:16:15 -04:00
|
|
|
$form = IcingaCloneObjectForm::load()
|
2021-08-25 05:28:51 -04:00
|
|
|
->setBranch($this->getBranch())
|
2017-08-16 17:53:37 -04:00
|
|
|
->setObject($object)
|
2020-11-30 04:17:44 -05:00
|
|
|
->setObjectBaseUrl($this->getObjectBaseUrl())
|
2017-07-25 04:16:15 -04:00
|
|
|
->handleRequest();
|
2017-08-16 17:53:37 -04:00
|
|
|
|
2017-08-18 10:13:09 -04:00
|
|
|
if ($object->isExternal()) {
|
|
|
|
|
$this->tabs()->activate('render');
|
|
|
|
|
} else {
|
|
|
|
|
$this->tabs()->activate('modify');
|
|
|
|
|
}
|
2021-12-14 04:46:52 -05:00
|
|
|
$this->content()->add($form);
|
2015-06-30 05:19:31 -04:00
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
/**
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
* @throws \Icinga\Security\SecurityException
|
|
|
|
|
*/
|
2015-08-02 09:01:47 -04:00
|
|
|
public function fieldsAction()
|
|
|
|
|
{
|
2017-07-11 02:33:03 -04:00
|
|
|
$this->assertPermission('director/admin');
|
2017-07-28 18:12:34 -04:00
|
|
|
$object = $this->requireObject();
|
2015-08-02 09:01:47 -04:00
|
|
|
$type = $this->getType();
|
|
|
|
|
|
2017-07-06 03:04:32 -04:00
|
|
|
$this->addTitle(
|
2016-05-03 03:09:01 -04:00
|
|
|
$this->translate('Custom fields: %s'),
|
2017-07-28 18:12:34 -04:00
|
|
|
$object->getObjectName()
|
2015-08-02 09:01:47 -04:00
|
|
|
);
|
2017-07-28 18:12:34 -04:00
|
|
|
$this->tabs()->activate('fields');
|
2021-12-14 04:46:52 -05:00
|
|
|
if ($this->showNotInBranch($this->translate('Managing Fields'))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-13 15:41:46 -05:00
|
|
|
try {
|
|
|
|
|
$this->addFieldsFormAndTable($object, $type);
|
|
|
|
|
} catch (NestingError $e) {
|
2020-10-26 13:50:13 -04:00
|
|
|
$this->content()->add(Hint::error($e->getMessage()));
|
2019-02-13 15:41:46 -05:00
|
|
|
}
|
|
|
|
|
}
|
2015-08-02 09:01:47 -04:00
|
|
|
|
2019-02-13 15:41:46 -05:00
|
|
|
protected function addFieldsFormAndTable($object, $type)
|
|
|
|
|
{
|
2017-07-06 03:04:32 -04:00
|
|
|
$form = IcingaObjectFieldForm::load()
|
2017-06-21 18:44:31 -04:00
|
|
|
->setDb($this->db())
|
2015-09-14 10:54:43 -04:00
|
|
|
->setIcingaObject($object);
|
|
|
|
|
|
|
|
|
|
if ($id = $this->params->get('field_id')) {
|
2017-08-16 17:53:37 -04:00
|
|
|
$form->loadObject([
|
2023-07-19 04:30:13 -04:00
|
|
|
"{$type}_id" => $object->id,
|
2015-10-13 11:58:50 -04:00
|
|
|
'datafield_id' => $id
|
2017-08-16 17:53:37 -04:00
|
|
|
]);
|
2016-02-28 04:58:42 -05:00
|
|
|
|
2017-07-06 03:04:32 -04:00
|
|
|
$this->actions()->add(Link::create(
|
2016-02-28 04:58:42 -05:00
|
|
|
$this->translate('back'),
|
2017-07-06 03:04:32 -04:00
|
|
|
$this->url()->without('field_id'),
|
2016-02-28 04:58:42 -05:00
|
|
|
null,
|
2017-07-06 03:04:32 -04:00
|
|
|
['class' => 'icon-left-big']
|
|
|
|
|
));
|
2015-09-14 10:54:43 -04:00
|
|
|
}
|
|
|
|
|
$form->handleRequest();
|
2017-08-16 17:53:37 -04:00
|
|
|
$this->content()->add($form);
|
|
|
|
|
$table = new IcingaObjectDatafieldTable($object);
|
2018-05-04 18:24:49 -04:00
|
|
|
$table->getAttributes()->set('data-base-target', '_self');
|
2017-08-16 17:53:37 -04:00
|
|
|
$table->renderTo($this);
|
2015-08-02 09:01:47 -04:00
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
/**
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
* @throws \Icinga\Security\SecurityException
|
|
|
|
|
*/
|
2015-06-30 05:19:31 -04:00
|
|
|
public function historyAction()
|
|
|
|
|
{
|
2017-10-12 10:26:50 -04:00
|
|
|
$this
|
|
|
|
|
->assertTypePermission()
|
|
|
|
|
->assertPermission('director/audit')
|
2017-07-28 18:12:34 -04:00
|
|
|
->setAutorefreshInterval(10)
|
|
|
|
|
->tabs()->activate('history');
|
|
|
|
|
|
|
|
|
|
$name = $this->requireObject()->getObjectName();
|
|
|
|
|
$this->addTitle($this->translate('Activity Log: %s'), $name);
|
|
|
|
|
|
2016-03-16 17:50:35 -04:00
|
|
|
$db = $this->db();
|
2019-04-10 04:39:05 -04:00
|
|
|
$objectTable = $this->object->getTableName();
|
2019-01-11 06:24:29 -05:00
|
|
|
$table = (new ActivityLogTable($db))
|
2017-07-28 18:12:34 -04:00
|
|
|
->setLastDeployedId($db->getLastDeploymentActivityLogId())
|
2019-04-10 04:39:05 -04:00
|
|
|
->filterObject($objectTable, $name);
|
2019-01-11 06:24:29 -05:00
|
|
|
if ($host = $this->params->get('host')) {
|
|
|
|
|
$table->filterHost($host);
|
|
|
|
|
}
|
2021-10-05 17:10:50 -04:00
|
|
|
$this->showOptionalBranchActivity($table);
|
2019-01-11 06:24:29 -05:00
|
|
|
$table->renderTo($this);
|
2015-06-30 05:19:31 -04:00
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
/**
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
*/
|
2017-07-11 02:33:03 -04:00
|
|
|
public function membershipAction()
|
|
|
|
|
{
|
2017-07-28 18:12:34 -04:00
|
|
|
$object = $this->requireObject();
|
|
|
|
|
if (! $object instanceof IcingaObjectGroup) {
|
2017-07-11 02:33:03 -04:00
|
|
|
throw new NotFoundError('Not Found');
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-28 18:12:34 -04:00
|
|
|
$this
|
|
|
|
|
->addTitle($this->translate('Group membership: %s'), $object->getObjectName())
|
|
|
|
|
->setAutorefreshInterval(15)
|
|
|
|
|
->tabs()->activate('membership');
|
2017-07-11 02:33:03 -04:00
|
|
|
|
2017-07-28 18:12:34 -04:00
|
|
|
$type = substr($this->getType(), 0, -5);
|
|
|
|
|
GroupMemberTable::create($type, $this->db())
|
|
|
|
|
->setGroup($object)
|
|
|
|
|
->renderTo($this);
|
2017-07-11 02:33:03 -04:00
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
/**
|
|
|
|
|
* @return $this
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
*/
|
2017-08-16 17:53:37 -04:00
|
|
|
protected function addObjectTitle()
|
|
|
|
|
{
|
|
|
|
|
$object = $this->requireObject();
|
|
|
|
|
$name = $object->getObjectName();
|
|
|
|
|
if ($object->isTemplate()) {
|
|
|
|
|
$this->addTitle($this->translate('Template: %s'), $name);
|
|
|
|
|
} else {
|
|
|
|
|
$this->addTitle($name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:52:03 -04:00
|
|
|
/**
|
|
|
|
|
* @return $this
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
*/
|
2017-08-16 17:53:37 -04:00
|
|
|
protected function addActionUsage()
|
|
|
|
|
{
|
|
|
|
|
$type = $this->getType();
|
|
|
|
|
$object = $this->requireObject();
|
2018-10-15 08:52:03 -04:00
|
|
|
if ($object->isTemplate() && $type !== 'serviceSet') {
|
2017-08-16 17:53:37 -04:00
|
|
|
$this->actions()->add([
|
|
|
|
|
Link::create(
|
|
|
|
|
$this->translate('Usage'),
|
2023-07-19 04:30:13 -04:00
|
|
|
"director/{$type}template/usage",
|
2017-08-16 17:53:37 -04:00
|
|
|
['name' => $object->getObjectName()],
|
|
|
|
|
['class' => 'icon-sitemap']
|
|
|
|
|
)
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function addActionClone()
|
|
|
|
|
{
|
|
|
|
|
$this->actions()->add(Link::create(
|
|
|
|
|
$this->translate('Clone'),
|
2020-11-30 04:17:44 -05:00
|
|
|
$this->getObjectBaseUrl() . '/clone',
|
2017-08-16 17:53:37 -04:00
|
|
|
$this->object->getUrlParams(),
|
|
|
|
|
array('class' => 'icon-paste')
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
/**
|
|
|
|
|
* @return $this
|
|
|
|
|
*/
|
|
|
|
|
protected function addActionBasket()
|
|
|
|
|
{
|
|
|
|
|
if ($this->hasBasketSupport()) {
|
|
|
|
|
$object = $this->object;
|
|
|
|
|
if ($object instanceof ExportInterface) {
|
2019-05-27 11:27:18 -04:00
|
|
|
if ($object instanceof IcingaCommand) {
|
|
|
|
|
if ($object->isExternal()) {
|
|
|
|
|
$type = 'ExternalCommand';
|
|
|
|
|
} elseif ($object->isTemplate()) {
|
|
|
|
|
$type = 'CommandTemplate';
|
|
|
|
|
} else {
|
|
|
|
|
$type = 'Command';
|
|
|
|
|
}
|
|
|
|
|
} elseif ($object instanceof IcingaServiceSet) {
|
2018-10-25 02:38:24 -04:00
|
|
|
$type = 'ServiceSet';
|
|
|
|
|
} elseif ($object->isTemplate()) {
|
2018-10-30 11:41:49 -04:00
|
|
|
$type = ucfirst($this->getType()) . 'Template';
|
2018-10-15 08:49:47 -04:00
|
|
|
} 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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-16 17:53:37 -04:00
|
|
|
protected function addTemplate()
|
2015-06-30 05:19:31 -04:00
|
|
|
{
|
2017-08-16 17:53:37 -04:00
|
|
|
$this->assertPermission('director/admin');
|
|
|
|
|
$this->addTitle(
|
|
|
|
|
$this->translate('Add new Icinga %s template'),
|
|
|
|
|
$this->getTranslatedType()
|
2015-06-30 05:19:31 -04:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-16 17:53:37 -04:00
|
|
|
protected function addObject()
|
|
|
|
|
{
|
2017-10-12 10:26:50 -04:00
|
|
|
$this->assertTypePermission();
|
2017-08-16 17:53:37 -04:00
|
|
|
$imports = $this->params->get('imports');
|
|
|
|
|
if (is_string($imports) && strlen($imports)) {
|
|
|
|
|
$this->addTitle(
|
|
|
|
|
$this->translate('Add %s: %s'),
|
|
|
|
|
$this->getTranslatedType(),
|
|
|
|
|
$imports
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
$this->addTitle(
|
|
|
|
|
$this->translate('Add new Icinga %s'),
|
|
|
|
|
$this->getTranslatedType()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function redirectToPreviewForExternals()
|
|
|
|
|
{
|
2024-10-22 08:31:14 -04:00
|
|
|
if (
|
|
|
|
|
$this->object
|
2017-08-16 17:53:37 -04:00
|
|
|
&& $this->object->isExternal()
|
|
|
|
|
&& ! in_array($this->object->getShortTableName(), $this->allowedExternals)
|
|
|
|
|
) {
|
|
|
|
|
$this->redirectNow(
|
|
|
|
|
$this->getRequest()->getUrl()->setPath(sprintf('director/%s/render', $this->getType()))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function getType()
|
|
|
|
|
{
|
|
|
|
|
if ($this->type === null) {
|
|
|
|
|
// Strip final 's' and upcase an eventual 'group'
|
|
|
|
|
$this->type = preg_replace(
|
|
|
|
|
array('/group$/', '/period$/', '/argument$/', '/apiuser$/', '/set$/'),
|
|
|
|
|
array('Group', 'Period', 'Argument', 'ApiUser', 'Set'),
|
|
|
|
|
$this->getRequest()->getControllerName()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function getPluralType()
|
|
|
|
|
{
|
|
|
|
|
return $this->getType() . 's';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function getTranslatedType()
|
|
|
|
|
{
|
|
|
|
|
return $this->translate(ucfirst($this->getType()));
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-12 10:26:50 -04:00
|
|
|
protected function assertTypePermission()
|
|
|
|
|
{
|
2021-04-23 06:33:42 -04:00
|
|
|
$type = strtolower($this->getPluralType());
|
|
|
|
|
// TODO: Check getPluralType usage, fix it there.
|
|
|
|
|
if ($type === 'scheduleddowntimes') {
|
|
|
|
|
$type = 'scheduled-downtimes';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->assertPermission("director/$type");
|
2017-10-12 10:26:50 -04:00
|
|
|
}
|
|
|
|
|
|
2021-10-05 17:10:50 -04:00
|
|
|
protected function loadOptionalObject()
|
2017-08-16 02:08:08 -04:00
|
|
|
{
|
2021-10-05 17:10:50 -04:00
|
|
|
if ($this->params->get('uuid') || null !== $this->params->get('name') || $this->params->get('id')) {
|
2017-08-16 02:08:08 -04:00
|
|
|
$this->loadObject();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 17:10:50 -04:00
|
|
|
/**
|
|
|
|
|
* @return ?UuidInterface
|
|
|
|
|
* @throws InvalidPropertyException
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
*/
|
|
|
|
|
protected function getUuidFromUrl()
|
2015-06-30 05:19:31 -04:00
|
|
|
{
|
2021-10-05 17:10:50 -04:00
|
|
|
$key = null;
|
|
|
|
|
if ($uuid = $this->params->get('uuid')) {
|
|
|
|
|
$key = Uuid::fromString($uuid);
|
|
|
|
|
} elseif ($id = $this->params->get('id')) {
|
2021-08-16 05:43:09 -04:00
|
|
|
$key = (int) $id;
|
|
|
|
|
} elseif (null !== ($name = $this->params->get('name'))) {
|
|
|
|
|
$key = $name;
|
|
|
|
|
}
|
|
|
|
|
if ($key === null) {
|
2021-10-05 17:10:50 -04:00
|
|
|
$request = $this->getRequest();
|
|
|
|
|
if ($request->isApiRequest() && $request->isGet()) {
|
2021-08-16 05:43:09 -04:00
|
|
|
$this->getResponse()->setHttpResponseCode(422);
|
2016-03-06 14:24:47 -05:00
|
|
|
|
2021-08-16 05:43:09 -04:00
|
|
|
throw new InvalidPropertyException(
|
|
|
|
|
'Cannot load object, missing parameters'
|
|
|
|
|
);
|
2016-03-06 08:20:49 -05:00
|
|
|
}
|
2016-02-27 06:23:00 -05:00
|
|
|
|
2021-10-05 17:10:50 -04:00
|
|
|
return null;
|
2021-08-16 05:43:09 -04:00
|
|
|
}
|
2021-10-05 17:10:50 -04:00
|
|
|
|
|
|
|
|
return $this->requireUuid($key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function loadObject()
|
|
|
|
|
{
|
|
|
|
|
if ($this->object) {
|
|
|
|
|
throw new ProgrammingError('Loading an object twice is not very efficient');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->object = $this->loadSpecificObject($this->getTableName(), $this->getUuidFromUrl(), true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function loadSpecificObject($tableName, $key, $showHint = false)
|
|
|
|
|
{
|
2021-08-16 05:43:09 -04:00
|
|
|
$branch = $this->getBranch();
|
2021-10-05 17:10:50 -04:00
|
|
|
$branchedObject = BranchedObject::load($this->db(), $tableName, $key, $branch);
|
|
|
|
|
$object = $branchedObject->getBranchedDbObject($this->db());
|
|
|
|
|
assert($object instanceof IcingaObject);
|
|
|
|
|
$object->setBeingLoadedFromDb();
|
2021-08-16 05:43:09 -04:00
|
|
|
if (! $this->allowsObject($object)) {
|
|
|
|
|
throw new NotFoundError('No such object available');
|
|
|
|
|
}
|
2022-12-16 08:16:02 -05:00
|
|
|
if ($showHint) {
|
|
|
|
|
$hasPreferredBranch = $this->hasPreferredBranch();
|
2024-10-22 08:31:14 -04:00
|
|
|
if (
|
|
|
|
|
($hasPreferredBranch || $branch->isBranch())
|
2022-12-16 08:16:02 -05:00
|
|
|
&& $object->isObject()
|
|
|
|
|
&& ! $this->getRequest()->isApiRequest()
|
|
|
|
|
) {
|
|
|
|
|
$this->content()->add(
|
|
|
|
|
new BranchedObjectHint($branch, $this->Auth(), $branchedObject, $hasPreferredBranch)
|
|
|
|
|
);
|
|
|
|
|
}
|
2015-06-30 05:19:31 -04:00
|
|
|
}
|
|
|
|
|
|
2021-10-05 17:10:50 -04:00
|
|
|
return $object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function requireUuid($key)
|
|
|
|
|
{
|
|
|
|
|
if (! $key instanceof UuidInterface) {
|
|
|
|
|
$key = UuidLookup::findUuidForKey($key, $this->getTableName(), $this->db(), $this->getBranch());
|
|
|
|
|
if ($key === null) {
|
|
|
|
|
throw new NotFoundError('No such object available');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $key;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function getTableName()
|
|
|
|
|
{
|
|
|
|
|
return DbObjectTypeRegistry::tableNameByType($this->getType());
|
2015-06-30 05:19:31 -04:00
|
|
|
}
|
2016-02-02 18:54:00 -05:00
|
|
|
|
2017-08-16 17:53:37 -04:00
|
|
|
protected function addDeploymentLink()
|
2017-07-31 04:34:57 -04:00
|
|
|
{
|
2017-10-20 04:23:23 -04:00
|
|
|
try {
|
|
|
|
|
$info = new DeploymentInfo($this->db());
|
|
|
|
|
$info->setObject($this->object);
|
|
|
|
|
|
|
|
|
|
if (! $this->getRequest()->isApiRequest()) {
|
2021-08-16 05:43:09 -04:00
|
|
|
if ($this->getBranch()->isBranch()) {
|
|
|
|
|
$this->actions()->add($this->linkToMergeBranch($this->getBranch()));
|
|
|
|
|
} else {
|
|
|
|
|
$this->actions()->add(
|
|
|
|
|
DeploymentLinkForm::create(
|
|
|
|
|
$this->db(),
|
|
|
|
|
$info,
|
|
|
|
|
$this->Auth(),
|
|
|
|
|
$this->api()
|
2026-02-17 09:52:50 -05:00
|
|
|
)
|
|
|
|
|
->callOnSuccess(function () {
|
|
|
|
|
$this->getResponse()->setHeader('X-Icinga-Extra-Updates', '#col1');
|
|
|
|
|
})
|
|
|
|
|
->handleRequest()
|
2021-08-16 05:43:09 -04:00
|
|
|
);
|
2026-02-17 09:52:50 -05:00
|
|
|
|
2026-03-26 04:28:03 -04:00
|
|
|
if (
|
|
|
|
|
DirectorDeploymentLog::hasDeployments($this->db())
|
|
|
|
|
&& (new DeploymentDashlet($this->db()))->lastDeploymentPending()
|
|
|
|
|
) {
|
2026-02-17 09:52:50 -05:00
|
|
|
$this->actions()->prependHtml(
|
|
|
|
|
Hint::warning($this->translate(
|
|
|
|
|
'There is an active deployment running, please wait until it is finished'
|
|
|
|
|
. ' before creating a new deployment.'
|
|
|
|
|
))
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-08-16 05:43:09 -04:00
|
|
|
}
|
2017-10-20 04:23:23 -04:00
|
|
|
}
|
|
|
|
|
} catch (IcingaException $e) {
|
|
|
|
|
// pass (deployment may not be set up yet)
|
2017-07-31 04:34:57 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-16 05:43:09 -04:00
|
|
|
protected function linkToMergeBranch(Branch $branch)
|
|
|
|
|
{
|
2021-08-23 02:55:30 -04:00
|
|
|
$link = Branch::requireHook()->linkToBranch($branch, $this->Auth(), $this->translate('Merge'));
|
2021-08-16 05:43:09 -04:00
|
|
|
if ($link instanceof Link) {
|
|
|
|
|
$link->addAttributes(['class' => 'icon-flapping']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $link;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-16 17:53:37 -04:00
|
|
|
protected function addBackToObjectLink()
|
2016-02-02 18:54:00 -05:00
|
|
|
{
|
2019-03-19 10:29:08 -04:00
|
|
|
$params = [
|
2021-10-18 01:27:28 -04:00
|
|
|
'uuid' => $this->object->getUniqueId()->toString(),
|
2019-03-19 10:29:08 -04:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if ($this->object instanceof IcingaService) {
|
|
|
|
|
if (($host = $this->object->get('host')) !== null) {
|
|
|
|
|
$params['host'] = $host;
|
2019-03-19 10:43:20 -04:00
|
|
|
} elseif (($set = $this->object->get('service_set')) !== null) {
|
2019-03-19 10:29:08 -04:00
|
|
|
$params['set'] = $set;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-16 17:53:37 -04:00
|
|
|
$this->actions()->add(Link::create(
|
|
|
|
|
$this->translate('back'),
|
2020-11-30 04:17:44 -05:00
|
|
|
$this->getObjectBaseUrl(),
|
2019-03-19 10:29:08 -04:00
|
|
|
$params,
|
2017-08-16 17:53:37 -04:00
|
|
|
['class' => 'icon-left-big']
|
|
|
|
|
));
|
2016-02-02 18:54:00 -05:00
|
|
|
|
2017-08-16 17:53:37 -04:00
|
|
|
return $this;
|
|
|
|
|
}
|
2016-02-02 18:54:00 -05:00
|
|
|
|
2026-01-29 09:22:40 -05:00
|
|
|
protected function addObjectForm(?IcingaObject $object = null)
|
2017-08-16 17:53:37 -04:00
|
|
|
{
|
|
|
|
|
$form = $this->loadObjectForm($object);
|
|
|
|
|
$this->content()->add($form);
|
|
|
|
|
$form->handleRequest();
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
2016-02-02 18:54:00 -05:00
|
|
|
|
2026-01-29 09:22:40 -05:00
|
|
|
protected function loadObjectForm(?IcingaObject $object = null)
|
2017-08-16 17:53:37 -04:00
|
|
|
{
|
|
|
|
|
/** @var DirectorObjectForm $class */
|
|
|
|
|
$class = sprintf(
|
|
|
|
|
'Icinga\\Module\\Director\\Forms\\Icinga%sForm',
|
|
|
|
|
ucfirst($this->getType())
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$form = $class::load()
|
|
|
|
|
->setDb($this->db())
|
|
|
|
|
->setAuth($this->Auth());
|
2016-02-02 18:54:00 -05:00
|
|
|
|
2017-08-16 17:53:37 -04:00
|
|
|
if ($object !== null) {
|
|
|
|
|
$form->setObject($object);
|
2016-02-02 18:54:00 -05:00
|
|
|
}
|
2021-08-16 05:43:09 -04:00
|
|
|
if (true || $form->supportsBranches()) {
|
2021-08-25 07:00:56 -04:00
|
|
|
$form->setBranch($this->getBranch());
|
2021-08-16 05:43:09 -04:00
|
|
|
}
|
2017-08-16 17:53:37 -04:00
|
|
|
|
|
|
|
|
$this->onObjectFormLoaded($form);
|
|
|
|
|
|
|
|
|
|
return $form;
|
2016-02-02 18:54:00 -05:00
|
|
|
}
|
2016-02-17 13:22:36 -05:00
|
|
|
|
2020-11-30 04:17:44 -05:00
|
|
|
protected function getObjectBaseUrl()
|
|
|
|
|
{
|
|
|
|
|
return $this->objectBaseUrl ?: 'director/' . strtolower($this->getType());
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
protected function hasBasketSupport()
|
|
|
|
|
{
|
|
|
|
|
return $this->object->isTemplate() || $this->object->isGroup();
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-16 17:53:37 -04:00
|
|
|
protected function onObjectFormLoaded(DirectorObjectForm $form)
|
2016-02-27 06:23:00 -05:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-15 08:49:47 -04:00
|
|
|
/**
|
|
|
|
|
* @return IcingaObject
|
|
|
|
|
* @throws NotFoundError
|
|
|
|
|
*/
|
2016-02-17 13:22:36 -05:00
|
|
|
protected function requireObject()
|
|
|
|
|
{
|
|
|
|
|
if (! $this->object) {
|
|
|
|
|
$this->getResponse()->setHttpResponseCode(404);
|
2017-07-31 04:34:57 -04:00
|
|
|
if (null === $this->params->get('name')) {
|
2016-02-17 13:22:36 -05:00
|
|
|
throw new NotFoundError('You need to pass a "name" parameter to access a specific object');
|
|
|
|
|
} else {
|
|
|
|
|
throw new NotFoundError('No such object available');
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-05-25 02:11:53 -04:00
|
|
|
|
2017-07-28 18:12:34 -04:00
|
|
|
return $this->object;
|
2016-03-18 06:44:48 -04:00
|
|
|
}
|
2021-10-05 17:10:50 -04:00
|
|
|
|
|
|
|
|
protected function showOptionalBranchActivity($activityTable)
|
|
|
|
|
{
|
|
|
|
|
$branch = $this->getBranch();
|
|
|
|
|
if ($branch->isBranch() && (int) $this->params->get('page', '1') === 1) {
|
|
|
|
|
$table = new BranchActivityTable($branch->getUuid(), $this->db(), $this->object->getUniqueId());
|
|
|
|
|
if (count($table) > 0) {
|
|
|
|
|
$this->content()->add(Hint::info(Html::sprintf($this->translate(
|
|
|
|
|
'The following modifications are visible in this %s only...'
|
|
|
|
|
), Branch::requireHook()->linkToBranch(
|
|
|
|
|
$branch,
|
|
|
|
|
$this->Auth(),
|
|
|
|
|
$this->translate('configuration branch')
|
|
|
|
|
))));
|
|
|
|
|
$this->content()->add($table);
|
|
|
|
|
if (count($activityTable) === 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$this->content()->add(Html::tag('br'));
|
|
|
|
|
$this->content()->add(Hint::ok($this->translate(
|
|
|
|
|
'...and the modifications below are already in the main branch:'
|
|
|
|
|
)));
|
|
|
|
|
$this->content()->add(Html::tag('br'));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-30 05:19:31 -04:00
|
|
|
}
|