summaryrefslogtreecommitdiffstats
path: root/modules/monitoring/application/forms/Config
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--modules/monitoring/application/forms/Config/BackendConfigForm.php367
-rw-r--r--modules/monitoring/application/forms/Config/SecurityConfigForm.php75
-rw-r--r--modules/monitoring/application/forms/Config/Transport/ApiTransportForm.php75
-rw-r--r--modules/monitoring/application/forms/Config/Transport/LocalTransportForm.php37
-rw-r--r--modules/monitoring/application/forms/Config/Transport/RemoteTransportForm.php185
-rw-r--r--modules/monitoring/application/forms/Config/TransportConfigForm.php392
-rw-r--r--modules/monitoring/application/forms/Config/TransportReorderForm.php87
7 files changed, 1218 insertions, 0 deletions
diff --git a/modules/monitoring/application/forms/Config/BackendConfigForm.php b/modules/monitoring/application/forms/Config/BackendConfigForm.php
new file mode 100644
index 0000000..5ed42e1
--- /dev/null
+++ b/modules/monitoring/application/forms/Config/BackendConfigForm.php
@@ -0,0 +1,367 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Config;
+
+use Exception;
+use InvalidArgumentException;
+use Icinga\Application\Config;
+use Icinga\Data\ConfigObject;
+use Icinga\Data\ResourceFactory;
+use Icinga\Exception\ConfigurationError;
+use Icinga\Exception\IcingaException;
+use Icinga\Exception\NotFoundError;
+use Icinga\Forms\ConfigForm;
+use Icinga\Web\Form;
+
+/**
+ * Form for managing monitoring backends
+ */
+class BackendConfigForm extends ConfigForm
+{
+ /**
+ * The available monitoring backend resources split by type
+ *
+ * @var array
+ */
+ protected $resources;
+
+ /**
+ * The backend to load when displaying the form for the first time
+ *
+ * @var string
+ */
+ protected $backendToLoad;
+
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->setName('form_config_monitoring_backends');
+ $this->setSubmitLabel($this->translate('Save Changes'));
+ }
+
+ /**
+ * Set the resource configuration to use
+ *
+ * @param Config $resourceConfig The resource configuration
+ *
+ * @return $this
+ *
+ * @throws ConfigurationError In case there are no valid monitoring backend resources
+ */
+ public function setResourceConfig(Config $resourceConfig)
+ {
+ $resources = array();
+ foreach ($resourceConfig as $name => $resource) {
+ if ($resource->type === 'db') {
+ $resources['ido'][$name] = $name;
+ }
+ }
+
+ if (empty($resources)) {
+ throw new ConfigurationError($this->translate(
+ 'Could not find any valid monitoring backend resources. Please configure a database resource first.'
+ ));
+ }
+
+ $this->resources = $resources;
+ return $this;
+ }
+
+ /**
+ * Populate the form with the given backend's config
+ *
+ * @param string $name
+ *
+ * @return $this
+ *
+ * @throws NotFoundError In case no backend with the given name is found
+ */
+ public function load($name)
+ {
+ if (! $this->config->hasSection($name)) {
+ throw new NotFoundError('No monitoring backend called "%s" found', $name);
+ }
+
+ $this->backendToLoad = $name;
+ return $this;
+ }
+
+ /**
+ * Add a new monitoring backend
+ *
+ * The backend to add is identified by the array-key `name'.
+ *
+ * @param array $data
+ *
+ * @return $this
+ *
+ * @throws InvalidArgumentException In case $data does not contain a backend name
+ * @throws IcingaException In case a backend with the same name already exists
+ */
+ public function add(array $data)
+ {
+ if (! isset($data['name'])) {
+ throw new InvalidArgumentException('Key \'name\' missing');
+ }
+
+ $backendName = $data['name'];
+ if ($this->config->hasSection($backendName)) {
+ throw new IcingaException(
+ $this->translate('A monitoring backend with the name "%s" does already exist'),
+ $backendName
+ );
+ }
+
+ unset($data['name']);
+ $this->config->setSection($backendName, $data);
+ return $this;
+ }
+
+ /**
+ * Edit a monitoring backend
+ *
+ * @param string $name
+ * @param array $data
+ *
+ * @return $this
+ *
+ * @throws NotFoundError In case no backend with the given name is found
+ */
+ public function edit($name, array $data)
+ {
+ if (! $this->config->hasSection($name)) {
+ throw new NotFoundError('No monitoring backend called "%s" found', $name);
+ }
+
+ $backendConfig = $this->config->getSection($name);
+ if (isset($data['name'])) {
+ if ($data['name'] !== $name) {
+ $this->config->removeSection($name);
+ $name = $data['name'];
+ }
+
+ unset($data['name']);
+ }
+
+ $backendConfig->merge($data);
+ $this->config->setSection($name, $backendConfig);
+ return $this;
+ }
+
+ /**
+ * Remove a monitoring backend
+ *
+ * @param string $name
+ *
+ * @return $this
+ */
+ public function delete($name)
+ {
+ $this->config->removeSection($name);
+ return $this;
+ }
+
+ /**
+ * Create and add elements to this form
+ *
+ * @param array $formData
+ */
+ public function createElements(array $formData)
+ {
+ $this->addElement(
+ 'checkbox',
+ 'disabled',
+ array(
+ 'label' => $this->translate('Disable This Backend')
+ )
+ );
+ $this->addElement(
+ 'text',
+ 'name',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Backend Name'),
+ 'description' => $this->translate(
+ 'The name of this monitoring backend that is used to differentiate it from others'
+ )
+ )
+ );
+
+ $resourceType = isset($formData['type']) ? $formData['type'] : null;
+
+ $resourceTypes = array();
+ if ($resourceType === 'ido' || array_key_exists('ido', $this->resources)) {
+ $resourceTypes['ido'] = 'IDO Backend';
+ }
+
+ if ($resourceType === null) {
+ $resourceType = key($resourceTypes);
+ }
+
+ $this->addElement(
+ 'select',
+ 'type',
+ array(
+ 'required' => true,
+ 'autosubmit' => true,
+ 'label' => $this->translate('Backend Type'),
+ 'description' => $this->translate(
+ 'The type of data source used for retrieving monitoring information'
+ ),
+ 'multiOptions' => $resourceTypes
+ )
+ );
+
+ $this->addElement(
+ 'select',
+ 'resource',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Resource'),
+ 'description' => $this->translate('The resource to use'),
+ 'multiOptions' => $this->resources[$resourceType],
+ 'value' => current($this->resources[$resourceType]),
+ 'autosubmit' => true
+ )
+ );
+ $resourceName = isset($formData['resource']) ? $formData['resource'] : $this->getValue('resource');
+ $this->addElement(
+ 'note',
+ 'resource_note',
+ array(
+ 'escape' => false,
+ 'value' => sprintf(
+ '<a href="%1$s" data-base-target="_next" title="%2$s" aria-label="%2$s">%3$s</a>',
+ $this->getView()->url('config/editresource', array('resource' => $resourceName)),
+ sprintf($this->translate('Show the configuration of the %s resource'), $resourceName),
+ $this->translate('Show resource configuration')
+ )
+ )
+ );
+
+ if (isset($formData['skip_validation']) && $formData['skip_validation']) {
+ // In case another error occured and the checkbox was displayed before
+ $this->addSkipValidationCheckbox();
+ }
+ }
+
+ /**
+ * Populate the configuration of the backend to load
+ */
+ public function onRequest()
+ {
+ if ($this->backendToLoad) {
+ $data = $this->config->getSection($this->backendToLoad)->toArray();
+ $data['name'] = $this->backendToLoad;
+ $this->populate($data);
+ }
+ }
+
+ /**
+ * Return whether the given values are valid
+ *
+ * @param array $formData The data to validate
+ *
+ * @return bool
+ */
+ public function isValid($formData)
+ {
+ if (! parent::isValid($formData)) {
+ return false;
+ }
+
+ if (($el = $this->getElement('skip_validation')) === null || false === $el->isChecked()) {
+ $resourceConfig = ResourceFactory::getResourceConfig($this->getValue('resource'));
+ if (! self::isValidIdoSchema($this, $resourceConfig)
+ || (! $this->getElement('disabled')->isChecked()
+ && ! self::isValidIdoInstance($this, $resourceConfig))
+ ) {
+ if ($el === null) {
+ $this->addSkipValidationCheckbox();
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Add a checkbox to the form by which the user can skip the schema validation
+ */
+ protected function addSkipValidationCheckbox()
+ {
+ $this->addElement(
+ 'checkbox',
+ 'skip_validation',
+ array(
+ 'order' => 0,
+ 'ignore' => true,
+ 'label' => $this->translate('Skip Validation'),
+ 'description' => $this->translate(
+ 'Check this to not to validate the IDO schema of the chosen resource.'
+ )
+ )
+ );
+ }
+
+ /**
+ * Return whether the given resource contains a valid IDO schema
+ *
+ * @param Form $form
+ * @param ConfigObject $resourceConfig
+ *
+ * @return bool
+ */
+ public static function isValidIdoSchema(Form $form, ConfigObject $resourceConfig)
+ {
+ try {
+ $db = ResourceFactory::createResource($resourceConfig);
+ $db->select()->from('icinga_dbversion', array('version'))->fetchOne();
+ } catch (Exception $_) {
+ $form->error($form->translate(
+ 'Cannot find the IDO schema. Please verify that the given database '
+ . 'contains the schema and that the configured user has access to it.'
+ ));
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Return whether a single icinga instance is writing to the given resource
+ *
+ * @param Form $form
+ * @param ConfigObject $resourceConfig
+ *
+ * @return bool True if it's a single instance, false if none
+ * or multiple instances are writing to it
+ */
+ public static function isValidIdoInstance(Form $form, ConfigObject $resourceConfig)
+ {
+ $db = ResourceFactory::createResource($resourceConfig);
+ $rowCount = $db->select()->from('icinga_instances')->count();
+
+ if ($rowCount === 0) {
+ $form->warning($form->translate(
+ 'There is currently no icinga instance writing to the IDO. Make sure '
+ . 'that a icinga instance is configured and able to write to the IDO.'
+ ));
+ return false;
+ } elseif ($rowCount > 1) {
+ $form->warning($form->translate(
+ 'There is currently more than one icinga instance writing to the IDO. You\'ll see all objects from all'
+ . ' instances without any differentation. If this is not desired, consider setting up a separate IDO'
+ . ' for each instance.'
+ ));
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Config/SecurityConfigForm.php b/modules/monitoring/application/forms/Config/SecurityConfigForm.php
new file mode 100644
index 0000000..d57f985
--- /dev/null
+++ b/modules/monitoring/application/forms/Config/SecurityConfigForm.php
@@ -0,0 +1,75 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Config;
+
+use Icinga\Web\Notification;
+use Icinga\Forms\ConfigForm;
+
+/**
+ * Form for modifying security relevant settings
+ */
+class SecurityConfigForm extends ConfigForm
+{
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->setName('form_config_monitoring_security');
+ $this->setSubmitLabel($this->translate('Save Changes'));
+ }
+
+ /**
+ * @see Form::onSuccess()
+ */
+ public function onSuccess()
+ {
+ $this->config->setSection('security', $this->getValues());
+
+ if ($this->save()) {
+ Notification::success($this->translate('New security configuration has successfully been stored'));
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @see Form::onRequest()
+ */
+ public function onRequest()
+ {
+ $this->populate($this->config->getSection('security')->toArray());
+ }
+
+ /**
+ * @see Form::createElements()
+ */
+ public function createElements(array $formData)
+ {
+ $this->addElement(
+ 'text',
+ 'protected_customvars',
+ array(
+ 'allowEmpty' => true,
+ 'attribs' => array('placeholder' => $this->getDefaultProtectedCustomvars()),
+ 'label' => $this->translate('Protected Custom Variables'),
+ 'description' => $this->translate(
+ 'Comma separated case insensitive list of protected custom variables.'
+ . ' Use * as a placeholder for zero or more wildcard characters.'
+ . ' Existence of those custom variables will be shown, but their values will be masked.'
+ )
+ )
+ );
+ }
+
+ /**
+ * Return the customvars to suggest to protect when none are protected
+ *
+ * @return string
+ */
+ public function getDefaultProtectedCustomvars()
+ {
+ return '*pw*,*pass*,community';
+ }
+}
diff --git a/modules/monitoring/application/forms/Config/Transport/ApiTransportForm.php b/modules/monitoring/application/forms/Config/Transport/ApiTransportForm.php
new file mode 100644
index 0000000..3d501e0
--- /dev/null
+++ b/modules/monitoring/application/forms/Config/Transport/ApiTransportForm.php
@@ -0,0 +1,75 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Config\Transport;
+
+use Icinga\Web\Form;
+
+class ApiTransportForm extends Form
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setName('form_config_command_transport_api');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData = array())
+ {
+ $this->addElements(array(
+ array(
+ 'text',
+ 'host',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Host'),
+ 'description' => $this->translate(
+ 'Hostname or address of the remote Icinga instance'
+ )
+ )
+ ),
+ array(
+ 'number',
+ 'port',
+ array(
+ 'required' => true,
+ 'preserveDefault' => true,
+ 'label' => $this->translate('Port'),
+ 'description' => $this->translate('SSH port to connect to on the remote Icinga instance'),
+ 'value' => 5665
+ )
+ ),
+ array(
+ 'text',
+ 'username',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('API Username'),
+ 'description' => $this->translate(
+ 'User to log in as on the remote Icinga instance. Please note that key-based SSH login must be'
+ . ' possible for this user'
+ )
+ )
+ ),
+ array(
+ 'password',
+ 'password',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('API Password'),
+ 'description' => $this->translate(
+ 'User to log in as on the remote Icinga instance. Please note that key-based SSH login must be'
+ . ' possible for this user'
+ ),
+ 'renderPassword' => true
+ )
+ )
+ ));
+
+ return $this;
+ }
+}
diff --git a/modules/monitoring/application/forms/Config/Transport/LocalTransportForm.php b/modules/monitoring/application/forms/Config/Transport/LocalTransportForm.php
new file mode 100644
index 0000000..15c7357
--- /dev/null
+++ b/modules/monitoring/application/forms/Config/Transport/LocalTransportForm.php
@@ -0,0 +1,37 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Config\Transport;
+
+use Icinga\Web\Form;
+
+class LocalTransportForm extends Form
+{
+ /**
+ * (non-PHPDoc)
+ * @see Form::init() For the method documentation.
+ */
+ public function init()
+ {
+ $this->setName('form_config_command_transport_local');
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData = array())
+ {
+ $this->addElement(
+ 'text',
+ 'path',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Command File'),
+ 'value' => '/var/run/icinga2/cmd/icinga2.cmd',
+ 'description' => $this->translate('Path to the local Icinga command file')
+ )
+ );
+ return $this;
+ }
+}
diff --git a/modules/monitoring/application/forms/Config/Transport/RemoteTransportForm.php b/modules/monitoring/application/forms/Config/Transport/RemoteTransportForm.php
new file mode 100644
index 0000000..7beeacf
--- /dev/null
+++ b/modules/monitoring/application/forms/Config/Transport/RemoteTransportForm.php
@@ -0,0 +1,185 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Config\Transport;
+
+use Icinga\Data\ResourceFactory;
+use Icinga\Exception\ConfigurationError;
+use Icinga\Web\Form;
+
+class RemoteTransportForm extends Form
+{
+ /**
+ * The available resources split by type
+ *
+ * @var array
+ */
+ protected $resources;
+
+ /**
+ * (non-PHPDoc)
+ * @see Form::init() For the method documentation.
+ */
+ public function init()
+ {
+ $this->setName('form_config_command_transport_remote');
+ }
+
+ /**
+ * Load all available ssh identity resources
+ *
+ * @return $this
+ *
+ * @throws \Icinga\Exception\ConfigurationError
+ */
+ public function loadResources()
+ {
+ $resourceConfig = ResourceFactory::getResourceConfigs();
+
+ $resources = array();
+ foreach ($resourceConfig as $name => $resource) {
+ if ($resource->type === 'ssh') {
+ $resources['ssh'][$name] = $name;
+ }
+ }
+
+ if (empty($resources)) {
+ throw new ConfigurationError($this->translate('Could not find any valid SSH resources'));
+ }
+
+ $this->resources = $resources;
+
+ return $this;
+ }
+
+ /**
+ * Check whether ssh identity resources exists or not
+ *
+ * @return boolean
+ */
+ public function hasResources()
+ {
+ $resourceConfig = ResourceFactory::getResourceConfigs();
+
+ foreach ($resourceConfig as $name => $resource) {
+ if ($resource->type === 'ssh') {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData = array())
+ {
+ $useResource = false;
+
+ if ($this->hasResources()) {
+ $useResource = isset($formData['use_resource'])
+ ? $formData['use_resource'] : $this->getValue('use_resource');
+
+ $this->addElement(
+ 'checkbox',
+ 'use_resource',
+ array(
+ 'label' => $this->translate('Use SSH Identity'),
+ 'description' => $this->translate('Make use of the ssh identity resource'),
+ 'autosubmit' => true,
+ 'ignore' => true
+ )
+ );
+ }
+
+ if ($useResource) {
+ $this->loadResources();
+
+ $decorators = static::$defaultElementDecorators;
+ array_pop($decorators); // Removes the HtmlTag decorator
+
+ $this->addElement(
+ 'select',
+ 'resource',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('SSH Identity'),
+ 'description' => $this->translate('The resource to use'),
+ 'decorators' => $decorators,
+ 'multiOptions' => $this->resources['ssh'],
+ 'value' => current($this->resources['ssh']),
+ 'autosubmit' => false
+ )
+ );
+ $resourceName = isset($formData['resource']) ? $formData['resource'] : $this->getValue('resource');
+ $this->addElement(
+ 'note',
+ 'resource_note',
+ array(
+ 'escape' => false,
+ 'decorators' => $decorators,
+ 'value' => sprintf(
+ '<a href="%1$s" data-base-target="_next" title="%2$s" aria-label="%2$s">%3$s</a>',
+ $this->getView()->url('config/editresource', array('resource' => $resourceName)),
+ sprintf($this->translate('Show the configuration of the %s resource'), $resourceName),
+ $this->translate('Show resource configuration')
+ )
+ )
+ );
+ }
+
+ $this->addElements(array(
+ array(
+ 'text',
+ 'host',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Host'),
+ 'description' => $this->translate(
+ 'Hostname or address of the remote Icinga instance'
+ )
+ )
+ ),
+ array(
+ 'number',
+ 'port',
+ array(
+ 'required' => true,
+ 'preserveDefault' => true,
+ 'label' => $this->translate('Port'),
+ 'description' => $this->translate('SSH port to connect to on the remote Icinga instance'),
+ 'value' => 22
+ )
+ )
+ ));
+
+ if (! $useResource) {
+ $this->addElement(
+ 'text',
+ 'user',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('User'),
+ 'description' => $this->translate(
+ 'User to log in as on the remote Icinga instance. Please note that key-based SSH login must be'
+ . ' possible for this user'
+ )
+ )
+ );
+ }
+
+ $this->addElement(
+ 'text',
+ 'path',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Command File'),
+ 'value' => '/var/run/icinga2/cmd/icinga2.cmd',
+ 'description' => $this->translate('Path to the Icinga command file on the remote Icinga instance')
+ )
+ );
+
+ return $this;
+ }
+}
diff --git a/modules/monitoring/application/forms/Config/TransportConfigForm.php b/modules/monitoring/application/forms/Config/TransportConfigForm.php
new file mode 100644
index 0000000..c68e63d
--- /dev/null
+++ b/modules/monitoring/application/forms/Config/TransportConfigForm.php
@@ -0,0 +1,392 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Config;
+
+use Icinga\Data\ConfigObject;
+use Icinga\Module\Monitoring\Command\Transport\CommandTransport;
+use Icinga\Module\Monitoring\Exception\CommandTransportException;
+use InvalidArgumentException;
+use Icinga\Application\Platform;
+use Icinga\Exception\IcingaException;
+use Icinga\Exception\NotFoundError;
+use Icinga\Forms\ConfigForm;
+use Icinga\Module\Monitoring\Command\Transport\ApiCommandTransport;
+use Icinga\Module\Monitoring\Command\Transport\LocalCommandFile;
+use Icinga\Module\Monitoring\Command\Transport\RemoteCommandFile;
+use Icinga\Module\Monitoring\Forms\Config\Transport\ApiTransportForm;
+use Icinga\Module\Monitoring\Forms\Config\Transport\LocalTransportForm;
+use Icinga\Module\Monitoring\Forms\Config\Transport\RemoteTransportForm;
+
+/**
+ * Form for managing command transports
+ */
+class TransportConfigForm extends ConfigForm
+{
+ /**
+ * The transport to load when displaying the form for the first time
+ *
+ * @var string
+ */
+ protected $transportToLoad;
+
+ /**
+ * The names of all available Icinga instances
+ *
+ * @var array
+ */
+ protected $instanceNames;
+
+ /**
+ * @var bool
+ */
+ protected $validatePartial = true;
+
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->setName('form_config_command_transports');
+ $this->setSubmitLabel($this->translate('Save Changes'));
+ }
+
+ /**
+ * Set the names of all available Icinga instances
+ *
+ * @param array $names
+ *
+ * @return $this
+ */
+ public function setInstanceNames(array $names)
+ {
+ $this->instanceNames = $names;
+ return $this;
+ }
+
+ /**
+ * Return the names of all available Icinga instances
+ *
+ * @return array
+ */
+ public function getInstanceNames()
+ {
+ return $this->instanceNames ?: array();
+ }
+
+ /**
+ * Return a form object for the given transport type
+ *
+ * @param string $type The transport type for which to return a form
+ *
+ * @return \Icinga\Web\Form
+ *
+ * @throws InvalidArgumentException In case the given transport type is invalid
+ */
+ public function getTransportForm($type)
+ {
+ switch (strtolower($type)) {
+ case LocalCommandFile::TRANSPORT:
+ return new LocalTransportForm();
+ case RemoteCommandFile::TRANSPORT:
+ return new RemoteTransportForm();
+ case ApiCommandTransport::TRANSPORT:
+ return new ApiTransportForm();
+ default:
+ throw new InvalidArgumentException(
+ sprintf($this->translate('Invalid command transport type "%s" given'), $type)
+ );
+ }
+ }
+
+ /**
+ * Populate the form with the given transport's config
+ *
+ * @param string $name
+ *
+ * @return $this
+ *
+ * @throws NotFoundError In case no transport with the given name is found
+ */
+ public function load($name)
+ {
+ if (! $this->config->hasSection($name)) {
+ throw new NotFoundError('No command transport called "%s" found', $name);
+ }
+
+ $this->transportToLoad = $name;
+ return $this;
+ }
+
+ /**
+ * Add a new command transport
+ *
+ * The transport to add is identified by the array-key `name'.
+ *
+ * @param array $data
+ *
+ * @return $this
+ *
+ * @throws InvalidArgumentException In case $data does not contain a transport name
+ * @throws IcingaException In case a transport with the same name already exists
+ */
+ public function add(array $data)
+ {
+ if (! isset($data['name'])) {
+ throw new InvalidArgumentException('Key \'name\' missing');
+ }
+
+ $transportName = $data['name'];
+ if ($this->config->hasSection($transportName)) {
+ throw new IcingaException(
+ $this->translate('A command transport with the name "%s" does already exist'),
+ $transportName
+ );
+ }
+
+ unset($data['name']);
+ $this->config->setSection($transportName, $data);
+ return $this;
+ }
+
+ /**
+ * Edit an existing command transport
+ *
+ * @param string $name
+ * @param array $data
+ *
+ * @return $this
+ *
+ * @throws NotFoundError In case no transport with the given name is found
+ */
+ public function edit($name, array $data)
+ {
+ if (! $this->config->hasSection($name)) {
+ throw new NotFoundError('No command transport called "%s" found', $name);
+ }
+
+ $transportConfig = $this->config->getSection($name);
+ if (isset($data['name'])) {
+ if ($data['name'] !== $name) {
+ $this->config->removeSection($name);
+ $name = $data['name'];
+ }
+
+ unset($data['name']);
+ }
+
+ $transportConfig->merge($data);
+ $this->config->setSection($name, $transportConfig);
+ return $this;
+ }
+
+ /**
+ * Remove a command transport
+ *
+ * @param string $name
+ *
+ * @return $this
+ */
+ public function delete($name)
+ {
+ $this->config->removeSection($name);
+ return $this;
+ }
+
+ /**
+ * Create and add elements to this form
+ *
+ * @param array $formData
+ */
+ public function createElements(array $formData)
+ {
+ $instanceNames = $this->getInstanceNames();
+ if (count($instanceNames) > 1) {
+ $options = array('none' => $this->translate('None', 'command transport instance association'));
+ $this->addElement(
+ 'select',
+ 'instance',
+ array(
+ 'label' => $this->translate('Instance Link'),
+ 'description' => $this->translate(
+ 'The name of the Icinga instance this transport should exclusively transfer commands to.'
+ ),
+ 'multiOptions' => array_merge($options, array_combine($instanceNames, $instanceNames))
+ )
+ );
+ }
+
+ $this->addElement(
+ 'text',
+ 'name',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Transport Name'),
+ 'description' => $this->translate(
+ 'The name of this command transport that is used to differentiate it from others'
+ )
+ )
+ );
+
+ $transportTypes = array(
+ ApiCommandTransport::TRANSPORT => $this->translate('Icinga 2 API'),
+ LocalCommandFile::TRANSPORT => $this->translate('Local Command File'),
+ RemoteCommandFile::TRANSPORT => $this->translate('Remote Command File')
+ );
+ if (! Platform::extensionLoaded('curl')) {
+ unset($transportTypes[ApiCommandTransport::TRANSPORT]);
+ }
+
+ $transportType = isset($formData['transport']) ? $formData['transport'] : null;
+ if ($transportType === null) {
+ $transportType = key($transportTypes);
+ }
+
+ $this->addElements(array(
+ array(
+ 'select',
+ 'transport',
+ array(
+ 'required' => true,
+ 'autosubmit' => true,
+ 'label' => $this->translate('Transport Type'),
+ 'multiOptions' => $transportTypes
+ )
+ )
+ ));
+
+ $this->addSubForm($this->getTransportForm($transportType)->create($formData), 'transport_form');
+ }
+
+ /**
+ * Add a submit button to this form and one to manually validate the configuration
+ *
+ * Calls parent::addSubmitButton() to add the submit button.
+ *
+ * @return $this
+ */
+ public function addSubmitButton()
+ {
+ parent::addSubmitButton();
+
+ if ($this->getSubForm('transport_form') instanceof ApiTransportForm) {
+ $btnSubmit = $this->getElement('btn_submit');
+
+ if ($btnSubmit !== null) {
+ // In the setup wizard $this is being used as a subform which doesn't have a submit button.
+ $this->addElement(
+ 'submit',
+ 'transport_validation',
+ array(
+ 'ignore' => true,
+ 'label' => $this->translate('Validate Configuration'),
+ 'data-progress-label' => $this->translate('Validation In Progress'),
+ 'decorators' => array('ViewHelper')
+ )
+ );
+
+ $this->setAttrib('data-progress-element', 'transport-progress');
+ $this->addElement(
+ 'note',
+ 'transport-progress',
+ array(
+ 'decorators' => array(
+ 'ViewHelper',
+ array('Spinner', array('id' => 'transport-progress'))
+ )
+ )
+ );
+
+ $elements = array('transport_validation', 'transport-progress');
+
+ $btnSubmit->setDecorators(array('ViewHelper'));
+ array_unshift($elements, 'btn_submit');
+
+ $this->addDisplayGroup(
+ $elements,
+ 'submit_validation',
+ array(
+ 'decorators' => array(
+ 'FormElements',
+ array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
+ )
+ )
+ );
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Populate the configuration of the transport to load
+ */
+ public function onRequest()
+ {
+ if ($this->transportToLoad) {
+ $data = $this->config->getSection($this->transportToLoad)->toArray();
+ $data['name'] = $this->transportToLoad;
+ $this->populate($data);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isValidPartial(array $formData)
+ {
+ $isValidPartial = parent::isValidPartial($formData);
+
+ $transportValidation = $this->getElement('transport_validation');
+ if ($transportValidation !== null && $transportValidation->isChecked() && $this->isValid($formData)) {
+ $this->info($this->translate('The configuration has been successfully validated.'));
+ }
+
+ return $isValidPartial;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isValid($formData)
+ {
+ if (! parent::isValid($formData)) {
+ return false;
+ }
+
+ if ($this->getSubForm('transport_form') instanceof ApiTransportForm) {
+ if (! isset($formData['transport_validation'])
+ && isset($formData['force_creation']) && $formData['force_creation']
+ ) {
+ // ignore any validation result
+ return true;
+ }
+
+ try {
+ CommandTransport::createTransport(new ConfigObject($this->getValues()))->probe();
+ } catch (CommandTransportException $e) {
+ $this->error(sprintf(
+ $this->translate('Failed to successfully validate the configuration: %s'),
+ $e->getMessage()
+ ));
+
+ $this->addElement(
+ 'checkbox',
+ 'force_creation',
+ array(
+ 'order' => 0,
+ 'ignore' => true,
+ 'label' => $this->translate('Force Changes'),
+ 'description' => $this->translate(
+ 'Check this box to enforce changes without connectivity validation'
+ )
+ )
+ );
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Config/TransportReorderForm.php b/modules/monitoring/application/forms/Config/TransportReorderForm.php
new file mode 100644
index 0000000..f3efe4c
--- /dev/null
+++ b/modules/monitoring/application/forms/Config/TransportReorderForm.php
@@ -0,0 +1,87 @@
+<?php
+/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Config;
+
+use Icinga\Application\Config;
+use Icinga\Web\Form;
+use Icinga\Web\Notification;
+
+/**
+ * Form for reordering command transports
+ */
+class TransportReorderForm extends Form
+{
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->setName('form_reorder_command_transports');
+ $this->setViewScript('form/reorder-command-transports.phtml');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData)
+ {
+ // This adds just a dummy element to be able to utilize Form::getValue as part of onSuccess()
+ $this->addElement(
+ 'hidden',
+ 'transport_newpos',
+ array(
+ 'required' => true,
+ 'validators' => array(
+ array(
+ 'validator' => 'regex',
+ 'options' => array(
+ 'pattern' => '/\A\d+\|/'
+ )
+ )
+ )
+ )
+ );
+ }
+
+ /**
+ * Update the command transport order and save the configuration
+ */
+ public function onSuccess()
+ {
+ list($position, $transportName) = explode('|', $this->getValue('transport_newpos'), 2);
+ $config = $this->getConfig();
+ if (! $config->hasSection($transportName)) {
+ Notification::error(sprintf($this->translate('Command transport "%s" not found'), $transportName));
+ return false;
+ }
+
+ if ($config->count() > 1) {
+ $sections = $config->keys();
+ array_splice($sections, array_search($transportName, $sections, true), 1);
+ array_splice($sections, $position, 0, array($transportName));
+
+ $sectionsInNewOrder = array();
+ foreach ($sections as $section) {
+ $sectionsInNewOrder[$section] = $config->getSection($section);
+ $config->removeSection($section);
+ }
+ foreach ($sectionsInNewOrder as $name => $options) {
+ $config->setSection($name, $options);
+ }
+
+ $config->saveIni();
+ Notification::success($this->translate('Command transport order updated'));
+ }
+ }
+
+ /**
+ * Get the command transports config
+ *
+ * @return Config
+ */
+ public function getConfig()
+ {
+ return Config::module('monitoring', 'commandtransports');
+ }
+}