diff options
Diffstat (limited to 'application/controllers/HostController.php')
-rw-r--r-- | application/controllers/HostController.php | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/application/controllers/HostController.php b/application/controllers/HostController.php new file mode 100644 index 0000000..259dd33 --- /dev/null +++ b/application/controllers/HostController.php @@ -0,0 +1,293 @@ +<?php + +/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Icingadb\Controllers; + +use ArrayIterator; +use Icinga\Exception\NotFoundError; +use Icinga\Module\Icingadb\Command\Object\GetObjectCommand; +use Icinga\Module\Icingadb\Command\Transport\CommandTransport; +use Icinga\Module\Icingadb\Common\CommandActions; +use Icinga\Module\Icingadb\Common\HostLinks; +use Icinga\Module\Icingadb\Common\Links; +use Icinga\Module\Icingadb\Hook\TabHook\HookActions; +use Icinga\Module\Icingadb\Model\History; +use Icinga\Module\Icingadb\Model\Host; +use Icinga\Module\Icingadb\Model\Service; +use Icinga\Module\Icingadb\Model\ServicestateSummary; +use Icinga\Module\Icingadb\Redis\VolatileStateResults; +use Icinga\Module\Icingadb\Web\Controller; +use Icinga\Module\Icingadb\Widget\Detail\HostDetail; +use Icinga\Module\Icingadb\Widget\Detail\HostInspectionDetail; +use Icinga\Module\Icingadb\Widget\Detail\HostMetaInfo; +use Icinga\Module\Icingadb\Widget\Detail\QuickActions; +use Icinga\Module\Icingadb\Widget\ItemList\HostList; +use Icinga\Module\Icingadb\Widget\ItemList\HistoryList; +use Icinga\Module\Icingadb\Widget\ItemList\ServiceList; +use ipl\Stdlib\Filter; +use ipl\Web\Url; +use ipl\Web\Widget\Tabs; + +class HostController extends Controller +{ + use CommandActions; + use HookActions; + + /** @var Host The host object */ + protected $host; + + public function init() + { + $name = $this->params->getRequired('name'); + + $query = Host::on($this->getDb())->with(['state', 'icon_image', 'timeperiod']); + $query + ->setResultSetClass(VolatileStateResults::class) + ->filter(Filter::equal('host.name', $name)); + + $this->applyRestrictions($query); + + /** @var Host $host */ + $host = $query->first(); + if ($host === null) { + throw new NotFoundError(t('Host not found')); + } + + $this->host = $host; + $this->loadTabsForObject($host); + + $this->setTitleTab($this->getRequest()->getActionName()); + $this->setTitle($host->display_name); + } + + public function indexAction() + { + $serviceSummary = ServicestateSummary::on($this->getDb()); + $serviceSummary->filter(Filter::equal('service.host_id', $this->host->id)); + + $this->applyRestrictions($serviceSummary); + + if ($this->host->state->is_overdue) { + $this->controls->addAttributes(['class' => 'overdue']); + } + + $this->addControl((new HostList([$this->host])) + ->setViewMode('objectHeader') + ->setDetailActionsDisabled() + ->setNoSubjectLink()); + $this->addControl(new HostMetaInfo($this->host)); + $this->addControl(new QuickActions($this->host)); + + $this->addContent(new HostDetail($this->host, $serviceSummary->first())); + + $this->setAutorefreshInterval(10); + } + + public function sourceAction() + { + $this->assertPermission('icingadb/object/show-source'); + + $apiResult = (new CommandTransport())->send( + (new GetObjectCommand()) + ->setObjects(new ArrayIterator([$this->host])) + ); + + if ($this->host->state->is_overdue) { + $this->controls->addAttributes(['class' => 'overdue']); + } + + $this->addControl((new HostList([$this->host])) + ->setViewMode('objectHeader') + ->setDetailActionsDisabled() + ->setNoSubjectLink()); + $this->addContent(new HostInspectionDetail( + $this->host, + reset($apiResult) + )); + } + + public function historyAction() + { + $compact = $this->view->compact; // TODO: Find a less-legacy way.. + + if ($this->host->state->is_overdue) { + $this->controls->addAttributes(['class' => 'overdue']); + } + + $db = $this->getDb(); + + $history = History::on($db)->with([ + 'host', + 'host.state', + 'comment', + 'downtime', + 'flapping', + 'notification', + 'acknowledgement', + 'state' + ]); + + $history->filter(Filter::all( + Filter::equal('history.host_id', $this->host->id), + Filter::unlike('history.service_id', '*') + )); + + $before = $this->params->shift('before', time()); + $url = Url::fromRequest()->setParams(clone $this->params); + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($history); + $sortControl = $this->createSortControl( + $history, + [ + 'history.event_time desc, history.event_type desc' => t('Event Time') + ] + ); + $viewModeSwitcher = $this->createViewModeSwitcher($paginationControl, $limitControl, true); + + $history->peekAhead(); + + $page = $paginationControl->getCurrentPageNumber(); + + if ($page > 1 && ! $compact) { + $history->limit($page * $limitControl->getLimit()); + } + + $history->filter(Filter::lessThanOrEqual('event_time', $before)); + + yield $this->export($history); + + $this->addControl((new HostList([$this->host])) + ->setViewMode('objectHeader') + ->setDetailActionsDisabled() + ->setNoSubjectLink()); + $this->addControl($sortControl); + $this->addControl($limitControl); + $this->addControl($viewModeSwitcher); + + $historyList = (new HistoryList($history->execute())) + ->setViewMode($viewModeSwitcher->getViewMode()) + ->setPageSize($limitControl->getLimit()) + ->setLoadMoreUrl($url->setParam('before', $before)); + + if ($compact) { + $historyList->setPageNumber($page); + } + + if ($compact && $page > 1) { + $this->document->addFrom($historyList); + } else { + $this->addContent($historyList); + } + } + + public function servicesAction() + { + if ($this->host->state->is_overdue) { + $this->controls->addAttributes(['class' => 'overdue']); + } + + $db = $this->getDb(); + + $services = Service::on($db)->with([ + 'state', + 'state.last_comment', + 'icon_image', + 'host', + 'host.state' + ]); + $services + ->setResultSetClass(VolatileStateResults::class) + ->filter(Filter::equal('host.id', $this->host->id)); + + $this->applyRestrictions($services); + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($services); + $viewModeSwitcher = $this->createViewModeSwitcher($paginationControl, $limitControl); + $sortControl = $this->createSortControl( + $services, + [ + 'service.display_name' => t('Name'), + 'service.state.severity desc,service.state.last_state_change desc' => t('Severity'), + 'service.state.soft_state' => t('Current State'), + 'service.state.last_state_change desc' => t('Last State Change') + ] + ); + + yield $this->export($services); + + $serviceList = (new ServiceList($services)) + ->setViewMode($viewModeSwitcher->getViewMode()); + + $this->addControl((new HostList([$this->host])) + ->setViewMode('objectHeader') + ->setDetailActionsDisabled() + ->setNoSubjectLink()); + $this->addControl($paginationControl); + $this->addControl($sortControl); + $this->addControl($limitControl); + $this->addControl($viewModeSwitcher); + + $this->addContent($serviceList); + + $this->setAutorefreshInterval(10); + } + + protected function createTabs(): Tabs + { + $tabs = $this->getTabs() + ->add('index', [ + 'label' => t('Host'), + 'url' => Links::host($this->host) + ]) + ->add('services', [ + 'label' => t('Services'), + 'url' => HostLinks::services($this->host) + ]) + ->add('history', [ + 'label' => t('History'), + 'url' => HostLinks::history($this->host) + ]); + + if ($this->hasPermission('icingadb/object/show-source')) { + $tabs->add('source', [ + 'label' => t('Source'), + 'url' => Links::hostSource($this->host) + ]); + } + + foreach ($this->loadAdditionalTabs() as $name => $tab) { + $tabs->add($name, $tab + ['urlParams' => ['name' => $this->host->name]]); + } + + return $tabs; + } + + protected function setTitleTab(string $name) + { + $tab = $this->createTabs()->get($name); + + if ($tab !== null) { + $tab->setActive(); + + $this->setTitle($tab->getLabel()); + } + } + + protected function fetchCommandTargets(): array + { + return [$this->host]; + } + + protected function getCommandTargetsUrl(): Url + { + return Links::host($this->host); + } + + protected function getDefaultTabControls(): array + { + return [(new HostList([$this->host]))->setDetailActionsDisabled()->setNoSubjectLink()]; + } +} |