mirror of
https://github.com/Icinga/icingadb-web.git
synced 2026-05-28 04:36:06 -04:00
Add command transport configuration UI
This commit is contained in:
parent
c6832d5740
commit
2e8acdcba7
10 changed files with 446 additions and 1 deletions
147
application/controllers/CommandTransportController.php
Normal file
147
application/controllers/CommandTransportController.php
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Controllers;
|
||||
|
||||
use GuzzleHttp\Psr7\ServerRequest;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Forms\ConfirmRemovalForm;
|
||||
use Icinga\Module\Icingadb\Command\Transport\CommandTransportConfig;
|
||||
use Icinga\Module\Icingadb\Forms\ApiTransportForm;
|
||||
use Icinga\Module\Icingadb\Widget\ItemList\CommandTransportList;
|
||||
use ipl\Html\HtmlString;
|
||||
use ipl\Web\Widget\ButtonLink;
|
||||
|
||||
class CommandTransportController extends ConfigController
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->assertPermission('config/modules');
|
||||
}
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
$list = new CommandTransportList((new CommandTransportConfig())->select());
|
||||
|
||||
$this->addControl(
|
||||
(new ButtonLink(
|
||||
t('Create Command Transport'),
|
||||
'icingadb/command-transport/add',
|
||||
'plus'
|
||||
))->setBaseTarget('_next')
|
||||
);
|
||||
|
||||
$this->addContent($list);
|
||||
|
||||
$this->mergeTabs($this->Module()->getConfigTabs());
|
||||
$this->getTabs()->disableLegacyExtensions();
|
||||
$this->view->title = $this->getTabs()
|
||||
->activate('command-transports')
|
||||
->getActiveTab()
|
||||
->getLabel();
|
||||
}
|
||||
|
||||
public function showAction()
|
||||
{
|
||||
$transportName = $this->params->getRequired('name');
|
||||
|
||||
$transportConfig = (new CommandTransportConfig())
|
||||
->select()
|
||||
->where('name', $transportName)
|
||||
->fetchRow();
|
||||
if ($transportConfig === false) {
|
||||
$this->httpNotFound(t('Unknown transport'));
|
||||
}
|
||||
|
||||
$form = new ApiTransportForm();
|
||||
$form->populate((array) $transportConfig);
|
||||
$form->on(ApiTransportForm::ON_SUCCESS, function (ApiTransportForm $form) use ($transportName) {
|
||||
(new CommandTransportConfig())->update(
|
||||
'transport',
|
||||
$form->getValues(),
|
||||
Filter::where('name', $transportName)
|
||||
);
|
||||
|
||||
$this->redirectNow('icingadb/command-transport');
|
||||
});
|
||||
|
||||
$form->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
$this->addContent($form);
|
||||
|
||||
$this->setTitle(sprintf($this->translate('Command Transport: %s'), $transportName));
|
||||
$this->getTabs()->disableLegacyExtensions();
|
||||
}
|
||||
|
||||
public function addAction()
|
||||
{
|
||||
$form = new ApiTransportForm();
|
||||
$form->on(ApiTransportForm::ON_SUCCESS, function (ApiTransportForm $form) {
|
||||
(new CommandTransportConfig())->insert('transport', $form->getValues());
|
||||
$this->redirectNow('icingadb/command-transport');
|
||||
});
|
||||
|
||||
$form->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
$this->addContent($form);
|
||||
|
||||
$this->setTitle($this->translate('Add Command Transport'));
|
||||
$this->getTabs()->disableLegacyExtensions();
|
||||
}
|
||||
|
||||
public function removeAction()
|
||||
{
|
||||
$transportName = $this->params->getRequired('name');
|
||||
|
||||
$form = new ConfirmRemovalForm();
|
||||
$form->setAttrib('style', 'text-align:center;');
|
||||
$form->setOnSuccess(function () use ($transportName) {
|
||||
(new CommandTransportConfig())->delete(
|
||||
'transport',
|
||||
Filter::where('name', $transportName)
|
||||
);
|
||||
|
||||
$this->redirectNow('icingadb/command-transport');
|
||||
});
|
||||
|
||||
$form->handleRequest();
|
||||
|
||||
$this->addContent(HtmlString::create($form->render()));
|
||||
|
||||
$this->setTitle($this->translate('Remove Command Transport: %s'), $transportName);
|
||||
$this->getTabs()->disableLegacyExtensions();
|
||||
}
|
||||
|
||||
public function sortAction()
|
||||
{
|
||||
$transportName = $this->params->getRequired('name');
|
||||
$newPosition = (int) $this->params->getRequired('pos');
|
||||
|
||||
$config = $this->Config('commandtransports');
|
||||
if (! $config->hasSection($transportName)) {
|
||||
$this->httpNotFound(t('Unknown transport'));
|
||||
}
|
||||
|
||||
if ($newPosition < 0 || $newPosition > $config->count()) {
|
||||
$this->httpBadRequest(t('Position out of bounds'));
|
||||
}
|
||||
|
||||
$transports = $config->getConfigObject()->toArray();
|
||||
$transportNames = array_keys($transports);
|
||||
|
||||
array_splice($transportNames, array_search($transportName, $transportNames, true), 1);
|
||||
array_splice($transportNames, $newPosition, 0, [$transportName]);
|
||||
|
||||
$sortedTransports = [];
|
||||
foreach ($transportNames as $name) {
|
||||
$sortedTransports[$name] = $transports[$name];
|
||||
}
|
||||
|
||||
$newConfig = Config::fromArray($sortedTransports);
|
||||
$newConfig->saveIni($config->getConfigFile());
|
||||
|
||||
$this->redirectNow('icingadb/command-transport');
|
||||
}
|
||||
}
|
||||
102
application/forms/ApiTransportForm.php
Normal file
102
application/forms/ApiTransportForm.php
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Forms;
|
||||
|
||||
use Icinga\Data\ConfigObject;
|
||||
use Icinga\Module\Icingadb\Command\Transport\CommandTransport;
|
||||
use Icinga\Module\Icingadb\Command\Transport\CommandTransportException;
|
||||
use Icinga\Web\Session;
|
||||
use ipl\Web\Common\CsrfCounterMeasure;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
|
||||
class ApiTransportForm extends CompatForm
|
||||
{
|
||||
use CsrfCounterMeasure;
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
// TODO: Use a validator to check if a name is not already in use
|
||||
$this->addElement('text', 'name', [
|
||||
'required' => true,
|
||||
'label' => t('Transport Name')
|
||||
]);
|
||||
|
||||
$this->addElement('hidden', 'transport', [
|
||||
'value' => 'api'
|
||||
]);
|
||||
|
||||
$this->addElement('text', 'host', [
|
||||
'required' => true,
|
||||
'id' => 'api_transport_host',
|
||||
'label' => t('Host'),
|
||||
'description' => t('Hostname or address of the Icinga master')
|
||||
]);
|
||||
|
||||
// TODO: Don't rely only on browser validation
|
||||
$this->addElement('number', 'port', [
|
||||
'required' => true,
|
||||
'label' => t('Port'),
|
||||
'value' => 5665,
|
||||
'min' => 1,
|
||||
'max' => 65536
|
||||
]);
|
||||
|
||||
$this->addElement('text', 'username', [
|
||||
'required' => true,
|
||||
'label' => t('API Username'),
|
||||
'description' => t('User to authenticate with using HTTP Basic Auth')
|
||||
]);
|
||||
|
||||
// TODO: Use a password element
|
||||
$this->addElement('text', 'password', [
|
||||
'required' => true,
|
||||
'label' => t('API Password')
|
||||
]);
|
||||
|
||||
$this->addElement('submit', 'btn_submit', [
|
||||
'label' => t('Save')
|
||||
]);
|
||||
|
||||
$this->addElement($this->createCsrfCounterMeasure(Session::getSession()->getId()));
|
||||
}
|
||||
|
||||
public function validate()
|
||||
{
|
||||
parent::validate();
|
||||
if (! $this->isValid) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($this->getPopulatedValue('force_creation') === 'n') {
|
||||
return $this;
|
||||
}
|
||||
|
||||
try {
|
||||
CommandTransport::createTransport(new ConfigObject($this->getValues()))->probe();
|
||||
} catch (CommandTransportException $e) {
|
||||
$this->addMessage(
|
||||
sprintf(t('Failed to successfully validate the configuration: %s'), $e->getMessage())
|
||||
);
|
||||
|
||||
$forceCheckbox = $this->createElement(
|
||||
'checkbox',
|
||||
'force_creation',
|
||||
[
|
||||
'ignore' => true,
|
||||
'label' => t('Force Changes'),
|
||||
'description' => t('Check this box to enforce changes without connectivity validation')
|
||||
]
|
||||
);
|
||||
|
||||
$this->registerElement($forceCheckbox);
|
||||
$this->decorate($forceCheckbox);
|
||||
$this->prepend($forceCheckbox);
|
||||
|
||||
$this->isValid = false;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
@ -212,7 +212,7 @@ namespace Icinga\Module\Icingadb
|
|||
$this->provideConfigTab('command-transports', [
|
||||
'label' => t('Command Transports'),
|
||||
'title' => t('Configure command transports'),
|
||||
'url' => 'config/command-transports'
|
||||
'url' => 'command-transport'
|
||||
]);
|
||||
$this->provideConfigTab('security', [
|
||||
'label' => t('Security'),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Command\Transport;
|
||||
|
||||
use Icinga\Repository\IniRepository;
|
||||
|
||||
class CommandTransportConfig extends IniRepository
|
||||
{
|
||||
protected $configs = [
|
||||
'transport' => [
|
||||
'name' => 'commandtransports',
|
||||
'module' => 'icingadb',
|
||||
'keyColumn' => 'name'
|
||||
]
|
||||
];
|
||||
|
||||
protected $queryColumns = [
|
||||
'transport' => [
|
||||
'name',
|
||||
'transport',
|
||||
|
||||
// API options
|
||||
'host',
|
||||
'port',
|
||||
'username',
|
||||
'password'
|
||||
]
|
||||
];
|
||||
}
|
||||
33
library/Icingadb/Common/BaseOrderedItemList.php
Normal file
33
library/Icingadb/Common/BaseOrderedItemList.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Common;
|
||||
|
||||
use Icinga\Module\Icingadb\Widget\BaseItemList;
|
||||
|
||||
/**
|
||||
* @method BaseOrderedListItem getItemClass()
|
||||
*/
|
||||
abstract class BaseOrderedItemList extends BaseItemList
|
||||
{
|
||||
protected $tag = 'ol';
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
$itemClass = $this->getItemClass();
|
||||
|
||||
$i = 0;
|
||||
foreach ($this->data as $data) {
|
||||
$item = new $itemClass($data, $this);
|
||||
$item->setOrder($i++);
|
||||
|
||||
$this->add($item);
|
||||
}
|
||||
|
||||
if ($this->isEmpty()) {
|
||||
$this->setTag('div');
|
||||
$this->add(new EmptyState(t('No items found.')));
|
||||
}
|
||||
}
|
||||
}
|
||||
37
library/Icingadb/Common/BaseOrderedListItem.php
Normal file
37
library/Icingadb/Common/BaseOrderedListItem.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Common;
|
||||
|
||||
use Icinga\Module\Icingadb\Widget\BaseListItem;
|
||||
|
||||
abstract class BaseOrderedListItem extends BaseListItem
|
||||
{
|
||||
/** @var int This element's position */
|
||||
protected $order;
|
||||
|
||||
/**
|
||||
* Set this element's position
|
||||
*
|
||||
* @param int $order
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOrder($order)
|
||||
{
|
||||
$this->order = (int) $order;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this element's position
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,8 @@ use ipl\Web\Url;
|
|||
|
||||
/**
|
||||
* Base class for item lists
|
||||
*
|
||||
* @todo Move this to Icinga\Module\Icingadb\Common
|
||||
*/
|
||||
abstract class BaseItemList extends BaseHtmlElement
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ use ipl\Web\Filter\QueryString;
|
|||
|
||||
/**
|
||||
* Base class for list items
|
||||
*
|
||||
* @todo Move this to Icinga\Module\Icingadb\Common
|
||||
*/
|
||||
abstract class BaseListItem extends BaseHtmlElement
|
||||
{
|
||||
|
|
|
|||
22
library/Icingadb/Widget/ItemList/CommandTransportList.php
Normal file
22
library/Icingadb/Widget/ItemList/CommandTransportList.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Widget\ItemList;
|
||||
|
||||
use Icinga\Module\Icingadb\Common\BaseOrderedItemList;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class CommandTransportList extends BaseOrderedItemList
|
||||
{
|
||||
protected function init()
|
||||
{
|
||||
$this->getAttributes()->add('class', 'command-transport-list');
|
||||
$this->setDetailUrl(Url::fromPath('icingadb/command-transport/show'));
|
||||
}
|
||||
|
||||
protected function getItemClass()
|
||||
{
|
||||
return CommandTransportListItem::class;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/* Icinga DB Web | (c) 2021 Icinga GmbH | GPLv2 */
|
||||
|
||||
namespace Icinga\Module\Icingadb\Widget\ItemList;
|
||||
|
||||
use Icinga\Module\Icingadb\Common\BaseOrderedListItem;
|
||||
use ipl\Html\BaseHtmlElement;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Stdlib\Filter;
|
||||
use ipl\Web\Url;
|
||||
use ipl\Web\Widget\Icon;
|
||||
use ipl\Web\Widget\Link;
|
||||
|
||||
class CommandTransportListItem extends BaseOrderedListItem
|
||||
{
|
||||
protected function init()
|
||||
{
|
||||
$this->setDetailFilter(Filter::equal('name', $this->item->name));
|
||||
}
|
||||
|
||||
protected function assembleHeader(BaseHtmlElement $header)
|
||||
{
|
||||
}
|
||||
|
||||
protected function assembleMain(BaseHtmlElement $main)
|
||||
{
|
||||
$main->add(new Link(
|
||||
new HtmlElement('strong', null, $this->item->name),
|
||||
Url::fromPath('icingadb/command-transport/show', ['name' => $this->item->name])
|
||||
));
|
||||
|
||||
$main->add(new Link(
|
||||
new Icon('trash', ['title' => sprintf(t('Remove command transport "%s"'), $this->item->name)]),
|
||||
Url::fromPath('icingadb/command-transport/remove', ['name' => $this->item->name]),
|
||||
[
|
||||
'class' => 'pull-right action-link',
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]
|
||||
));
|
||||
|
||||
if ($this->getOrder() + 1 < $this->list->count()) {
|
||||
$main->add((new Link(
|
||||
new Icon('arrow-down'),
|
||||
Url::fromPath('icingadb/command-transport/sort', [
|
||||
'name' => $this->item->name,
|
||||
'pos' => $this->getOrder() + 1
|
||||
]),
|
||||
['class' => 'pull-right action-link']
|
||||
))->setBaseTarget('_self'));
|
||||
}
|
||||
|
||||
if ($this->getOrder() > 0) {
|
||||
$main->add((new Link(
|
||||
new Icon('arrow-up'),
|
||||
Url::fromPath('icingadb/command-transport/sort', [
|
||||
'name' => $this->item->name,
|
||||
'pos' => $this->getOrder() - 1
|
||||
]),
|
||||
['class' => 'pull-right action-link']
|
||||
))->setBaseTarget('_self'));
|
||||
}
|
||||
}
|
||||
|
||||
protected function createVisual()
|
||||
{
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue