mirror of
				https://github.com/Icinga/icingaweb2-module-director.git
				synced 2025-10-31 03:14:33 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			547 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			547 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| namespace Icinga\Module\Director\Web\Controller;
 | |
| 
 | |
| use gipfl\IcingaWeb2\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\Data\Db\DbObjectStore;
 | |
| use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
 | |
| 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;
 | |
| use Icinga\Module\Director\Web\ActionBar\ObjectsActionBar;
 | |
| use Icinga\Module\Director\Web\ActionBar\TemplateActionBar;
 | |
| use Icinga\Module\Director\Web\Form\FormLoader;
 | |
| use Icinga\Module\Director\Web\Table\ApplyRulesTable;
 | |
| use Icinga\Module\Director\Web\Table\ObjectSetTable;
 | |
| use Icinga\Module\Director\Web\Table\ObjectsTable;
 | |
| use Icinga\Module\Director\Web\Table\TemplatesTable;
 | |
| use Icinga\Module\Director\Web\Tabs\ObjectsTabs;
 | |
| use Icinga\Module\Director\Web\Tree\TemplateTreeRenderer;
 | |
| use gipfl\IcingaWeb2\Link;
 | |
| use Icinga\Module\Director\Web\Widget\AdditionalTableActions;
 | |
| use Icinga\Module\Director\Web\Widget\BranchedObjectsHint;
 | |
| use InvalidArgumentException;
 | |
| use Ramsey\Uuid\Uuid;
 | |
| 
 | |
| abstract class ObjectsController extends ActionController
 | |
| {
 | |
|     use BranchHelper;
 | |
| 
 | |
|     protected $isApified = true;
 | |
| 
 | |
|     /** @var ObjectsTable */
 | |
|     protected $table;
 | |
| 
 | |
|     protected function checkDirectorPermissions()
 | |
|     {
 | |
|         if ($this->getRequest()->getActionName() !== 'sets') {
 | |
|             $this->assertPermission('director/' . $this->getPluralBaseType());
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return $this
 | |
|      * @throws \Icinga\Exception\Http\HttpNotFoundException
 | |
|      */
 | |
|     protected function addObjectsTabs()
 | |
|     {
 | |
|         $tabName = $this->getRequest()->getActionName();
 | |
|         if (substr($this->getType(), -5) === 'Group') {
 | |
|             $tabName = 'groups';
 | |
|         }
 | |
|         $this->tabs(new ObjectsTabs(
 | |
|             $this->getBaseType(),
 | |
|             $this->Auth(),
 | |
|             $this->getBaseObjectUrl()
 | |
|         ))->activate($tabName);
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return IcingaObjectsHandler
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     protected function apiRequestHandler()
 | |
|     {
 | |
|         $request = $this->getRequest();
 | |
|         $table = $this->getTable();
 | |
|         if ($request->getControllerName() === 'services'
 | |
|             && $host = $this->params->get('host')
 | |
|         ) {
 | |
|             $host = IcingaHost::load($host, $this->db());
 | |
|             $table->getQuery()->where('o.host_id = ?', $host->get('id'));
 | |
|         }
 | |
| 
 | |
|         if ($request->getActionName() === 'templates') {
 | |
|             $table->filterObjectType('template');
 | |
|         } elseif ($request->getActionName() === 'applyrules') {
 | |
|             $table->filterObjectType('apply');
 | |
|         }
 | |
|         $search = $this->params->get('q');
 | |
|         if ($search !== null && \strlen($search) > 0) {
 | |
|             $table->search($search);
 | |
|         }
 | |
| 
 | |
|         return (new IcingaObjectsHandler(
 | |
|             $request,
 | |
|             $this->getResponse(),
 | |
|             $this->db()
 | |
|         ))->setTable($table);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @throws \Icinga\Exception\Http\HttpNotFoundException
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     public function indexAction()
 | |
|     {
 | |
|         if ($this->getRequest()->isApiRequest()) {
 | |
|             $this->apiRequestHandler()->dispatch();
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         $type = $this->getType();
 | |
|         if ($this->params->get('format') === 'json') {
 | |
|             $filename = sprintf(
 | |
|                 "director-${type}_%s.json",
 | |
|                 date('YmdHis')
 | |
|             );
 | |
|             $this->getResponse()->setHeader('Content-disposition', "attachment; filename=$filename", true);
 | |
|             $this->apiRequestHandler()->dispatch();
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         $this
 | |
|             ->addObjectsTabs()
 | |
|             ->setAutorefreshInterval(10)
 | |
|             ->addTitle($this->translate(ucfirst($this->getPluralType())))
 | |
|             ->actions(new ObjectsActionBar($this->getBaseObjectUrl(), $this->url()));
 | |
| 
 | |
|         $this->content()->add(new BranchedObjectsHint($this->getBranch(), $this->Auth()));
 | |
| 
 | |
|         if ($type === 'command' && $this->params->get('type') === 'external_object') {
 | |
|             $this->tabs()->activate('external');
 | |
|         }
 | |
| 
 | |
|         // Hint: might be used in controllers extending this
 | |
|         $this->table = $this->eventuallyFilterCommand($this->getTable());
 | |
| 
 | |
|         $this->table->renderTo($this);
 | |
|         (new AdditionalTableActions($this->getAuth(), $this->url(), $this->table))
 | |
|             ->appendTo($this->actions());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return ObjectsTable
 | |
|      */
 | |
|     protected function getTable()
 | |
|     {
 | |
|         $table = ObjectsTable::create($this->getType(), $this->db())
 | |
|             ->setAuth($this->getAuth())
 | |
|             ->setBranchUuid($this->getBranchUuid())
 | |
|             ->setBaseObjectUrl($this->getBaseObjectUrl());
 | |
| 
 | |
|         return $table;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return ApplyRulesTable
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     protected function getApplyRulesTable()
 | |
|     {
 | |
|         $table = new ApplyRulesTable($this->db());
 | |
|         $table->setType($this->getType())
 | |
|             ->setBaseObjectUrl($this->getBaseObjectUrl());
 | |
|         $this->eventuallyFilterCommand($table);
 | |
| 
 | |
|         return $table;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     public function edittemplatesAction()
 | |
|     {
 | |
|         $this->commonForEdit();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     public function editAction()
 | |
|     {
 | |
|         $this->commonForEdit();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     public function commonForEdit()
 | |
|     {
 | |
|         $type = ucfirst($this->getType());
 | |
| 
 | |
|         if (empty($this->multiEdit)) {
 | |
|             throw new NotFoundError('Cannot edit multiple "%s" instances', $type);
 | |
|         }
 | |
| 
 | |
|         $objects = $this->loadMultiObjectsFromParams();
 | |
|         if (empty($objects)) {
 | |
|             throw new NotFoundError('No "%s" instances have been loaded', $type);
 | |
|         }
 | |
|         $formName = 'icinga' . $type;
 | |
|         $form = IcingaMultiEditForm::load()
 | |
|             ->setBranch($this->getBranch())
 | |
|             ->setObjects($objects)
 | |
|             ->pickElementsFrom($this->loadForm($formName), $this->multiEdit);
 | |
|         if ($type === 'Service') {
 | |
|             $form->setListUrl('director/services');
 | |
|         } elseif ($type === 'Host') {
 | |
|             $form->setListUrl('director/hosts');
 | |
|         }
 | |
| 
 | |
|         $form->handleRequest();
 | |
| 
 | |
|         $this
 | |
|             ->addSingleTab($this->translate('Multiple objects'))
 | |
|             ->addTitle(
 | |
|                 $this->translate('Modify %d objects'),
 | |
|                 count($objects)
 | |
|             )->content()->add($form);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Loads the TemplatesTable or the TemplateTreeRenderer
 | |
|      *
 | |
|      * Passing render=tree switches to the tree view.
 | |
|      * @throws \Icinga\Exception\Http\HttpNotFoundException
 | |
|      * @throws \Icinga\Security\SecurityException
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     public function templatesAction()
 | |
|     {
 | |
|         if ($this->getRequest()->isApiRequest()) {
 | |
|             $this->apiRequestHandler()->dispatch();
 | |
|             return;
 | |
|         }
 | |
|         $type = $this->getType();
 | |
| 
 | |
|         if ($this->params->get('format') === 'json') {
 | |
|             $filename = sprintf(
 | |
|                 "director-${type}-templates_%s.json",
 | |
|                 date('YmdHis')
 | |
|             );
 | |
|             $this->getResponse()->setHeader('Content-disposition', "attachment; filename=$filename", true);
 | |
|             $this->apiRequestHandler()->dispatch();
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         $shortType = IcingaObject::createByType($type)->getShortTableName();
 | |
|         $this
 | |
|             ->assertPermission('director/admin')
 | |
|             ->addObjectsTabs()
 | |
|             ->setAutorefreshInterval(10)
 | |
|             ->addTitle(
 | |
|                 $this->translate('All your %s Templates'),
 | |
|                 $this->translate(ucfirst($type))
 | |
|             )
 | |
|             ->actions(new TemplateActionBar($shortType, $this->url()));
 | |
| 
 | |
|         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);
 | |
|             (new AdditionalTableActions($this->getAuth(), $this->url(), $table))
 | |
|                 ->appendTo($this->actions());
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return $this
 | |
|      * @throws \Icinga\Security\SecurityException
 | |
|      */
 | |
|     protected function assertApplyRulePermission()
 | |
|     {
 | |
|         return $this->assertPermission('director/admin');
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @throws \Icinga\Exception\Http\HttpNotFoundException
 | |
|      * @throws \Icinga\Security\SecurityException
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     public function applyrulesAction()
 | |
|     {
 | |
|         if ($this->getRequest()->isApiRequest()) {
 | |
|             $this->apiRequestHandler()->dispatch();
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         $type = $this->getType();
 | |
| 
 | |
|         if ($this->params->get('format') === 'json') {
 | |
|             $filename = sprintf(
 | |
|                 "director-${type}-applyrules_%s.json",
 | |
|                 date('YmdHis')
 | |
|             );
 | |
|             $this->getResponse()->setHeader('Content-disposition', "attachment; filename=$filename", true);
 | |
|             $this->apiRequestHandler()->dispatch();
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         $tType = $this->translate(ucfirst($type));
 | |
|         $this
 | |
|             ->assertApplyRulePermission()
 | |
|             ->addObjectsTabs()
 | |
|             ->setAutorefreshInterval(10)
 | |
|             ->addTitle(
 | |
|                 $this->translate('All your %s Apply Rules'),
 | |
|                 $tType
 | |
|             );
 | |
|         $baseUrl = 'director/' . $this->getBaseObjectUrl();
 | |
|         $this->actions()
 | |
|             //->add($this->getBackToDashboardLink())
 | |
|             ->add(
 | |
|                 Link::create(
 | |
|                     $this->translate('Add'),
 | |
|                     "${baseUrl}/add",
 | |
|                     ['type' => 'apply'],
 | |
|                     [
 | |
|                         'title' => sprintf(
 | |
|                             $this->translate('Create a new %s Apply Rule'),
 | |
|                             $tType
 | |
|                         ),
 | |
|                         'class' => 'icon-plus',
 | |
|                         'data-base-target' => '_next'
 | |
|                     ]
 | |
|                 )
 | |
|             );
 | |
| 
 | |
|         $table = $this->getApplyRulesTable();
 | |
|         $table->renderTo($this);
 | |
|         (new AdditionalTableActions($this->getAuth(), $this->url(), $table))
 | |
|             ->appendTo($this->actions());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @throws NotFoundError
 | |
|      * @throws \Icinga\Exception\Http\HttpNotFoundException
 | |
|      * @throws \Icinga\Security\SecurityException
 | |
|      */
 | |
|     public function setsAction()
 | |
|     {
 | |
|         $type = $this->getType();
 | |
|         $tType = $this->translate(ucfirst($type));
 | |
|         $this
 | |
|             ->assertPermission('director/' . $this->getBaseType() . 'sets')
 | |
|             ->addObjectsTabs()
 | |
|             ->requireSupportFor('Sets')
 | |
|             ->setAutorefreshInterval(10)
 | |
|             ->addTitle(
 | |
|                 $this->translate('Icinga %s Sets'),
 | |
|                 $tType
 | |
|             );
 | |
| 
 | |
|         $this->actions()->add(
 | |
|             Link::create(
 | |
|                 $this->translate('Add'),
 | |
|                 "director/${type}set/add",
 | |
|                 null,
 | |
|                 [
 | |
|                     'title' => sprintf(
 | |
|                         $this->translate('Create a new %s Set'),
 | |
|                         $tType
 | |
|                     ),
 | |
|                     'class' => 'icon-plus',
 | |
|                     'data-base-target' => '_next'
 | |
|                 ]
 | |
|             )
 | |
|         );
 | |
| 
 | |
|         ObjectSetTable::create($type, $this->db(), $this->getAuth())->renderTo($this);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return array
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     protected function loadMultiObjectsFromParams()
 | |
|     {
 | |
|         $filter = Filter::fromQueryString($this->params->toString());
 | |
|         $type = $this->getType();
 | |
|         $objects = array();
 | |
|         $db = $this->db();
 | |
|         $class = DbObjectTypeRegistry::classByType($type);
 | |
|         $table = DbObjectTypeRegistry::tableNameByType($type);
 | |
|         $store = new DbObjectStore($db, $this->getBranch());
 | |
| 
 | |
|         /** @var $filter FilterChain */
 | |
|         foreach ($filter->filters() as $sub) {
 | |
|             /** @var $sub FilterChain */
 | |
|             foreach ($sub->filters() as $ex) {
 | |
|                 /** @var $ex FilterChain|FilterExpression */
 | |
|                 $col = $ex->getColumn();
 | |
|                 if ($ex->isExpression()) {
 | |
|                     if ($col === 'name') {
 | |
|                         $name = $ex->getExpression();
 | |
|                         if ($type === 'service') {
 | |
|                             $key = [
 | |
|                                 'object_type' => 'template',
 | |
|                                 'object_name' => $name
 | |
|                             ];
 | |
|                         } else {
 | |
|                             $key = $name;
 | |
|                         }
 | |
|                         $objects[$name] = $class::load($key, $db);
 | |
|                     } elseif ($col === 'id') {
 | |
|                         $name = $ex->getExpression();
 | |
|                         $objects[$name] = $class::load($name, $db);
 | |
|                     } elseif ($col === 'uuid') {
 | |
|                         $object = $store->load($table, Uuid::fromString($ex->getExpression()));
 | |
|                         $objects[$object->getObjectName()] = $object;
 | |
|                     } else {
 | |
|                         throw new InvalidArgumentException("'$col' is no a valid key component for '$type'");
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return $objects;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param string $name
 | |
|      *
 | |
|      * @return \Icinga\Module\Director\Web\Form\QuickForm
 | |
|      */
 | |
|     public function loadForm($name)
 | |
|     {
 | |
|         $form = FormLoader::load($name, $this->Module());
 | |
|         if ($this->getRequest()->isApiRequest()) {
 | |
|             // TODO: Ask form for API support?
 | |
|             $form->setApiRequest();
 | |
|         }
 | |
| 
 | |
|         return $form;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param ZfQueryBasedTable $table
 | |
|      * @return ZfQueryBasedTable
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     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
 | |
|      * @throws NotFoundError
 | |
|      */
 | |
|     protected function requireSupportFor($feature)
 | |
|     {
 | |
|         if ($this->supports($feature) !== true) {
 | |
|             throw new NotFoundError(
 | |
|                 '%s does not support %s',
 | |
|                 $this->getType(),
 | |
|                 $feature
 | |
|             );
 | |
|         }
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param $feature
 | |
|      * @return bool
 | |
|      */
 | |
|     protected function supports($feature)
 | |
|     {
 | |
|         $func = "supports$feature";
 | |
|         return IcingaObject::createByType($this->getType())->$func();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     protected function getBaseType()
 | |
|     {
 | |
|         $type = $this->getType();
 | |
|         if (substr($type, -5) === 'Group') {
 | |
|             return substr($type, 0, -5);
 | |
|         } else {
 | |
|             return $type;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     protected function getBaseObjectUrl()
 | |
|     {
 | |
|         return $this->getType();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     protected function getType()
 | |
|     {
 | |
|         // Strip final 's' and upcase an eventual 'group'
 | |
|         return preg_replace(
 | |
|             array('/group$/', '/period$/', '/argument$/', '/apiuser$/', '/dependencie$/', '/set$/'),
 | |
|             array('Group', 'Period', 'Argument', 'ApiUser', 'dependency', 'Set'),
 | |
|             str_replace(
 | |
|                 'template',
 | |
|                 '',
 | |
|                 substr($this->getRequest()->getControllerName(), 0, -1)
 | |
|             )
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     protected function getPluralType()
 | |
|     {
 | |
|         return preg_replace('/cys$/', 'cies', $this->getType() . 's');
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     protected function getPluralBaseType()
 | |
|     {
 | |
|         return preg_replace('/cys$/', 'cies', $this->getBaseType() . 's');
 | |
|     }
 | |
| }
 |