Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add redundancy group detail view #1079

Draft
wants to merge 9 commits into
base: dependencies
Choose a base branch
from
349 changes: 349 additions & 0 deletions application/controllers/RedundancygroupController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,349 @@
<?php

/* Icinga DB Web | (c) 2024 Icinga GmbH | GPLv2 */

namespace Icinga\Module\Icingadb\Controllers;

use Icinga\Exception\NotFoundError;
use Icinga\Module\Icingadb\Common\CommandActions;
use Icinga\Module\Icingadb\Data\DependencyNodes;
use Icinga\Module\Icingadb\Model\DependencyNode;
use Icinga\Module\Icingadb\Model\RedundancyGroup;
use Icinga\Module\Icingadb\Model\RedundancyGroupSummary;
use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions;
use Icinga\Module\Icingadb\Web\Control\ViewModeSwitcher;
use Icinga\Module\Icingadb\Web\Controller;
use Icinga\Module\Icingadb\Widget\Detail\MultiselectQuickActions;
use Icinga\Module\Icingadb\Widget\Detail\RedundancyGroupDetail;
use Icinga\Module\Icingadb\Widget\Detail\RedundancyGroupHeader;
use Icinga\Module\Icingadb\Widget\ItemList\DependencyNodeList;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\Orm\Query;
use ipl\Stdlib\Filter;
use ipl\Web\Control\LimitControl;
use ipl\Web\Control\SortControl;
use ipl\Web\Url;
use ipl\Web\Widget\Tabs;

class RedundancygroupController extends Controller
{
use CommandActions;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

override the process check result action, it won't work after all and isn't provided in the quick action bar


/** @var string */
protected $groupId;

/** @var RedundancyGroup */
protected $group;

public function init(): void
{
// in case of quick actions, param id is not given
$groupId = $this->params->shift('child.redundancy_group.id');
if ($groupId === null) {
$groupId = $this->params->shiftRequired('id');
}

$this->groupId = $groupId;

Check failure on line 47 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest

Property Icinga\Module\Icingadb\Controllers\RedundancygroupController::$groupId (string) does not accept mixed.

Check failure on line 47 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest

Property Icinga\Module\Icingadb\Controllers\RedundancygroupController::$groupId (string) does not accept mixed.
}

/**
* Load the redundancy group
*/
protected function loadGroup(): void
{
$query = RedundancyGroup::on($this->getDb())
->with(['state'])
->filter(Filter::equal('id', $this->groupId));

$this->applyRestrictions($query);

$this->group = $query->first();

Check failure on line 61 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest

Property Icinga\Module\Icingadb\Controllers\RedundancygroupController::$group (Icinga\Module\Icingadb\Model\RedundancyGroup) does not accept ipl\Orm\Model|null.

Check failure on line 61 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest

Property Icinga\Module\Icingadb\Controllers\RedundancygroupController::$group (Icinga\Module\Icingadb\Model\RedundancyGroup) does not accept ipl\Orm\Model|null.

if ($this->group === null) {
throw new NotFoundError($this->translate('Redundancy Group not found'));
}

$this->setTitleTab($this->getRequest()->getActionName());
$this->setTitle($this->group->display_name);

$summary = RedundancyGroupSummary::on($this->getDb())
->filter(Filter::equal('id', $this->groupId));

$this->applyRestrictions($summary);

$this->addControl(new RedundancyGroupHeader($this->group, $summary->first()));

Check failure on line 75 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest

Parameter #2 $summary of class Icinga\Module\Icingadb\Widget\Detail\RedundancyGroupHeader constructor expects Icinga\Module\Icingadb\Model\RedundancyGroupSummary, ipl\Orm\Model|null given.

Check failure on line 75 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest

Parameter #2 $summary of class Icinga\Module\Icingadb\Widget\Detail\RedundancyGroupHeader constructor expects Icinga\Module\Icingadb\Model\RedundancyGroupSummary, ipl\Orm\Model|null given.
}

public function indexAction(): void
{
$this->loadGroup();
$summary = RedundancyGroupSummary::on($this->getDb())
->filter(Filter::equal('id', $this->groupId));

$this->filter($summary);

$this->addControl(
(new MultiselectQuickActions('dependency_node', $summary->first()))
->setBaseFilter(Filter::equal('child.redundancy_group.id', $this->groupId))
->allowToProcessCheckResults(false)
->setColumnPrefix('nodes')
->setUrlPath('icingadb/redundancygroup')
);

$this->addContent(new RedundancyGroupDetail($this->group));
}

public function membersAction(): void
{
$this->loadGroup();
$nodesQuery = $this->fetchNodes(true);

$limitControl = $this->createLimitControl();
$paginationControl = $this->createPaginationControl($nodesQuery);
$sortControl = $this->createSortControl($nodesQuery);
$viewModeSwitcher = $this->createViewModeSwitcher($paginationControl, $limitControl);

$searchBar = $this->createSearchBar(
$nodesQuery,
Url::fromPath('icingadb/redundancygroup/members', ['id' => $this->groupId]),
[
$limitControl->getLimitParam(),
$sortControl->getSortParam(),
$viewModeSwitcher->getViewModeParam(),
'id'
]
);

if ($searchBar->hasBeenSent() && ! $searchBar->isValid()) {
if ($searchBar->hasBeenSubmitted()) {
$filter = $this->getFilter();
} else {
$this->addControl($searchBar);
$this->sendMultipartUpdate();
return;
}
} else {
$filter = $searchBar->getFilter();
}

$nodesQuery->filter($filter);

$this->addControl($paginationControl);
$this->addControl($sortControl);
$this->addControl($limitControl);
$this->addControl($viewModeSwitcher);
$this->addControl($searchBar);

$this->addContent(
(new DependencyNodeList($nodesQuery->execute()))
->setViewMode($viewModeSwitcher->getViewMode())
);

if (! $searchBar->hasBeenSubmitted() && $searchBar->hasBeenSent()) {
$this->sendMultipartUpdate();
}

$this->setAutorefreshInterval(10);
}

public function childrenAction(): void
{
$this->loadGroup();
$nodesQuery = $this->fetchNodes();

$limitControl = $this->createLimitControl();
$paginationControl = $this->createPaginationControl($nodesQuery);
$sortControl = $this->createSortControl($nodesQuery);
$viewModeSwitcher = $this->createViewModeSwitcher($paginationControl, $limitControl);

$searchBar = $this->createSearchBar(
$nodesQuery,
Url::fromPath('icingadb/redundancygroup/children', ['id' => $this->groupId]),
[
$limitControl->getLimitParam(),
$sortControl->getSortParam(),
$viewModeSwitcher->getViewModeParam(),
'id'
]
);

$searchBar->getSuggestionUrl()->setParam('isChildrenTab');
$searchBar->getEditorUrl()->setParam('isChildrenTab');

if ($searchBar->hasBeenSent() && ! $searchBar->isValid()) {
if ($searchBar->hasBeenSubmitted()) {
$filter = $this->getFilter();
} else {
$this->addControl($searchBar);
$this->sendMultipartUpdate();
return;
}
} else {
$filter = $searchBar->getFilter();
}

$nodesQuery->filter($filter);

$this->addControl($paginationControl);
$this->addControl($sortControl);
$this->addControl($limitControl);
$this->addControl($viewModeSwitcher);
$this->addControl($searchBar);

$this->addContent(
(new DependencyNodeList($nodesQuery->execute()))
->setViewMode($viewModeSwitcher->getViewMode())
);

if (! $searchBar->hasBeenSubmitted() && $searchBar->hasBeenSent()) {
$this->sendMultipartUpdate();
}

$this->setAutorefreshInterval(10);
}

public function completeAction(): void
{
$isChildrenTab = $this->params->shift('isChildrenTab');
$column = $isChildrenTab ? 'parent' : 'child';

$suggestions = (new ObjectSuggestions())
->setModel(DependencyNode::class)
->setBaseFilter(Filter::equal("$column.redundancy_group.id", $this->groupId))
->forRequest($this->getServerRequest());

$this->getDocument()->add($suggestions);
}

public function searchEditorAction(): void
{
$isChildrenTab = $this->params->shift('isChildrenTab');
$redirectUrl = $isChildrenTab
? Url::fromPath('icingadb/redundancygroup/children', ['id' => $this->groupId])
: Url::fromPath('icingadb/redundancygroup/members', ['id' => $this->groupId]);

$editor = $this->createSearchEditor(
DependencyNode::on($this->getDb()),
$redirectUrl,
[
LimitControl::DEFAULT_LIMIT_PARAM,
SortControl::DEFAULT_SORT_PARAM,
ViewModeSwitcher::DEFAULT_VIEW_MODE_PARAM,
'id'
]
);

if ($isChildrenTab) {
$editor->getSuggestionUrl()->setParam('isChildrenTab');

Check failure on line 238 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest

Cannot call method setParam() on ipl\Web\Url|null.

Check failure on line 238 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest

Cannot call method setParam() on ipl\Web\Url|null.
}

$this->getDocument()->add($editor);
$this->setTitle($this->translate('Adjust Filter'));
}

protected function createTabs(): Tabs
{
$tabs = $this->getTabs()
->add('index', [
'label' => $this->translate('Redundancy Group'),
'url' => Url::fromPath('icingadb/redundancygroup', ['id' => $this->groupId])
])
->add('members', [
'label' => $this->translate('Members'),
'url' => Url::fromPath('icingadb/redundancygroup/members', ['id' => $this->groupId])
])
->add('children', [
'label' => $this->translate('Children'),
'url' => Url::fromPath('icingadb/redundancygroup/children', ['id' => $this->groupId])
]);

return $tabs;
}

protected function setTitleTab(string $name): void
{
$tab = $this->createTabs()->get($name);

if ($tab !== null) {
$this->getTabs()->activate($name);
}
}

public function createSortControl(Query $query, array $columns = null): SortControl

Check failure on line 273 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest

Method Icinga\Module\Icingadb\Controllers\RedundancygroupController::createSortControl() has parameter $columns with no value type specified in iterable type array.

Check failure on line 273 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest

Method Icinga\Module\Icingadb\Controllers\RedundancygroupController::createSortControl() has parameter $columns with no value type specified in iterable type array.
{
$sortRules = [
'host.display_name, service.display_name, redundancy_group.display_name' => $this->translate('Name'),
'service.state.severity desc, service.state.last_state_change desc, '
. 'host.state.severity desc, host.state.last_state_change desc, '
. 'redundancy_group.state.failed desc, redundancy_group.state.last_state_change desc' => $this->translate(
'Severity'
),
'service.state.soft_state, host.state.soft_state, redundancy_group.state.failed' => $this->translate(
'Current State'
),
'service.state.last_state_change desc, host.state.last_state_change desc, '
. 'redundancy_group.state.last_state_change desc' => $this->translate('Last State Change')
];

return parent::createSortControl($query, $sortRules);
}

/**
* Fetch the nodes for the current group
*
* @param bool $fetchParents Whether to fetch the parents or the children
*
* @return Query
*/
private function fetchNodes(bool $fetchParents = false): Query
{
$filterColumn = sprintf(
'%s.redundancy_group.id',
$fetchParents ? 'child' : 'parent'
);

return DependencyNode::on($this->getDb())
->with([
'host',
'host.state',
'service',
'service.state',
'service.host',
'service.host.state'
])
->filter(Filter::equal($filterColumn, $this->groupId));
}

protected function fetchCommandTargets()

Check failure on line 318 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.3 on ubuntu-latest

Method Icinga\Module\Icingadb\Controllers\RedundancygroupController::fetchCommandTargets() has no return type specified.

Check failure on line 318 in application/controllers/RedundancygroupController.php

View workflow job for this annotation

GitHub Actions / phpstan / Static analysis with phpstan and php 7.2 on ubuntu-latest

Method Icinga\Module\Icingadb\Controllers\RedundancygroupController::fetchCommandTargets() has no return type specified.
{
$filter = Filter::all(Filter::equal('child.redundancy_group.id', $this->groupId));

if ($this->getRequest()->getActionName() === 'acknowledge') {
$filter->add(
Filter::any(
Filter::all(
Filter::unlike('child.service.id', '*'),
Filter::equal('host.state.is_problem', 'y'),
Filter::equal('host.state.is_acknowledged', 'n')
),
Filter::all(
Filter::equal('service.state.is_problem', 'y'),
Filter::equal('service.state.is_acknowledged', 'n')
)
)
);
}

return new DependencyNodes($filter);
}

protected function getCommandTargetsUrl(): Url
{
return Url::fromPath('icingadb/redundancygroup', ['id' => $this->groupId]);
}

public function processCheckresultAction(): void
{
}
}
8 changes: 6 additions & 2 deletions library/Icingadb/Authentication/ObjectAuthorization.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Icinga\Module\Icingadb\Common\Auth;
use Icinga\Module\Icingadb\Common\Database;
use Icinga\Module\Icingadb\Model\DependencyNode;
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Model\Service;
use InvalidArgumentException;
Expand Down Expand Up @@ -85,6 +86,9 @@ public static function grantsOnType(string $permission, string $type, Filter\Rul
case 'service':
$for = Service::class;
break;
case 'dependency_node':
$for = DependencyNode::class;
break;
default:
throw new InvalidArgumentException(sprintf('Unknown type "%s"', $type));
}
Expand Down Expand Up @@ -161,13 +165,13 @@ protected function loadGrants(string $model, Filter\Rule $filter, string $cacheK
$roleFilter->add($this->parseRestriction($restriction, 'icingadb/filter/objects'));
}

if ($tableName === 'host' || $tableName === 'service') {
if ($tableName === 'host' || $tableName === 'service' || $tableName === 'dependency_node') {
if (($restriction = $role->getRestrictions('icingadb/filter/hosts'))) {
$roleFilter->add($this->parseRestriction($restriction, 'icingadb/filter/hosts'));
}
}

if ($tableName === 'service' && ($restriction = $role->getRestrictions('icingadb/filter/services'))) {
if (($tableName === 'dependency_node' || $tableName === 'service') && ($restriction = $role->getRestrictions('icingadb/filter/services'))) {
$roleFilter->add($this->parseRestriction($restriction, 'icingadb/filter/services'));
}

Expand Down
Loading
Loading