summaryrefslogtreecommitdiffstats
path: root/modules/monitoring/application/forms
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:46:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:46:43 +0000
commit3e02d5aff85babc3ffbfcf52313f2108e313aa23 (patch)
treeb01f3923360c20a6a504aff42d45670c58af3ec5 /modules/monitoring/application/forms
parentInitial commit. (diff)
downloadicingaweb2-upstream.tar.xz
icingaweb2-upstream.zip
Adding upstream version 2.12.1.upstream/2.12.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'modules/monitoring/application/forms')
-rw-r--r--modules/monitoring/application/forms/Command/CommandForm.php92
-rw-r--r--modules/monitoring/application/forms/Command/Instance/DisableNotificationsExpireCommandForm.php64
-rw-r--r--modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php279
-rw-r--r--modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php172
-rw-r--r--modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php148
-rw-r--r--modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php87
-rw-r--r--modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php109
-rw-r--r--modules/monitoring/application/forms/Command/Object/DeleteCommentsCommandForm.php89
-rw-r--r--modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php129
-rw-r--r--modules/monitoring/application/forms/Command/Object/DeleteDowntimesCommandForm.php89
-rw-r--r--modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php47
-rw-r--r--modules/monitoring/application/forms/Command/Object/ProcessCheckResultCommandForm.php140
-rw-r--r--modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php122
-rw-r--r--modules/monitoring/application/forms/Command/Object/ScheduleHostCheckCommandForm.php67
-rw-r--r--modules/monitoring/application/forms/Command/Object/ScheduleHostDowntimeCommandForm.php178
-rw-r--r--modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php112
-rw-r--r--modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php263
-rw-r--r--modules/monitoring/application/forms/Command/Object/SendCustomNotificationCommandForm.php110
-rw-r--r--modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php187
-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
-rw-r--r--modules/monitoring/application/forms/EventOverviewForm.php157
-rw-r--r--modules/monitoring/application/forms/Navigation/ActionForm.php79
-rw-r--r--modules/monitoring/application/forms/Navigation/HostActionForm.php8
-rw-r--r--modules/monitoring/application/forms/Navigation/ServiceActionForm.php8
-rw-r--r--modules/monitoring/application/forms/Setup/BackendPage.php51
-rw-r--r--modules/monitoring/application/forms/Setup/IdoResourcePage.php188
-rw-r--r--modules/monitoring/application/forms/Setup/SecurityPage.php27
-rw-r--r--modules/monitoring/application/forms/Setup/TransportPage.php55
-rw-r--r--modules/monitoring/application/forms/Setup/WelcomePage.php63
-rw-r--r--modules/monitoring/application/forms/StatehistoryForm.php141
36 files changed, 4479 insertions, 0 deletions
diff --git a/modules/monitoring/application/forms/Command/CommandForm.php b/modules/monitoring/application/forms/Command/CommandForm.php
new file mode 100644
index 0000000..34391cf
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/CommandForm.php
@@ -0,0 +1,92 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command;
+
+use Icinga\Exception\ConfigurationError;
+use Icinga\Web\Form;
+use Icinga\Web\Request;
+use Icinga\Module\Monitoring\Backend\MonitoringBackend;
+use Icinga\Module\Monitoring\Command\Transport\CommandTransport;
+use Icinga\Module\Monitoring\Command\Transport\CommandTransportInterface;
+
+/**
+ * Base class for command forms
+ */
+abstract class CommandForm extends Form
+{
+ /**
+ * Monitoring backend
+ *
+ * @var MonitoringBackend
+ */
+ protected $backend;
+
+ /**
+ * Set the monitoring backend
+ *
+ * @param MonitoringBackend $backend
+ *
+ * @return $this
+ */
+ public function setBackend(MonitoringBackend $backend)
+ {
+ $this->backend = $backend;
+ return $this;
+ }
+
+ /**
+ * Get the monitoring backend
+ *
+ * @return MonitoringBackend
+ */
+ public function getBackend()
+ {
+ return $this->backend;
+ }
+
+ /**
+ * Get the transport used to send commands
+ *
+ * @param Request $request
+ *
+ * @return CommandTransportInterface
+ *
+ * @throws ConfigurationError
+ */
+ public function getTransport(Request $request)
+ {
+ if (($transportName = $request->getParam('transport')) !== null) {
+ $config = CommandTransport::getConfig();
+ if ($config->hasSection($transportName)) {
+ $transport = CommandTransport::createTransport($config->getSection($transportName));
+ } else {
+ throw new ConfigurationError(sprintf(
+ mt('monitoring', 'Command transport "%s" not found.'),
+ $transportName
+ ));
+ }
+ } else {
+ $transport = new CommandTransport();
+ }
+
+ return $transport;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRedirectUrl()
+ {
+ $redirectUrl = parent::getRedirectUrl();
+ // TODO(el): Forms should provide event handling. This is quite hackish
+ $formData = $this->getRequestData();
+ if ($this->wasSent($formData)
+ && (! $this->getSubmitLabel() || $this->isSubmitted())
+ && $this->isValid($formData)
+ ) {
+ $this->getResponse()->setAutoRefreshInterval(1);
+ }
+ return $redirectUrl;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Instance/DisableNotificationsExpireCommandForm.php b/modules/monitoring/application/forms/Command/Instance/DisableNotificationsExpireCommandForm.php
new file mode 100644
index 0000000..ee49962
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Instance/DisableNotificationsExpireCommandForm.php
@@ -0,0 +1,64 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Instance;
+
+use DateTime;
+use DateInterval;
+use Icinga\Module\Monitoring\Command\Instance\DisableNotificationsExpireCommand;
+use Icinga\Module\Monitoring\Forms\Command\CommandForm;
+use Icinga\Web\Notification;
+
+/**
+ * Form for disabling host and service notifications w/ an optional expire date and time on an Icinga instance
+ */
+class DisableNotificationsExpireCommandForm extends CommandForm
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Zend_Form::init() For the method documentation.
+ */
+ public function init()
+ {
+ $this->setRequiredCue(null);
+ $this->setSubmitLabel($this->translate('Disable Notifications'));
+ $this->addDescription($this->translate(
+ 'This command is used to disable host and service notifications for a specific time.'
+ ));
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData = array())
+ {
+ $expireTime = new DateTime();
+ $expireTime->add(new DateInterval('PT1H'));
+ $this->addElement(
+ 'dateTimePicker',
+ 'expire_time',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Expire Time'),
+ 'description' => $this->translate('Set the expire time.'),
+ 'value' => $expireTime
+ )
+ );
+ return $this;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ $disableNotifications = new DisableNotificationsExpireCommand();
+ $disableNotifications
+ ->setExpireTime($this->getElement('expire_time')->getValue()->getTimestamp());
+ $this->getTransport($this->request)->send($disableNotifications);
+ Notification::success($this->translate('Disabling host and service notifications..'));
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php
new file mode 100644
index 0000000..8b01399
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Instance/ToggleInstanceFeaturesCommandForm.php
@@ -0,0 +1,279 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Instance;
+
+use Icinga\Module\Monitoring\Command\Instance\ToggleInstanceFeatureCommand;
+use Icinga\Module\Monitoring\Forms\Command\CommandForm;
+use Icinga\Web\Notification;
+
+/**
+ * Form for enabling or disabling features of Icinga instances
+ */
+class ToggleInstanceFeaturesCommandForm extends CommandForm
+{
+ /**
+ * Instance status
+ *
+ * @var object
+ */
+ protected $status;
+
+ /**
+ * (non-PHPDoc)
+ * @see \Zend_Form::init() For the method documentation.
+ */
+ public function init()
+ {
+ $this->setUseFormAutosubmit();
+ $this->setAttrib('class', self::DEFAULT_CLASSES . ' instance-features');
+ }
+
+ /**
+ * Set the instance status
+ *
+ * @param object $status
+ *
+ * @return $this
+ */
+ public function setStatus($status)
+ {
+ $this->status = (object) $status;
+ return $this;
+ }
+
+ /**
+ * Get the instance status
+ *
+ * @return object
+ */
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData = array())
+ {
+ $notificationDescription = null;
+ $isIcinga2 = $this->getBackend()->isIcinga2($this->status->program_version);
+
+ if (! $isIcinga2) {
+ if ((bool) $this->status->notifications_enabled) {
+ if ($this->hasPermission('monitoring/command/feature/instance')) {
+ $notificationDescription = sprintf(
+ '<a aria-label="%1$s" class="action-link" title="%1$s"'
+ . ' href="%2$s" data-base-target="_next">%3$s</a>',
+ $this->translate('Disable notifications for a specific time on a program-wide basis'),
+ $this->getView()->href('monitoring/health/disable-notifications'),
+ $this->translate('Disable temporarily')
+ );
+ } else {
+ $notificationDescription = null;
+ }
+ } elseif ($this->status->disable_notif_expire_time) {
+ $notificationDescription = sprintf(
+ $this->translate('Notifications will be re-enabled in <strong>%s</strong>'),
+ $this->getView()->timeUntil($this->status->disable_notif_expire_time)
+ );
+ }
+ }
+
+ $toggleDisabled = $this->hasPermission('monitoring/command/feature/instance') ? null : '';
+
+ $this->addElement(
+ 'checkbox',
+ ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS,
+ array(
+ 'label' => $this->translate('Active Host Checks'),
+ 'autosubmit' => true,
+ 'disabled' => $toggleDisabled
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS,
+ array(
+ 'label' => $this->translate('Active Service Checks'),
+ 'autosubmit' => true,
+ 'disabled' => $toggleDisabled
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS,
+ array(
+ 'label' => $this->translate('Event Handlers'),
+ 'autosubmit' => true,
+ 'disabled' => $toggleDisabled
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION,
+ array(
+ 'label' => $this->translate('Flap Detection'),
+ 'autosubmit' => true,
+ 'disabled' => $toggleDisabled
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ ToggleInstanceFeatureCommand::FEATURE_NOTIFICATIONS,
+ array(
+ 'label' => $this->translate('Notifications'),
+ 'autosubmit' => true,
+ 'description' => $notificationDescription,
+ 'decorators' => array(
+ array('Label', array('tag'=>'span', 'separator' => '', 'class' => 'control-label')),
+ array(
+ 'Description',
+ array('tag' => 'span', 'class' => 'description', 'escape' => false)
+ ),
+ array(array('labelWrap' => 'HtmlTag'), array('tag' => 'div', 'class' => 'control-label-group')),
+ array('ViewHelper', array('separator' => '')),
+ array('Errors', array('separator' => '')),
+ array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
+ ),
+ 'disabled' => $toggleDisabled
+ )
+ );
+
+ if (! $isIcinga2) {
+ $this->addElement(
+ 'checkbox',
+ ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING,
+ array(
+ 'label' => $this->translate('Obsessing Over Hosts'),
+ 'autosubmit' => true,
+ 'disabled' => $toggleDisabled
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ ToggleInstanceFeatureCommand::FEATURE_SERVICE_OBSESSING,
+ array(
+ 'label' => $this->translate('Obsessing Over Services'),
+ 'autosubmit' => true,
+ 'disabled' => $toggleDisabled
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ ToggleInstanceFeatureCommand::FEATURE_PASSIVE_HOST_CHECKS,
+ array(
+ 'label' => $this->translate('Passive Host Checks'),
+ 'autosubmit' => true,
+ 'disabled' => $toggleDisabled
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ ToggleInstanceFeatureCommand::FEATURE_PASSIVE_SERVICE_CHECKS,
+ array(
+ 'label' => $this->translate('Passive Service Checks'),
+ 'autosubmit' => true,
+ 'disabled' => $toggleDisabled
+ )
+ );
+ }
+
+ $this->addElement(
+ 'checkbox',
+ ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA,
+ array(
+ 'label' => $this->translate('Performance Data'),
+ 'autosubmit' => true,
+ 'disabled' => $toggleDisabled
+ )
+ );
+ }
+
+ /**
+ * Load feature status
+ *
+ * @param object $instanceStatus
+ *
+ * @return $this
+ */
+ public function load($instanceStatus)
+ {
+ $this->create();
+ foreach ($this->getValues() as $feature => $enabled) {
+ $this->getElement($feature)->setChecked($instanceStatus->{$feature});
+ }
+
+ return $this;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ $this->assertPermission('monitoring/command/feature/instance');
+
+ $notifications = array(
+ ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS => array(
+ $this->translate('Enabling active host checks..'),
+ $this->translate('Disabling active host checks..')
+ ),
+ ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS => array(
+ $this->translate('Enabling active service checks..'),
+ $this->translate('Disabling active service checks..')
+ ),
+ ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS => array(
+ $this->translate('Enabling event handlers..'),
+ $this->translate('Disabling event handlers..')
+ ),
+ ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION => array(
+ $this->translate('Enabling flap detection..'),
+ $this->translate('Disabling flap detection..')
+ ),
+ ToggleInstanceFeatureCommand::FEATURE_NOTIFICATIONS => array(
+ $this->translate('Enabling notifications..'),
+ $this->translate('Disabling notifications..')
+ ),
+ ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING => array(
+ $this->translate('Enabling obsessing over hosts..'),
+ $this->translate('Disabling obsessing over hosts..')
+ ),
+ ToggleInstanceFeatureCommand::FEATURE_SERVICE_OBSESSING => array(
+ $this->translate('Enabling obsessing over services..'),
+ $this->translate('Disabling obsessing over services..')
+ ),
+ ToggleInstanceFeatureCommand::FEATURE_PASSIVE_HOST_CHECKS => array(
+ $this->translate('Enabling passive host checks..'),
+ $this->translate('Disabling passive host checks..')
+ ),
+ ToggleInstanceFeatureCommand::FEATURE_PASSIVE_SERVICE_CHECKS => array(
+ $this->translate('Enabling passive service checks..'),
+ $this->translate('Disabling passive service checks..')
+ ),
+ ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA => array(
+ $this->translate('Enabling performance data..'),
+ $this->translate('Disabling performance data..')
+ )
+ );
+
+ foreach ($this->getValues() as $feature => $enabled) {
+ if ((bool) $this->status->{$feature} !== (bool) $enabled) {
+ $toggleFeature = new ToggleInstanceFeatureCommand();
+ $toggleFeature
+ ->setFeature($feature)
+ ->setEnabled($enabled);
+ $this->getTransport($this->request)->send($toggleFeature);
+
+ Notification::success(
+ $notifications[$feature][$enabled ? 0 : 1]
+ );
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php b/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php
new file mode 100644
index 0000000..c7caf5d
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php
@@ -0,0 +1,172 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use DateTime;
+use DateInterval;
+use Icinga\Application\Config;
+use Icinga\Module\Monitoring\Command\Object\AcknowledgeProblemCommand;
+use Icinga\Web\Notification;
+
+/**
+ * Form for acknowledging host or service problems
+ */
+class AcknowledgeProblemCommandForm extends ObjectsCommandForm
+{
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->addDescription($this->translate(
+ 'This command is used to acknowledge host or service problems. When a problem is acknowledged,'
+ . ' future notifications about problems are temporarily disabled until the host or service'
+ . ' recovers.'
+ ));
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
+ */
+ public function getSubmitLabel()
+ {
+ return $this->translatePlural('Acknowledge problem', 'Acknowledge problems', count($this->objects));
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData = array())
+ {
+ $config = Config::module('monitoring');
+
+ $acknowledgeExpire = (bool) $config->get('settings', 'acknowledge_expire', false);
+
+ $this->addElements(array(
+ array(
+ 'textarea',
+ 'comment',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Comment'),
+ 'description' => $this->translate(
+ 'If you work with other administrators, you may find it useful to share information about'
+ . ' the host or service that is having problems. Make sure you enter a brief description of'
+ . ' what you are doing.'
+ ),
+ 'attribs' => array('class' => 'autofocus')
+ )
+ ),
+ array(
+ 'checkbox',
+ 'persistent',
+ array(
+ 'label' => $this->translate('Persistent Comment'),
+ 'value' => (bool) $config->get('settings', 'acknowledge_persistent', false),
+ 'description' => $this->translate(
+ 'If you would like the comment to remain even when the acknowledgement is removed, check this'
+ . ' option.'
+ )
+ )
+ ),
+ array(
+ 'checkbox',
+ 'expire',
+ array(
+ 'label' => $this->translate('Use Expire Time'),
+ 'value' => $acknowledgeExpire,
+ 'description' => $this->translate(
+ 'If the acknowledgement should expire, check this option.'
+ ),
+ 'autosubmit' => true
+ )
+ )
+ ));
+ $expire = isset($formData['expire']) ? $formData['expire'] : $acknowledgeExpire;
+ if ($expire) {
+ $expireTime = new DateTime();
+ $expireTime->add(new DateInterval($config->get('settings', 'acknowledge_expire_time', 'PT1H')));
+ $this->addElement(
+ 'dateTimePicker',
+ 'expire_time',
+ array(
+ 'label' => $this->translate('Expire Time'),
+ 'value' => $expireTime,
+ 'description' => $this->translate(
+ 'Enter the expire date and time for this acknowledgement here. Icinga will delete the'
+ . ' acknowledgement after this time expired.'
+ )
+ )
+ );
+ $this->addDisplayGroup(
+ array('expire', 'expire_time'),
+ 'expire-expire_time',
+ array(
+ 'decorators' => array(
+ 'FormElements',
+ array('HtmlTag', array('tag' => 'div'))
+ )
+ )
+ );
+ }
+ $this->addElements(array(
+ array(
+ 'checkbox',
+ 'sticky',
+ array(
+ 'label' => $this->translate('Sticky Acknowledgement'),
+ 'value' => (bool) $config->get('settings', 'acknowledge_sticky', false),
+ 'description' => $this->translate(
+ 'If you want the acknowledgement to remain until the host or service recovers even if the host'
+ . ' or service changes state, check this option.'
+ )
+ )
+ ),
+ array(
+ 'checkbox',
+ 'notify',
+ array(
+ 'label' => $this->translate('Send Notification'),
+ 'value' => (bool) $config->get('settings', 'acknowledge_notify', true),
+ 'description' => $this->translate(
+ 'If you do not want an acknowledgement notification to be sent out to the appropriate contacts,'
+ . ' uncheck this option.'
+ )
+ )
+ )
+ ));
+ return $this;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ foreach ($this->objects as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+ $ack = new AcknowledgeProblemCommand();
+ $ack
+ ->setObject($object)
+ ->setComment($this->getElement('comment')->getValue())
+ ->setAuthor($this->request->getUser()->getUsername())
+ ->setPersistent($this->getElement('persistent')->isChecked())
+ ->setSticky($this->getElement('sticky')->isChecked())
+ ->setNotify($this->getElement('notify')->isChecked());
+ if ($this->getElement('expire')->isChecked()) {
+ $ack->setExpireTime($this->getElement('expire_time')->getValue()->getTimestamp());
+ }
+ $this->getTransport($this->request)->send($ack);
+ }
+ Notification::success($this->translatePlural(
+ 'Acknowledging problem..',
+ 'Acknowledging problems..',
+ count($this->objects)
+ ));
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php b/modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php
new file mode 100644
index 0000000..72133a0
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/AddCommentCommandForm.php
@@ -0,0 +1,148 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use DateInterval;
+use DateTime;
+use Icinga\Application\Config;
+use Icinga\Module\Monitoring\Command\Object\AddCommentCommand;
+use Icinga\Web\Notification;
+
+/**
+ * Form for adding host or service comments
+ */
+class AddCommentCommandForm extends ObjectsCommandForm
+{
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->addDescription($this->translate('This command is used to add host or service comments.'));
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
+ */
+ public function getSubmitLabel()
+ {
+ return $this->translatePlural('Add comment', 'Add comments', count($this->objects));
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData = array())
+ {
+ $this->addElement(
+ 'textarea',
+ 'comment',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Comment'),
+ 'description' => $this->translate(
+ 'If you work with other administrators, you may find it useful to share information about'
+ . ' the host or service that is having problems. Make sure you enter a brief description of'
+ . ' what you are doing.'
+ ),
+ 'attribs' => array('class' => 'autofocus')
+ )
+ );
+ if (! $this->getBackend()->isIcinga2()) {
+ $this->addElement(
+ 'checkbox',
+ 'persistent',
+ array(
+ 'label' => $this->translate('Persistent'),
+ 'value' => (bool) Config::module('monitoring')->get('settings', 'comment_persistent', true),
+ 'description' => $this->translate(
+ 'If you uncheck this option, the comment will automatically be deleted the next time Icinga is'
+ . ' restarted.'
+ )
+ )
+ );
+ }
+
+ if (version_compare($this->getBackend()->getProgramVersion(), '2.13.0', '>=')) {
+ $config = Config::module('monitoring');
+ $commentExpire = (bool) $config->get('settings', 'comment_expire', false);
+
+ $this->addElement(
+ 'checkbox',
+ 'expire',
+ [
+ 'label' => $this->translate('Use Expire Time'),
+ 'value' => $commentExpire,
+ 'description' => $this->translate('If the comment should expire, check this option.'),
+ 'autosubmit' => true
+ ]
+ );
+
+ if (isset($formData['expire']) ? $formData['expire'] : $commentExpire) {
+ $expireTime = new DateTime();
+ $expireTime->add(new DateInterval($config->get('settings', 'comment_expire_time', 'PT1H')));
+
+ $this->addElement(
+ 'dateTimePicker',
+ 'expire_time',
+ [
+ 'label' => $this->translate('Expire Time'),
+ 'value' => $expireTime,
+ 'description' => $this->translate(
+ 'Enter the expire date and time for this comment here. Icinga will delete the'
+ . ' comment after this time expired.'
+ )
+ ]
+ );
+
+ $this->addDisplayGroup(
+ ['expire', 'expire_time'],
+ 'expire-expire_time',
+ [
+ 'decorators' => [
+ 'FormElements',
+ ['HtmlTag', ['tag' => 'div']]
+ ]
+ ]
+ );
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ foreach ($this->objects as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+ $comment = new AddCommentCommand();
+ $comment->setObject($object);
+ $comment->setComment($this->getElement('comment')->getValue());
+ $comment->setAuthor($this->request->getUser()->getUsername());
+ if (($persistent = $this->getElement('persistent')) !== null) {
+ $comment->setPersistent($persistent->isChecked());
+ }
+
+ $expire = $this->getElement('expire');
+
+ if ($expire !== null && $expire->isChecked()) {
+ $comment->setExpireTime($this->getElement('expire_time')->getValue()->getTimestamp());
+ }
+
+ $this->getTransport($this->request)->send($comment);
+ }
+ Notification::success($this->translatePlural(
+ 'Adding comment..',
+ 'Adding comments..',
+ count($this->objects)
+ ));
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php b/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php
new file mode 100644
index 0000000..a586d2f
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/CheckNowCommandForm.php
@@ -0,0 +1,87 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\ScheduleHostCheckCommand;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceCheckCommand;
+use Icinga\Web\Notification;
+
+/**
+ * Form for immediately checking hosts or services
+ */
+class CheckNowCommandForm extends ObjectsCommandForm
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Zend_Form::init() For the method documentation.
+ */
+ public function init()
+ {
+ $this->setAttrib('class', 'inline');
+ $this->setSubmitLabel($this->translate('Check now'));
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::addSubmitButton() For the method documentation.
+ */
+ public function addSubmitButton()
+ {
+ $this->addElements(array(
+ array(
+ 'button',
+ 'btn_submit',
+ array(
+ 'class' => 'link-button spinner',
+ 'decorators' => array(
+ 'ViewHelper',
+ array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
+ ),
+ 'escape' => false,
+ 'ignore' => true,
+ 'label' => $this->getView()->icon('arrows-cw') . $this->translate('Check now'),
+ 'type' => 'submit',
+ 'title' => $this->translate('Schedule the next active check to run immediately'),
+ 'value' => $this->translate('Check now')
+ )
+ )
+ ));
+
+ return $this;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ foreach ($this->objects as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+ if (! $object->active_checks_enabled
+ && ! $this->Auth()->hasPermission('monitoring/command/schedule-check')
+ ) {
+ continue;
+ }
+
+ if ($object->getType() === $object::TYPE_HOST) {
+ $check = new ScheduleHostCheckCommand();
+ } else {
+ $check = new ScheduleServiceCheckCommand();
+ }
+ $check
+ ->setObject($object)
+ ->setForced()
+ ->setCheckTime(time());
+ $this->getTransport($this->request)->send($check);
+ }
+ Notification::success(mtp(
+ 'monitoring',
+ 'Scheduling check..',
+ 'Scheduling checks..',
+ count($this->objects)
+ ));
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php b/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php
new file mode 100644
index 0000000..cd15b19
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/DeleteCommentCommandForm.php
@@ -0,0 +1,109 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
+use Icinga\Module\Monitoring\Forms\Command\CommandForm;
+use Icinga\Web\Notification;
+
+/**
+ * Form for deleting host or service comments
+ */
+class DeleteCommentCommandForm extends CommandForm
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setAttrib('class', 'inline');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addSubmitButton()
+ {
+ $this->addElement(
+ 'button',
+ 'btn_submit',
+ array(
+ 'class' => 'link-button spinner',
+ 'decorators' => array(
+ 'ViewHelper',
+ array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
+ ),
+ 'escape' => false,
+ 'ignore' => true,
+ 'label' => $this->getView()->icon('cancel'),
+ 'title' => $this->translate('Delete this comment'),
+ 'type' => 'submit'
+ )
+ );
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData = array())
+ {
+ $this->addElements(
+ array(
+ array(
+ 'hidden',
+ 'comment_id',
+ array(
+ 'required' => true,
+ 'validators' => array('NotEmpty'),
+ 'decorators' => array('ViewHelper')
+ )
+ ),
+ array(
+ 'hidden',
+ 'comment_is_service',
+ array(
+ 'filters' => array('Boolean'),
+ 'decorators' => array('ViewHelper')
+ )
+ ),
+ array(
+ 'hidden',
+ 'comment_name',
+ array(
+ 'decorators' => array('ViewHelper')
+ )
+ ),
+ array(
+ 'hidden',
+ 'redirect',
+ array(
+ 'decorators' => array('ViewHelper')
+ )
+ )
+ )
+ );
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onSuccess()
+ {
+ $cmd = new DeleteCommentCommand();
+ $cmd
+ ->setAuthor($this->Auth()->getUser()->getUsername())
+ ->setCommentId($this->getElement('comment_id')->getValue())
+ ->setCommentName($this->getElement('comment_name')->getValue())
+ ->setIsService($this->getElement('comment_is_service')->getValue());
+ $this->getTransport($this->request)->send($cmd);
+ $redirect = $this->getElement('redirect')->getValue();
+ if (! empty($redirect)) {
+ $this->setRedirectUrl($redirect);
+ }
+ Notification::success($this->translate('Deleting comment..'));
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/DeleteCommentsCommandForm.php b/modules/monitoring/application/forms/Command/Object/DeleteCommentsCommandForm.php
new file mode 100644
index 0000000..70ea7b8
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/DeleteCommentsCommandForm.php
@@ -0,0 +1,89 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
+use Icinga\Module\Monitoring\Forms\Command\CommandForm;
+use Icinga\Web\Notification;
+
+/**
+ * Form for deleting host or service comments
+ */
+class DeleteCommentsCommandForm extends CommandForm
+{
+ /**
+ * The comments to delete
+ *
+ * @var array
+ */
+ protected $comments;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setAttrib('class', 'inline');
+ }
+
+ /**
+ * Set the comments to delete
+ *
+ * @param iterable $comments
+ *
+ * @return $this
+ */
+ public function setComments($comments)
+ {
+ $this->comments = $comments;
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData = array())
+ {
+ $this->addElements(array(
+ array(
+ 'hidden',
+ 'redirect',
+ array('decorators' => array('ViewHelper'))
+ )
+ ));
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSubmitLabel()
+ {
+ return $this->translatePlural('Remove', 'Remove All', count($this->comments));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onSuccess()
+ {
+ foreach ($this->comments as $comment) {
+ $cmd = new DeleteCommentCommand();
+ $cmd
+ ->setCommentId($comment->id)
+ ->setCommentName($comment->name)
+ ->setAuthor($this->Auth()->getUser()->getUsername())
+ ->setIsService(isset($comment->service_description));
+ $this->getTransport($this->request)->send($cmd);
+ }
+ $redirect = $this->getElement('redirect')->getValue();
+ if (! empty($redirect)) {
+ $this->setRedirectUrl($redirect);
+ }
+ Notification::success(
+ $this->translatePlural('Deleting comment..', 'Deleting comments..', count($this->comments))
+ );
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php b/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php
new file mode 100644
index 0000000..79700cb
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/DeleteDowntimeCommandForm.php
@@ -0,0 +1,129 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
+use Icinga\Module\Monitoring\Exception\CommandTransportException;
+use Icinga\Module\Monitoring\Forms\Command\CommandForm;
+use Icinga\Web\Notification;
+
+/**
+ * Form for deleting host or service downtimes
+ */
+class DeleteDowntimeCommandForm extends CommandForm
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setAttrib('class', 'inline');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addSubmitButton()
+ {
+ $this->addElement(
+ 'button',
+ 'btn_submit',
+ array(
+ 'class' => 'link-button spinner',
+ 'decorators' => array(
+ 'ViewHelper',
+ array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
+ ),
+ 'escape' => false,
+ 'ignore' => true,
+ 'label' => $this->getView()->icon('cancel'),
+ 'title' => $this->translate('Delete this downtime'),
+ 'type' => 'submit'
+ )
+ );
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData = array())
+ {
+ $this->addElements(
+ array(
+ array(
+ 'hidden',
+ 'downtime_id',
+ array(
+ 'decorators' => array('ViewHelper'),
+ 'required' => true,
+ 'validators' => array('NotEmpty')
+ )
+ ),
+ array(
+ 'hidden',
+ 'downtime_is_service',
+ array(
+ 'decorators' => array('ViewHelper'),
+ 'filters' => array('Boolean')
+ )
+ ),
+ array(
+ 'hidden',
+ 'downtime_name',
+ array(
+ 'decorators' => array('ViewHelper')
+ )
+ ),
+ array(
+ 'hidden',
+ 'redirect',
+ array(
+ 'decorators' => array('ViewHelper')
+ )
+ )
+ )
+ );
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onSuccess()
+ {
+ $cmd = new DeleteDowntimeCommand();
+ $cmd
+ ->setAuthor($this->Auth()->getUser()->getUsername())
+ ->setDowntimeId($this->getElement('downtime_id')->getValue())
+ ->setDowntimeName($this->getElement('downtime_name')->getValue())
+ ->setIsService($this->getElement('downtime_is_service')->getValue());
+
+ $errorMsg = null;
+
+ try {
+ $this->getTransport($this->request)->send($cmd);
+ } catch (CommandTransportException $e) {
+ $errorMsg = $e->getMessage();
+ }
+
+ if (! $errorMsg) {
+ $redirect = $this->getElement('redirect')->getValue();
+ Notification::success($this->translate('Deleting downtime.'));
+ } else {
+ if (! $this->getIsApiTarget()) {
+ $redirect = $this->getRequest()->getUrl();
+ }
+
+ Notification::error($errorMsg);
+ }
+
+ if (! empty($redirect)) {
+ $this->setRedirectUrl($redirect);
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/DeleteDowntimesCommandForm.php b/modules/monitoring/application/forms/Command/Object/DeleteDowntimesCommandForm.php
new file mode 100644
index 0000000..d4ee803
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/DeleteDowntimesCommandForm.php
@@ -0,0 +1,89 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
+use Icinga\Module\Monitoring\Forms\Command\CommandForm;
+use Icinga\Web\Notification;
+
+/**
+ * Form for deleting host or service downtimes
+ */
+class DeleteDowntimesCommandForm extends CommandForm
+{
+ /**
+ * The downtimes to delete
+ *
+ * @var array
+ */
+ protected $downtimes;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setAttrib('class', 'inline');
+ }
+
+ /**
+ * Set the downtimes to delete
+ *
+ * @param iterable $downtimes
+ *
+ * @return $this
+ */
+ public function setDowntimes($downtimes)
+ {
+ $this->downtimes = $downtimes;
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData = array())
+ {
+ $this->addElements(array(
+ array(
+ 'hidden',
+ 'redirect',
+ array('decorators' => array('ViewHelper'))
+ )
+ ));
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSubmitLabel()
+ {
+ return $this->translatePlural('Remove', 'Remove All', count($this->downtimes));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onSuccess()
+ {
+ foreach ($this->downtimes as $downtime) {
+ $delDowntime = new DeleteDowntimeCommand();
+ $delDowntime
+ ->setDowntimeId($downtime->id)
+ ->setDowntimeName($downtime->name)
+ ->setAuthor($this->Auth()->getUser()->getUsername())
+ ->setIsService(isset($downtime->service_description));
+ $this->getTransport($this->request)->send($delDowntime);
+ }
+ $redirect = $this->getElement('redirect')->getValue();
+ if (! empty($redirect)) {
+ $this->setRedirectUrl($redirect);
+ }
+ Notification::success(
+ $this->translatePlural('Deleting downtime..', 'Deleting downtimes..', count($this->downtimes))
+ );
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php b/modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php
new file mode 100644
index 0000000..928c365
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ObjectsCommandForm.php
@@ -0,0 +1,47 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Module\Monitoring\Forms\Command\CommandForm;
+use Icinga\Module\Monitoring\Object\MonitoredObject;
+
+/**
+ * Base class for Icinga object command forms
+ */
+abstract class ObjectsCommandForm extends CommandForm
+{
+ /**
+ * Involved Icinga objects
+ *
+ * @var array|\Traversable|\ArrayAccess
+ */
+ protected $objects;
+
+ /**
+ * Set the involved Icinga objects
+ *
+ * @param $objects MonitoredObject|array|\Traversable|\ArrayAccess
+ *
+ * @return $this
+ */
+ public function setObjects($objects)
+ {
+ if ($objects instanceof MonitoredObject) {
+ $this->objects = array($objects);
+ } else {
+ $this->objects = $objects;
+ }
+ return $this;
+ }
+
+ /**
+ * Get the involved Icinga objects
+ *
+ * @return array|\ArrayAccess|\Traversable
+ */
+ public function getObjects()
+ {
+ return $this->objects;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ProcessCheckResultCommandForm.php b/modules/monitoring/application/forms/Command/Object/ProcessCheckResultCommandForm.php
new file mode 100644
index 0000000..7a196ec
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ProcessCheckResultCommandForm.php
@@ -0,0 +1,140 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Web\Notification;
+use Icinga\Module\Monitoring\Command\Object\ProcessCheckResultCommand;
+
+/**
+ * Form for submitting a passive host or service check result
+ */
+class ProcessCheckResultCommandForm extends ObjectsCommandForm
+{
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->addDescription($this->translate(
+ 'This command is used to submit passive host or service check results.'
+ ));
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
+ */
+ public function getSubmitLabel()
+ {
+ return $this->translatePlural(
+ 'Submit Passive Check Result',
+ 'Submit Passive Check Results',
+ count($this->objects)
+ );
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData)
+ {
+ $object = null;
+ foreach ($this->getObjects() as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+ // Nasty, but as getObjects() returns everything but an object with a real
+ // iterator interface this is the only way to fetch just the first element
+ break;
+ }
+
+ $this->addElement(
+ 'select',
+ 'status',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Status'),
+ 'description' => $this->translate('The state this check result should report'),
+ 'multiOptions' => $object->getType() === $object::TYPE_HOST ? $this->getHostMultiOptions() : array(
+ ProcessCheckResultCommand::SERVICE_OK => $this->translate('OK', 'icinga.state'),
+ ProcessCheckResultCommand::SERVICE_WARNING => $this->translate('WARNING', 'icinga.state'),
+ ProcessCheckResultCommand::SERVICE_CRITICAL => $this->translate('CRITICAL', 'icinga.state'),
+ ProcessCheckResultCommand::SERVICE_UNKNOWN => $this->translate('UNKNOWN', 'icinga.state')
+ )
+ )
+ );
+ $this->addElement(
+ 'text',
+ 'output',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Output'),
+ 'description' => $this->translate('The plugin output of this check result')
+ )
+ );
+ $this->addElement(
+ 'text',
+ 'perfdata',
+ array(
+ 'allowEmpty' => true,
+ 'label' => $this->translate('Performance Data'),
+ 'description' => $this->translate(
+ 'The performance data of this check result. Leave empty'
+ . ' if this check result has no performance data'
+ )
+ )
+ );
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ foreach ($this->objects as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+ if (! $object->passive_checks_enabled) {
+ continue;
+ }
+
+ $command = new ProcessCheckResultCommand();
+ $command->setObject($object);
+ $command->setStatus($this->getValue('status'));
+ $command->setOutput($this->getValue('output'));
+
+ if ($perfdata = $this->getValue('perfdata')) {
+ $command->setPerformanceData($perfdata);
+ }
+
+ $this->getTransport($this->request)->send($command);
+ }
+
+ Notification::success($this->translatePlural(
+ 'Processing check result..',
+ 'Processing check results..',
+ count($this->objects)
+ ));
+
+ return true;
+ }
+
+ /**
+ * Returns the available host options based on the program version
+ *
+ * @return array
+ */
+ protected function getHostMultiOptions()
+ {
+ $options = array(
+ ProcessCheckResultCommand::HOST_UP => $this->translate('UP', 'icinga.state'),
+ ProcessCheckResultCommand::HOST_DOWN => $this->translate('DOWN', 'icinga.state')
+ );
+
+ if (! $this->getBackend()->isIcinga2()) {
+ $options[ProcessCheckResultCommand::HOST_UNREACHABLE] = $this->translate('UNREACHABLE', 'icinga.state');
+ }
+
+ return $options;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php b/modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php
new file mode 100644
index 0000000..e45a055
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/RemoveAcknowledgementCommandForm.php
@@ -0,0 +1,122 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\RemoveAcknowledgementCommand;
+use Icinga\Web\Notification;
+
+/**
+ * Form for removing host or service problem acknowledgements
+ */
+class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
+{
+ /**
+ * Whether to show the submit label next to the remove icon
+ *
+ * The submit label is disabled in detail views but should be enabled in multi-select views.
+ *
+ * @var bool
+ */
+ protected $labelEnabled = false;
+
+ /**
+ * Whether to show the submit label next to the remove icon
+ *
+ * @return bool
+ */
+ public function isLabelEnabled()
+ {
+ return $this->labelEnabled;
+ }
+
+ /**
+ * Set whether to show the submit label next to the remove icon
+ *
+ * @param bool $labelEnabled
+ *
+ * @return $this
+ */
+ public function setLabelEnabled($labelEnabled)
+ {
+ $this->labelEnabled = (bool) $labelEnabled;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setAttrib('class', 'inline');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addSubmitButton()
+ {
+ $this->addElement(
+ 'button',
+ 'btn_submit',
+ array(
+ 'class' => 'link-button spinner',
+ 'decorators' => array(
+ 'ViewHelper',
+ array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
+ ),
+ 'escape' => false,
+ 'ignore' => true,
+ 'label' => $this->getSubmitLabel(),
+ 'title' => $this->translatePlural(
+ 'Remove acknowledgement',
+ 'Remove acknowledgements',
+ count($this->objects)
+ ),
+ 'type' => 'submit'
+ )
+ );
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSubmitLabel()
+ {
+ $label = $this->getView()->icon('cancel');
+ if ($this->isLabelEnabled()) {
+ $label .= $this->translatePlural(
+ 'Remove acknowledgement',
+ 'Remove acknowledgements',
+ count($this->objects)
+ );
+ }
+
+ return $label;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onSuccess()
+ {
+ foreach ($this->objects as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+ $removeAck = new RemoveAcknowledgementCommand();
+ $removeAck->setObject($object);
+ $removeAck->setAuthor($this->Auth()->getUser()->getUsername());
+ $this->getTransport($this->request)->send($removeAck);
+ }
+ Notification::success(mtp(
+ 'monitoring',
+ 'Removing acknowledgement..',
+ 'Removing acknowledgements..',
+ count($this->objects)
+ ));
+
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleHostCheckCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleHostCheckCommandForm.php
new file mode 100644
index 0000000..55b044f
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ScheduleHostCheckCommandForm.php
@@ -0,0 +1,67 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Application\Config;
+use Icinga\Module\Monitoring\Command\Object\ScheduleHostCheckCommand;
+use Icinga\Web\Notification;
+
+/**
+ * Form for scheduling host checks
+ */
+class ScheduleHostCheckCommandForm extends ScheduleServiceCheckCommandForm
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData = array())
+ {
+ $config = Config::module('monitoring');
+
+ parent::createElements($formData);
+ $this->addElements(array(
+ array(
+ 'checkbox',
+ 'all_services',
+ array(
+ 'label' => $this->translate('All Services'),
+ 'value' => (bool) $config->get('settings', 'hostcheck_all_services', false),
+ 'description' => $this->translate(
+ 'Schedule check for all services on the hosts and the hosts themselves.'
+ )
+ )
+ )
+ ));
+ return $this;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ foreach ($this->objects as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ if (! $object->active_checks_enabled
+ && ! $this->Auth()->hasPermission('monitoring/command/schedule-check')
+ ) {
+ continue;
+ }
+
+ $check = new ScheduleHostCheckCommand();
+ $check
+ ->setObject($object)
+ ->setOfAllServices($this->getElement('all_services')->isChecked());
+ $this->scheduleCheck($check, $this->request);
+ }
+ Notification::success($this->translatePlural(
+ 'Scheduling host check..',
+ 'Scheduling host checks..',
+ count($this->objects)
+ ));
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleHostDowntimeCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleHostDowntimeCommandForm.php
new file mode 100644
index 0000000..89db1ce
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ScheduleHostDowntimeCommandForm.php
@@ -0,0 +1,178 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use DateInterval;
+use DateTime;
+use Icinga\Application\Config;
+use Icinga\Module\Monitoring\Command\Object\ApiScheduleHostDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\PropagateHostDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\ScheduleHostDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Transport\ApiCommandTransport;
+use Icinga\Module\Monitoring\Command\Transport\CommandTransport;
+use Icinga\Web\Notification;
+
+/**
+ * Form for scheduling host downtimes
+ */
+class ScheduleHostDowntimeCommandForm extends ScheduleServiceDowntimeCommandForm
+{
+ /** @var bool */
+ protected $hostDowntimeAllServices;
+
+ public function init()
+ {
+ $this->start = new DateTime();
+ $config = Config::module('monitoring');
+ $this->commentText = $config->get('settings', 'hostdowntime_comment_text');
+
+ $this->hostDowntimeAllServices = (bool) $config->get('settings', 'hostdowntime_all_services', false);
+
+ $fixedEnd = clone $this->start;
+ $fixed = $config->get('settings', 'hostdowntime_end_fixed', 'PT1H');
+ $this->fixedEnd = $fixedEnd->add(new DateInterval($fixed));
+
+ $flexibleEnd = clone $this->start;
+ $flexible = $config->get('settings', 'hostdowntime_end_flexible', 'PT1H');
+ $this->flexibleEnd = $flexibleEnd->add(new DateInterval($flexible));
+
+ $flexibleDuration = $config->get('settings', 'hostdowntime_flexible_duration', 'PT2H');
+ $this->flexibleDuration = new DateInterval($flexibleDuration);
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData = array())
+ {
+ parent::createElements($formData);
+
+ $this->addElement(
+ 'checkbox',
+ 'all_services',
+ array(
+ 'description' => $this->translate(
+ 'Schedule downtime for all services on the hosts and the hosts themselves.'
+ ),
+ 'label' => $this->translate('All Services'),
+ 'value' => $this->hostDowntimeAllServices
+ )
+ );
+
+ if (! $this->getBackend()->isIcinga2()
+ || version_compare($this->getBackend()->getProgramVersion(), '2.6.0', '>=')
+ ) {
+ $this->addElement(
+ 'select',
+ 'child_hosts',
+ array(
+ 'description' => $this->translate(
+ 'Define what should be done with the child hosts of the hosts.'
+ ),
+ 'label' => $this->translate('Child Hosts'),
+ 'multiOptions' => array(
+ 0 => $this->translate('Do nothing with child hosts'),
+ 1 => $this->translate('Schedule triggered downtime for all child hosts'),
+ 2 => $this->translate('Schedule non-triggered downtime for all child hosts')
+ ),
+ 'value' => 0
+ )
+ );
+ }
+
+ return $this;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ $end = $this->getValue('end')->getTimestamp();
+ if ($end <= $this->getValue('start')->getTimestamp()) {
+ $endElement = $this->_elements['end'];
+ $endElement->setValue($endElement->getValue()->format($endElement->getFormat()));
+ $endElement->addError($this->translate('The end time must be greater than the start time'));
+ return false;
+ }
+
+ $now = new DateTime;
+ if ($end <= $now->getTimestamp()) {
+ $endElement = $this->_elements['end'];
+ $endElement->setValue($endElement->getValue()->format($endElement->getFormat()));
+ $endElement->addError($this->translate('A downtime must not be in the past'));
+ return false;
+ }
+
+ // Send all_services API parameter if Icinga is equal to or greater than 2.11.0
+ $allServicesNative = version_compare($this->getBackend()->getProgramVersion(), '2.11.0', '>=');
+ // Use ApiScheduleHostDowntimeCommand only when Icinga is equal to or greater than 2.11.0 and
+ // when an API command transport is requested or only API command transports are configured:
+ $useApiDowntime = $allServicesNative;
+ if ($useApiDowntime) {
+ $transport = $this->getTransport($this->getRequest());
+ if ($transport instanceof CommandTransport) {
+ foreach ($transport::getConfig() as $config) {
+ if (strtolower($config->transport) !== 'api') {
+ $useApiDowntime = false;
+ break;
+ }
+ }
+ } elseif (! $transport instanceof ApiCommandTransport) {
+ $useApiDowntime = false;
+ }
+ }
+
+ foreach ($this->objects as $object) {
+ if ($useApiDowntime) {
+ $hostDowntime = (new ApiScheduleHostDowntimeCommand())
+ ->setForAllServices($this->getElement('all_services')->isChecked())
+ ->setChildOptions((int) $this->getElement('child_hosts')->getValue());
+ // Code duplicated for readability and scope
+ $hostDowntime->setObject($object);
+ $this->scheduleDowntime($hostDowntime, $this->request);
+
+ continue;
+ }
+
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ if (($childHostsEl = $this->getElement('child_hosts')) !== null) {
+ $childHosts = (int) $childHostsEl->getValue();
+ } else {
+ $childHosts = 0;
+ }
+ $allServices = $this->getElement('all_services')->isChecked();
+ if ($childHosts === 0) {
+ $hostDowntime = (new ScheduleHostDowntimeCommand())
+ ->setForAllServicesNative($allServicesNative);
+ if ($allServices === true) {
+ $hostDowntime->setForAllServices();
+ };
+ } else {
+ $hostDowntime = new PropagateHostDowntimeCommand();
+ if ($childHosts === 1) {
+ $hostDowntime->setTriggered();
+ }
+ if ($allServices === true) {
+ foreach ($object->services as $service) {
+ $serviceDowntime = new ScheduleServiceDowntimeCommand();
+ $serviceDowntime->setObject($service);
+ $this->scheduleDowntime($serviceDowntime, $this->request);
+ }
+ }
+ }
+ $hostDowntime->setObject($object);
+ $this->scheduleDowntime($hostDowntime, $this->request);
+ }
+ Notification::success($this->translatePlural(
+ 'Scheduling host downtime..',
+ 'Scheduling host downtimes..',
+ count($this->objects)
+ ));
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php
new file mode 100644
index 0000000..f65aea8
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ScheduleServiceCheckCommandForm.php
@@ -0,0 +1,112 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use DateTime;
+use DateInterval;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceCheckCommand;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for scheduling service checks
+ */
+class ScheduleServiceCheckCommandForm extends ObjectsCommandForm
+{
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->addDescription($this->translate(
+ 'This command is used to schedule the next check of hosts or services. Icinga will re-queue the'
+ . ' hosts or services to be checked at the time you specify.'
+ ));
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
+ */
+ public function getSubmitLabel()
+ {
+ return $this->translatePlural('Schedule check', 'Schedule checks', count($this->objects));
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData = array())
+ {
+ $checkTime = new DateTime();
+ $checkTime->add(new DateInterval('PT1H'));
+ $this->addElements(array(
+ array(
+ 'dateTimePicker',
+ 'check_time',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Check Time'),
+ 'description' => $this->translate(
+ 'Set the date and time when the check should be scheduled.'
+ ),
+ 'value' => $checkTime
+ )
+ ),
+ array(
+ 'checkbox',
+ 'force_check',
+ array(
+ 'label' => $this->translate('Force Check'),
+ 'description' => $this->translate(
+ 'If you select this option, Icinga will force a check regardless of both what time the'
+ . ' scheduled check occurs and whether or not checks are enabled.'
+ )
+ )
+ )
+ ));
+ return $this;
+ }
+
+ /**
+ * Schedule a check
+ *
+ * @param ScheduleServiceCheckCommand $check
+ * @param Request $request
+ */
+ public function scheduleCheck(ScheduleServiceCheckCommand $check, Request $request)
+ {
+ $check
+ ->setForced($this->getElement('force_check')->isChecked())
+ ->setCheckTime($this->getElement('check_time')->getValue()->getTimestamp());
+ $this->getTransport($request)->send($check);
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ foreach ($this->objects as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ if (! $object->active_checks_enabled
+ && ! $this->Auth()->hasPermission('monitoring/command/schedule-check')
+ ) {
+ continue;
+ }
+
+ $check = new ScheduleServiceCheckCommand();
+ $check->setObject($object);
+ $this->scheduleCheck($check, $this->request);
+ }
+ Notification::success($this->translatePlural(
+ 'Scheduling service check..',
+ 'Scheduling service checks..',
+ count($this->objects)
+ ));
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php
new file mode 100644
index 0000000..90d50d4
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php
@@ -0,0 +1,263 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use DateTime;
+use DateInterval;
+use Icinga\Application\Config;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceDowntimeCommand;
+use Icinga\Web\Notification;
+use Icinga\Web\Request;
+
+/**
+ * Form for scheduling service downtimes
+ */
+class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm
+{
+ /**
+ * Fixed downtime
+ */
+ const FIXED = 'fixed';
+
+ /**
+ * Flexible downtime
+ */
+ const FLEXIBLE = 'flexible';
+
+ /** @var DateTime downtime start */
+ protected $start;
+
+ /** @var DateTime fixed downtime end */
+ protected $fixedEnd;
+
+ /** @var DateTime flexible downtime end */
+ protected $flexibleEnd;
+
+ /** @var DateInterval flexible downtime duration */
+ protected $flexibleDuration;
+
+ /** @var mixed Comment text */
+ protected $commentText;
+
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->start = new DateTime();
+
+ $config = Config::module('monitoring');
+
+ $this->commentText = $config->get('settings', 'servicedowntime_comment_text');
+ $fixedEnd = clone $this->start;
+ $fixed = $config->get('settings', 'servicedowntime_end_fixed', 'PT1H');
+ $this->fixedEnd = $fixedEnd->add(new DateInterval($fixed));
+
+ $flexibleEnd = clone $this->start;
+ $flexible = $config->get('settings', 'servicedowntime_end_flexible', 'PT1H');
+ $this->flexibleEnd = $flexibleEnd->add(new DateInterval($flexible));
+
+ $flexibleDuration = $config->get('settings', 'servicedowntime_flexible_duration', 'PT2H');
+ $this->flexibleDuration = new DateInterval($flexibleDuration);
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
+ */
+ public function getSubmitLabel()
+ {
+ return $this->translatePlural('Schedule downtime', 'Schedule downtimes', count($this->objects));
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::createElements() For the method documentation.
+ */
+ public function createElements(array $formData = array())
+ {
+ $this->addDescription($this->translate(
+ 'This command is used to schedule host and service downtimes. During the specified downtime,'
+ . ' Icinga will not send notifications out about the hosts and services. When the scheduled'
+ . ' downtime expires, Icinga will send out notifications for the hosts and services as it'
+ . ' normally would. Scheduled downtimes are preserved across program shutdowns and'
+ . ' restarts.'
+ ));
+
+ $isFlexible = (bool) isset($formData['type']) && $formData['type'] === self::FLEXIBLE;
+
+ $this->addElements(array(
+ array(
+ 'textarea',
+ 'comment',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Comment'),
+ 'description' => $this->translate(
+ 'If you work with other administrators, you may find it useful to share information about'
+ . ' the host or service that is having problems. Make sure you enter a brief description of'
+ . ' what you are doing.'
+ ),
+ 'attribs' => array('class' => 'autofocus'),
+ 'value' => $this->commentText
+ )
+ ),
+ array(
+ 'dateTimePicker',
+ 'start',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Start Time'),
+ 'description' => $this->translate('Set the start date and time for the downtime.'),
+ 'value' => $this->start
+ )
+ ),
+ array(
+ 'dateTimePicker',
+ 'end',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('End Time'),
+ 'description' => $this->translate('Set the end date and time for the downtime.'),
+ 'preserveDefault' => true,
+ 'value' => $isFlexible ? $this->flexibleEnd : $this->fixedEnd
+ )
+ ),
+ array(
+ 'select',
+ 'type',
+ array(
+ 'required' => true,
+ 'autosubmit' => true,
+ 'label' => $this->translate('Type'),
+ 'description' => $this->translate(
+ 'If you select the fixed option, the downtime will be in effect between the start and end'
+ . ' times you specify whereas a flexible downtime starts when the host or service enters a'
+ . ' problem state sometime between the start and end times you specified and lasts as long'
+ . ' as the duration time you enter. The duration fields do not apply for fixed downtimes.'
+ ),
+ 'multiOptions' => array(
+ self::FIXED => $this->translate('Fixed'),
+ self::FLEXIBLE => $this->translate('Flexible')
+ ),
+ 'validators' => array(
+ array(
+ 'InArray',
+ true,
+ array(array(self::FIXED, self::FLEXIBLE))
+ )
+ )
+ )
+ )
+ ));
+ $this->addDisplayGroup(
+ array('start', 'end'),
+ 'start-end',
+ array(
+ 'decorators' => array(
+ 'FormElements',
+ array('HtmlTag', array('tag' => 'div'))
+ )
+ )
+ );
+ if ($isFlexible) {
+ $this->addElements(array(
+ array(
+ 'number',
+ 'hours',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Hours'),
+ 'value' => $this->flexibleDuration->h,
+ 'min' => -1
+ )
+ ),
+ array(
+ 'number',
+ 'minutes',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Minutes'),
+ 'value' => $this->flexibleDuration->m,
+ 'min' => -1
+ )
+ )
+ ));
+ $this->addDisplayGroup(
+ array('hours', 'minutes'),
+ 'duration',
+ array(
+ 'legend' => $this->translate('Flexible Duration'),
+ 'description' => $this->translate(
+ 'Enter here the duration of the downtime. The downtime will be automatically deleted after this'
+ . ' time expired.'
+ ),
+ 'decorators' => array(
+ 'FormElements',
+ array('HtmlTag', array('tag' => 'div')),
+ array(
+ 'Description',
+ array('tag' => 'span', 'class' => 'description', 'placement' => 'prepend')
+ ),
+ 'Fieldset'
+ )
+ )
+ );
+ }
+ return $this;
+ }
+
+ public function scheduleDowntime(ScheduleServiceDowntimeCommand $downtime, Request $request)
+ {
+ $downtime
+ ->setComment($this->getElement('comment')->getValue())
+ ->setAuthor($request->getUser()->getUsername())
+ ->setStart($this->getElement('start')->getValue()->getTimestamp())
+ ->setEnd($this->getElement('end')->getValue()->getTimestamp());
+ if ($this->getElement('type')->getValue() === self::FLEXIBLE) {
+ $downtime->setFixed(false);
+ $downtime->setDuration(
+ (float) $this->getElement('hours')->getValue() * 3600
+ + (float) $this->getElement('minutes')->getValue() * 60
+ );
+ }
+ $this->getTransport($request)->send($downtime);
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ $end = $this->getValue('end')->getTimestamp();
+ if ($end <= $this->getValue('start')->getTimestamp()) {
+ $endElement = $this->_elements['end'];
+ $endElement->setValue($endElement->getValue()->format($endElement->getFormat()));
+ $endElement->addError($this->translate('The end time must be greater than the start time'));
+ return false;
+ }
+
+ $now = new DateTime;
+ if ($end <= $now->getTimestamp()) {
+ $endElement = $this->_elements['end'];
+ $endElement->setValue($endElement->getValue()->format($endElement->getFormat()));
+ $endElement->addError($this->translate('A downtime must not be in the past'));
+ return false;
+ }
+
+ foreach ($this->objects as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $downtime = new ScheduleServiceDowntimeCommand();
+ $downtime->setObject($object);
+ $this->scheduleDowntime($downtime, $this->request);
+ }
+ Notification::success($this->translatePlural(
+ 'Scheduling service downtime..',
+ 'Scheduling service downtimes..',
+ count($this->objects)
+ ));
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/SendCustomNotificationCommandForm.php b/modules/monitoring/application/forms/Command/Object/SendCustomNotificationCommandForm.php
new file mode 100644
index 0000000..0d1c393
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/SendCustomNotificationCommandForm.php
@@ -0,0 +1,110 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Application\Config;
+use Icinga\Module\Monitoring\Command\Object\SendCustomNotificationCommand;
+use Icinga\Web\Notification;
+
+/**
+ * Form to send custom notifications
+ */
+class SendCustomNotificationCommandForm extends ObjectsCommandForm
+{
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->addDescription(
+ $this->translate('This command is used to send custom notifications about hosts or services.')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSubmitLabel()
+ {
+ return $this->translatePlural('Send custom notification', 'Send custom notifications', count($this->objects));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData = array())
+ {
+ $config = Config::module('monitoring');
+
+ $this->addElements(array(
+ array(
+ 'textarea',
+ 'comment',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Comment'),
+ 'description' => $this->translate(
+ 'If you work with other administrators, you may find it useful to share information about'
+ . ' the host or service that is having problems. Make sure you enter a brief description of'
+ . ' what you are doing.'
+ )
+ )
+ ),
+ array(
+ 'checkbox',
+ 'forced',
+ array(
+ 'label' => $this->translate('Forced'),
+ 'value' => (bool) $config->get('settings', 'custom_notification_forced', false),
+ 'description' => $this->translate(
+ 'If you check this option, the notification is sent out regardless of time restrictions and'
+ . ' whether or not notifications are enabled.'
+ )
+ )
+ )
+ ));
+
+ if (! $this->getBackend()->isIcinga2()) {
+ $this->addElement(
+ 'checkbox',
+ 'broadcast',
+ array(
+ 'label' => $this->translate('Broadcast'),
+ 'value' => (bool) $config->get('settings', 'custom_notification_broadcast', false),
+ 'description' => $this->translate(
+ 'If you check this option, the notification is sent out to all normal and escalated contacts.'
+ )
+ )
+ );
+ }
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function onSuccess()
+ {
+ foreach ($this->objects as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+ $notification = new SendCustomNotificationCommand();
+ $notification
+ ->setObject($object)
+ ->setComment($this->getElement('comment')->getValue())
+ ->setAuthor($this->request->getUser()->getUsername())
+ ->setForced($this->getElement('forced')->isChecked());
+ if (($broadcast = $this->getElement('broadcast')) !== null) {
+ $notification->setBroadcast($broadcast->isChecked());
+ }
+ $this->getTransport($this->request)->send($notification);
+ }
+ Notification::success($this->translatePlural(
+ 'Sending custom notification..',
+ 'Sending custom notifications..',
+ count($this->objects)
+ ));
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php b/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php
new file mode 100644
index 0000000..e4aabb2
--- /dev/null
+++ b/modules/monitoring/application/forms/Command/Object/ToggleObjectFeaturesCommandForm.php
@@ -0,0 +1,187 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Command\Object;
+
+use Icinga\Module\Monitoring\Command\Object\ToggleObjectFeatureCommand;
+use Icinga\Module\Monitoring\Object\MonitoredObject;
+use Icinga\Web\Notification;
+
+/**
+ * Form for enabling or disabling features of Icinga objects, i.e. hosts or services
+ */
+class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm
+{
+ /**
+ * Feature to feature spec map
+ *
+ * @var string[]
+ */
+ protected $features;
+
+ /**
+ * Feature to feature status map
+ *
+ * @var int[]
+ */
+ protected $featureStatus;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setUseFormAutosubmit();
+ $this->setAttrib('class', self::DEFAULT_CLASSES . ' object-features');
+ $features = array(
+ ToggleObjectFeatureCommand::FEATURE_ACTIVE_CHECKS => array(
+ 'label' => $this->translate('Active Checks'),
+ 'permission' => 'monitoring/command/feature/object/active-checks'
+ ),
+ ToggleObjectFeatureCommand::FEATURE_PASSIVE_CHECKS => array(
+ 'label' => $this->translate('Passive Checks'),
+ 'permission' => 'monitoring/command/feature/object/passive-checks'
+ ),
+ ToggleObjectFeatureCommand::FEATURE_OBSESSING => array(
+ 'label' => $this->translate('Obsessing'),
+ 'permission' => 'monitoring/command/feature/object/obsessing'
+ ),
+ ToggleObjectFeatureCommand::FEATURE_NOTIFICATIONS => array(
+ 'label' => $this->translate('Notifications'),
+ 'permission' => 'monitoring/command/feature/object/notifications'
+ ),
+ ToggleObjectFeatureCommand::FEATURE_EVENT_HANDLER => array(
+ 'label' => $this->translate('Event Handler'),
+ 'permission' => 'monitoring/command/feature/object/event-handler'
+ ),
+ ToggleObjectFeatureCommand::FEATURE_FLAP_DETECTION => array(
+ 'label' => $this->translate('Flap Detection'),
+ 'permission' => 'monitoring/command/feature/object/flap-detection'
+ )
+ );
+ if ($this->getBackend()->isIcinga2()) {
+ unset($features[ToggleObjectFeatureCommand::FEATURE_OBSESSING]);
+ }
+ $this->features = $features;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData = array())
+ {
+ foreach ($this->features as $feature => $spec) {
+ $options = array(
+ 'autosubmit' => true,
+ 'disabled' => $this->hasPermission($spec['permission']) ? null : 'disabled',
+ 'label' => $spec['label']
+ );
+ if ($formData[$feature . '_changed']) {
+ $options['description'] = $this->translate('changed');
+ }
+ if ($formData[$feature] === 2) {
+ $this->addElement('select', $feature, $options + [
+ 'description' => $this->translate('Multiple Values'),
+ 'filters' => [['Null', ['type' => \Zend_Filter_Null::STRING]]],
+ 'multiOptions' => [
+ '' => $this->translate('Leave Unchanged'),
+ $this->translate('Disable All'),
+ $this->translate('Enable All')
+ ],
+ 'decorators' => array_merge(
+ array_slice(static::$defaultElementDecorators, 0, 3),
+ [['Description', ['tag' => 'span']]],
+ array_slice(static::$defaultElementDecorators, 4, 1),
+ [['HtmlTag', ['tag' => 'div', 'class' => 'control-group indeterminate']]]
+ )
+ ]);
+ } else {
+ $options['value'] = $formData[$feature];
+ $this->addElement('checkbox', $feature, $options);
+ }
+ }
+ }
+
+ /**
+ * Load feature status
+ *
+ * @param MonitoredObject|object $object
+ *
+ * @return $this
+ */
+ public function load($object)
+ {
+ $featureStatus = array();
+ foreach (array_keys($this->features) as $feature) {
+ $featureStatus[$feature] = $object->{$feature};
+ if (isset($object->{$feature . '_changed'})) {
+ $featureStatus[$feature . '_changed'] = (bool) $object->{$feature . '_changed'};
+ } else {
+ $featureStatus[$feature . '_changed'] = false;
+ }
+ }
+ $this->create($featureStatus);
+ $this->featureStatus = $featureStatus;
+
+ return $this;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Web\Form::onSuccess() For the method documentation.
+ */
+ public function onSuccess()
+ {
+ $notifications = array(
+ ToggleObjectFeatureCommand::FEATURE_ACTIVE_CHECKS => array(
+ $this->translate('Enabling active checks..'),
+ $this->translate('Disabling active checks..')
+ ),
+ ToggleObjectFeatureCommand::FEATURE_PASSIVE_CHECKS => array(
+ $this->translate('Enabling passive checks..'),
+ $this->translate('Disabling passive checks..')
+ ),
+ ToggleObjectFeatureCommand::FEATURE_OBSESSING => array(
+ $this->translate('Enabling obsessing..'),
+ $this->translate('Disabling obsessing..')
+ ),
+ ToggleObjectFeatureCommand::FEATURE_NOTIFICATIONS => array(
+ $this->translate('Enabling notifications..'),
+ $this->translate('Disabling notifications..')
+ ),
+ ToggleObjectFeatureCommand::FEATURE_EVENT_HANDLER => array(
+ $this->translate('Enabling event handler..'),
+ $this->translate('Disabling event handler..')
+ ),
+ ToggleObjectFeatureCommand::FEATURE_FLAP_DETECTION => array(
+ $this->translate('Enabling flap detection..'),
+ $this->translate('Disabling flap detection..')
+ )
+ );
+
+ foreach ($this->getValues() as $feature => $enabled) {
+ if ($this->getElement($feature)->getAttrib('disabled') !== null
+ || $enabled === null
+ || (int) $enabled === (int) $this->featureStatus[$feature]
+ ) {
+ continue;
+ }
+ foreach ($this->objects as $object) {
+ /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
+ if ((bool) $object->{$feature} !== (bool) $enabled) {
+ $toggleFeature = new ToggleObjectFeatureCommand();
+ $toggleFeature
+ ->setFeature($feature)
+ ->setObject($object)
+ ->setEnabled($enabled);
+ $this->getTransport($this->request)->send($toggleFeature);
+ }
+ }
+ Notification::success(
+ $notifications[$feature][$enabled ? 0 : 1]
+ );
+ }
+
+ return true;
+ }
+}
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');
+ }
+}
diff --git a/modules/monitoring/application/forms/EventOverviewForm.php b/modules/monitoring/application/forms/EventOverviewForm.php
new file mode 100644
index 0000000..78774f9
--- /dev/null
+++ b/modules/monitoring/application/forms/EventOverviewForm.php
@@ -0,0 +1,157 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms;
+
+use Icinga\Web\Url;
+use Icinga\Web\Form;
+use Icinga\Data\Filter\Filter;
+
+/**
+ * Configure the filter for the event overview
+ */
+class EventOverviewForm extends Form
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setName('form_event_overview');
+ $this->setDecorators(array(
+ 'FormElements',
+ array('HtmlTag', array('tag' => 'div', 'class' => 'hbox')),
+ 'Form'
+ ));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData)
+ {
+ $decorators = array(
+ array('Label', array('class' => 'optional')),
+ 'ViewHelper',
+ array('HtmlTag', array('tag' => 'div', 'class' => 'hbox-item optionbox')),
+ );
+
+ $url = Url::fromRequest()->getAbsoluteUrl();
+ $this->addElement(
+ 'checkbox',
+ 'statechange',
+ array(
+ 'label' => $this->translate('State Changes'),
+ 'class' => 'autosubmit',
+ 'decorators' => $decorators,
+ 'value' => strpos($url, $this->stateChangeFilter()->toQueryString()) === false ? 0 : 1
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ 'downtime',
+ array(
+ 'label' => $this->translate('Downtimes'),
+ 'class' => 'autosubmit',
+ 'decorators' => $decorators,
+ 'value' => strpos($url, $this->downtimeFilter()->toQueryString()) === false ? 0 : 1
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ 'comment',
+ array(
+ 'label' => $this->translate('Comments'),
+ 'class' => 'autosubmit',
+ 'decorators' => $decorators,
+ 'value' => strpos($url, $this->commentFilter()->toQueryString()) === false ? 0 : 1
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ 'notification',
+ array(
+ 'label' => $this->translate('Notifications'),
+ 'class' => 'autosubmit',
+ 'decorators' => $decorators,
+ 'value' => strpos($url, $this->notificationFilter()->toQueryString()) === false ? 0 : 1
+ )
+ );
+ $this->addElement(
+ 'checkbox',
+ 'flapping',
+ array(
+ 'label' => $this->translate('Flapping'),
+ 'class' => 'autosubmit',
+ 'decorators' => $decorators,
+ 'value' => strpos($url, $this->flappingFilter()->toQueryString()) === false ? 0 : 1
+ )
+ );
+ }
+
+ /**
+ * Return the corresponding filter-object
+ *
+ * @returns Filter
+ */
+ public function getFilter()
+ {
+ $filters = array();
+ if ($this->getValue('statechange')) {
+ $filters[] = $this->stateChangeFilter();
+ }
+ if ($this->getValue('comment')) {
+ $filters[] = $this->commentFilter();
+ }
+ if ($this->getValue('notification')) {
+ $filters[] = $this->notificationFilter();
+ }
+ if ($this->getValue('downtime')) {
+ $filters[] = $this->downtimeFilter();
+ }
+ if ($this->getValue('flapping')) {
+ $filters[] = $this->flappingFilter();
+ }
+ return Filter::matchAny($filters);
+ }
+
+ public function stateChangeFilter()
+ {
+ return Filter::matchAny(
+ Filter::expression('type', '=', 'hard_state'),
+ Filter::expression('type', '=', 'soft_state')
+ );
+ }
+
+ public function commentFilter()
+ {
+ return Filter::matchAny(
+ Filter::expression('type', '=', 'comment'),
+ Filter::expression('type', '=', 'comment_deleted'),
+ Filter::expression('type', '=', 'dt_comment'),
+ Filter::expression('type', '=', 'dt_comment_deleted'),
+ Filter::expression('type', '=', 'ack')
+ );
+ }
+
+ public function notificationFilter()
+ {
+ return Filter::expression('type', '=', 'notify');
+ }
+
+ public function downtimeFilter()
+ {
+ return Filter::matchAny(
+ Filter::expression('type', '=', 'downtime_start'),
+ Filter::expression('type', '=', 'downtime_end')
+ );
+ }
+
+ public function flappingFilter()
+ {
+ return Filter::matchAny(
+ Filter::expression('type', '=', 'flapping'),
+ Filter::expression('type', '=', 'flapping_deleted')
+ );
+ }
+}
diff --git a/modules/monitoring/application/forms/Navigation/ActionForm.php b/modules/monitoring/application/forms/Navigation/ActionForm.php
new file mode 100644
index 0000000..81d5588
--- /dev/null
+++ b/modules/monitoring/application/forms/Navigation/ActionForm.php
@@ -0,0 +1,79 @@
+<?php
+/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Navigation;
+
+use Icinga\Data\Filter\Filter;
+use Icinga\Exception\QueryException;
+use Icinga\Forms\Navigation\NavigationItemForm;
+
+class ActionForm extends NavigationItemForm
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData)
+ {
+ parent::createElements($formData);
+
+ $this->addElement(
+ 'text',
+ 'filter',
+ array(
+ 'allowEmpty' => true,
+ 'label' => $this->translate('Filter'),
+ 'description' => $this->translate(
+ 'Display this action only for objects matching this filter. Leave it blank'
+ . ' if you want this action being displayed regardless of the object'
+ )
+ )
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isValid($formData)
+ {
+ if (! parent::isValid($formData)) {
+ return false;
+ }
+
+ if (($filterString = $this->getValue('filter')) !== null) {
+ $filter = Filter::matchAll();
+ $filter->setAllowedFilterColumns(array(
+ 'host_name',
+ 'hostgroup_name',
+ 'instance_name',
+ 'service_description',
+ 'servicegroup_name',
+ 'contact_name',
+ 'contactgroup_name',
+ function ($c) {
+ return preg_match('/^_(?:host|service)_/', $c);
+ }
+ ));
+
+ try {
+ $filter->addFilter(Filter::fromQueryString($filterString));
+ } catch (QueryException $_) {
+ $this->getElement('filter')->addError(sprintf(
+ $this->translate('Invalid filter provided. You can only use the following columns: %s'),
+ implode(', ', array(
+ 'instance_name',
+ 'host_name',
+ 'hostgroup_name',
+ 'service_description',
+ 'servicegroup_name',
+ 'contact_name',
+ 'contactgroup_name',
+ '_(host|service)_<customvar-name>'
+ ))
+ ));
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Navigation/HostActionForm.php b/modules/monitoring/application/forms/Navigation/HostActionForm.php
new file mode 100644
index 0000000..da237d4
--- /dev/null
+++ b/modules/monitoring/application/forms/Navigation/HostActionForm.php
@@ -0,0 +1,8 @@
+<?php
+/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Navigation;
+
+class HostActionForm extends ActionForm
+{
+}
diff --git a/modules/monitoring/application/forms/Navigation/ServiceActionForm.php b/modules/monitoring/application/forms/Navigation/ServiceActionForm.php
new file mode 100644
index 0000000..68314d1
--- /dev/null
+++ b/modules/monitoring/application/forms/Navigation/ServiceActionForm.php
@@ -0,0 +1,8 @@
+<?php
+/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Navigation;
+
+class ServiceActionForm extends ActionForm
+{
+}
diff --git a/modules/monitoring/application/forms/Setup/BackendPage.php b/modules/monitoring/application/forms/Setup/BackendPage.php
new file mode 100644
index 0000000..d5c7efb
--- /dev/null
+++ b/modules/monitoring/application/forms/Setup/BackendPage.php
@@ -0,0 +1,51 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Setup;
+
+use Icinga\Web\Form;
+use Icinga\Application\Platform;
+
+class BackendPage extends Form
+{
+ public function init()
+ {
+ $this->setName('setup_monitoring_backend');
+ $this->setTitle($this->translate('Monitoring Backend', 'setup.page.title'));
+ $this->addDescription($this->translate(
+ 'Please configure below how Icinga Web 2 should retrieve monitoring information.'
+ ));
+ }
+
+ public function createElements(array $formData)
+ {
+ $this->addElement(
+ 'text',
+ 'name',
+ array(
+ 'required' => true,
+ 'value' => 'icinga',
+ 'label' => $this->translate('Backend Name'),
+ 'description' => $this->translate('The identifier of this backend')
+ )
+ );
+
+ $resourceTypes = array();
+ if (Platform::hasMysqlSupport() || Platform::hasPostgresqlSupport()) {
+ $resourceTypes['ido'] = 'IDO';
+ }
+
+ $this->addElement(
+ 'select',
+ 'type',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Backend Type'),
+ 'description' => $this->translate(
+ 'The data source used for retrieving monitoring information'
+ ),
+ 'multiOptions' => $resourceTypes
+ )
+ );
+ }
+}
diff --git a/modules/monitoring/application/forms/Setup/IdoResourcePage.php b/modules/monitoring/application/forms/Setup/IdoResourcePage.php
new file mode 100644
index 0000000..d648579
--- /dev/null
+++ b/modules/monitoring/application/forms/Setup/IdoResourcePage.php
@@ -0,0 +1,188 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Setup;
+
+use Icinga\Data\ConfigObject;
+use Icinga\Forms\Config\ResourceConfigForm;
+use Icinga\Forms\Config\Resource\DbResourceForm;
+use Icinga\Web\Form;
+use Icinga\Module\Monitoring\Forms\Config\BackendConfigForm;
+use Icinga\Module\Setup\Utils\DbTool;
+
+class IdoResourcePage extends Form
+{
+ /**
+ * Initialize this form
+ */
+ public function init()
+ {
+ $this->setName('setup_monitoring_ido');
+ $this->setTitle($this->translate('Monitoring IDO Resource', 'setup.page.title'));
+ $this->addDescription($this->translate(
+ 'Please fill out the connection details below to access the IDO database of your monitoring environment.'
+ ));
+ $this->setValidatePartial(true);
+ }
+
+ /**
+ * Create and add elements to this form
+ *
+ * @param array $formData
+ */
+ public function createElements(array $formData)
+ {
+ $this->addElement(
+ 'hidden',
+ 'type',
+ array(
+ 'required' => true,
+ 'value' => 'db'
+ )
+ );
+
+ if (isset($formData['skip_validation']) && $formData['skip_validation']) {
+ // In case another error occured and the checkbox was displayed before
+ $this->addSkipValidationCheckbox();
+ } else {
+ $this->addElement(
+ 'hidden',
+ 'skip_validation',
+ array(
+ 'required' => true,
+ 'value' => 0
+ )
+ );
+ }
+
+ $dbResourceForm = new DbResourceForm();
+ $this->addElements($dbResourceForm->createElements($formData)->getElements());
+ $this->getElement('name')->setValue('icinga_ido');
+ }
+
+ /**
+ * 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 (! isset($formData['skip_validation']) || !$formData['skip_validation']) {
+ if (! $this->validateConfiguration()) {
+ $this->addSkipValidationCheckbox();
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Run the configured backend's inspection checks and show the result, if necessary
+ *
+ * This will only run any validation if the user pushed the 'backend_validation' button.
+ *
+ * @param array $formData
+ *
+ * @return bool
+ */
+ public function isValidPartial(array $formData)
+ {
+ if (isset($formData['backend_validation']) && parent::isValid($formData)) {
+ if (! $this->validateConfiguration(true)) {
+ return false;
+ }
+
+ $this->info($this->translate('The configuration has been successfully validated.'));
+ } elseif (! isset($formData['backend_validation'])) {
+ // This is usually done by isValid(Partial), but as we're not calling any of these...
+ $this->populate($formData);
+ }
+
+ return true;
+ }
+
+ /**
+ * Return whether the configuration is valid
+ *
+ * @param bool $showLog Whether to show the validation log
+ *
+ * @return bool
+ */
+ protected function validateConfiguration($showLog = false)
+ {
+ $inspection = ResourceConfigForm::inspectResource($this);
+ if ($inspection !== null) {
+ if ($showLog) {
+ $join = function ($e) use (&$join) {
+ return is_string($e) ? $e : join("\n", array_map($join, $e));
+ };
+ $this->addElement(
+ 'note',
+ 'inspection_output',
+ array(
+ 'order' => 0,
+ 'value' => '<strong>' . $this->translate('Validation Log') . "</strong>\n\n"
+ . join("\n", array_map($join, $inspection->toArray())),
+ 'decorators' => array(
+ 'ViewHelper',
+ array('HtmlTag', array('tag' => 'pre', 'class' => 'log-output')),
+ )
+ )
+ );
+ }
+
+ if ($inspection->hasError()) {
+ $this->error(sprintf(
+ $this->translate('Failed to successfully validate the configuration: %s'),
+ $inspection->getError()
+ ));
+ return false;
+ }
+ }
+
+ $configObject = new ConfigObject($this->getValues());
+ if (! BackendConfigForm::isValidIdoSchema($this, $configObject)
+ || !BackendConfigForm::isValidIdoInstance($this, $configObject)
+ ) {
+ return false;
+ }
+
+ if ($this->getValue('db') === 'pgsql') {
+ $db = new DbTool($this->getValues());
+ $version = $db->connectToDb()->getServerVersion();
+ if (version_compare($version, '9.1', '<')) {
+ $this->error(sprintf(
+ $this->translate('The server\'s version %s is too old. The minimum required version is %s.'),
+ $version,
+ '9.1'
+ ));
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Add a checkbox to the form by which the user can skip the configuration validation
+ */
+ protected function addSkipValidationCheckbox()
+ {
+ $this->addElement(
+ 'checkbox',
+ 'skip_validation',
+ array(
+ 'required' => true,
+ 'label' => $this->translate('Skip Validation'),
+ 'description' => $this->translate('Check this to not to validate the configuration')
+ )
+ );
+ }
+}
diff --git a/modules/monitoring/application/forms/Setup/SecurityPage.php b/modules/monitoring/application/forms/Setup/SecurityPage.php
new file mode 100644
index 0000000..999103c
--- /dev/null
+++ b/modules/monitoring/application/forms/Setup/SecurityPage.php
@@ -0,0 +1,27 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Setup;
+
+use Icinga\Web\Form;
+use Icinga\Module\Monitoring\Forms\Config\SecurityConfigForm;
+
+class SecurityPage extends Form
+{
+ public function init()
+ {
+ $this->setName('setup_monitoring_security');
+ $this->setTitle($this->translate('Monitoring Security', 'setup.page.title'));
+ $this->addDescription($this->translate(
+ 'To protect your monitoring environment against prying eyes please fill out the settings below.'
+ ));
+ }
+
+ public function createElements(array $formData)
+ {
+ $securityConfigForm = new SecurityConfigForm();
+ $securityConfigForm->createElements($formData);
+ $this->addElements($securityConfigForm->getElements());
+ $this->getElement('protected_customvars')->setValue($securityConfigForm->getDefaultProtectedCustomvars());
+ }
+}
diff --git a/modules/monitoring/application/forms/Setup/TransportPage.php b/modules/monitoring/application/forms/Setup/TransportPage.php
new file mode 100644
index 0000000..9d0760a
--- /dev/null
+++ b/modules/monitoring/application/forms/Setup/TransportPage.php
@@ -0,0 +1,55 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Setup;
+
+use Icinga\Web\Form;
+use Icinga\Module\Monitoring\Forms\Config\TransportConfigForm;
+
+class TransportPage extends Form
+{
+ public function init()
+ {
+ $this->setName('setup_command_transport');
+ $this->setTitle($this->translate('Command Transport', 'setup.page.title'));
+ $this->addDescription($this->translate(
+ 'Please define below how you want to send commands to your monitoring instance.'
+ ));
+ $this->setValidatePartial(true);
+ }
+
+ public function createElements(array $formData)
+ {
+ $transportConfigForm = new TransportConfigForm();
+ $this->addSubForm($transportConfigForm, 'transport_form');
+ $transportConfigForm->create($formData);
+ $transportConfigForm->removeElement('instance');
+ $transportConfigForm->getElement('name')->setValue('icinga2');
+ }
+
+ public function getValues($suppressArrayNotation = false)
+ {
+ return $this->getSubForm('transport_form')->getValues($suppressArrayNotation);
+ }
+
+ /**
+ * Run the configured backend's inspection checks and show the result, if necessary
+ *
+ * This will only run any validation if the user pushed the 'transport_validation' button.
+ *
+ * @param array $formData
+ *
+ * @return bool
+ */
+ public function isValidPartial(array $formData)
+ {
+ if (isset($formData['transport_validation']) && parent::isValid($formData)) {
+ $this->info($this->translate('The configuration has been successfully validated.'));
+ } elseif (! isset($formData['transport_validation'])) {
+ // This is usually done by isValid(Partial), but as we're not calling any of these...
+ $this->populate($formData);
+ }
+
+ return true;
+ }
+}
diff --git a/modules/monitoring/application/forms/Setup/WelcomePage.php b/modules/monitoring/application/forms/Setup/WelcomePage.php
new file mode 100644
index 0000000..aa78db5
--- /dev/null
+++ b/modules/monitoring/application/forms/Setup/WelcomePage.php
@@ -0,0 +1,63 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms\Setup;
+
+use Icinga\Web\Form;
+
+class WelcomePage extends Form
+{
+ public function init()
+ {
+ $this->setName('setup_monitoring_welcome');
+ }
+
+ public function createElements(array $formData)
+ {
+ $this->addElement(
+ 'note',
+ 'welcome',
+ array(
+ 'value' => $this->translate(
+ 'Welcome to the configuration of the monitoring module for Icinga Web 2!'
+ ),
+ 'decorators' => array(
+ 'ViewHelper',
+ array('HtmlTag', array('tag' => 'h2'))
+ )
+ )
+ );
+
+ $this->addElement(
+ 'note',
+ 'core_hint',
+ array(
+ 'value' => $this->translate('This is the core module for Icinga Web 2.'),
+ 'decorators' => array('ViewHelper')
+ )
+ );
+
+ $this->addElement(
+ 'note',
+ 'description',
+ array(
+ 'value' => $this->translate(
+ 'It offers various status and reporting views with powerful filter capabilities that allow'
+ . ' you to keep track of the most important events in your monitoring environment.'
+ ),
+ 'decorators' => array('ViewHelper')
+ )
+ );
+
+ $this->addDisplayGroup(
+ array('core_hint', 'description'),
+ 'info',
+ array(
+ 'decorators' => array(
+ 'FormElements',
+ array('HtmlTag', array('tag' => 'div', 'class' => 'info'))
+ )
+ )
+ );
+ }
+}
diff --git a/modules/monitoring/application/forms/StatehistoryForm.php b/modules/monitoring/application/forms/StatehistoryForm.php
new file mode 100644
index 0000000..c28e39c
--- /dev/null
+++ b/modules/monitoring/application/forms/StatehistoryForm.php
@@ -0,0 +1,141 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Forms;
+
+use Icinga\Web\Form;
+use Icinga\Data\Filter\Filter;
+
+/**
+ * Configure the filter for the event grid
+ */
+class StatehistoryForm extends Form
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function init()
+ {
+ $this->setName('form_event_overview');
+ $this->setSubmitLabel($this->translate('Apply'));
+ }
+
+ /**
+ * Return the corresponding filter-object
+ *
+ * @returns Filter
+ */
+ public function getFilter()
+ {
+ $baseFilter = Filter::matchAny(
+ Filter::expression('type', '=', 'hard_state')
+ );
+
+ if ($this->getValue('objecttype') === 'hosts') {
+ $objectTypeFilter = Filter::expression('object_type', '=', 'host');
+ } else {
+ $objectTypeFilter = Filter::expression('object_type', '=', 'service');
+ }
+
+ $states = array(
+ 'cnt_down_hard' => Filter::expression('state', '=', '1'),
+ 'cnt_unreachable_hard' => Filter::expression('state', '=', '2'),
+ 'cnt_up' => Filter::expression('state', '=', '0'),
+ 'cnt_critical_hard' => Filter::expression('state', '=', '2'),
+ 'cnt_warning_hard' => Filter::expression('state', '=', '1'),
+ 'cnt_unknown_hard' => Filter::expression('state', '=', '3'),
+ 'cnt_ok' => Filter::expression('state', '=', '0')
+ );
+ $state = $this->getValue('state');
+ $stateFilter = $states[$state];
+ if (in_array($state, array('cnt_ok', 'cnt_up'))) {
+ return Filter::matchAll($objectTypeFilter, $stateFilter);
+ }
+ return Filter::matchAll($baseFilter, $objectTypeFilter, $stateFilter);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createElements(array $formData)
+ {
+ $this->addElement(
+ 'select',
+ 'from',
+ array(
+ 'label' => $this->translate('From'),
+ 'value' => $this->getRequest()->getParam('from', strtotime('3 months ago')),
+ 'multiOptions' => array(
+ strtotime('midnight 3 months ago') => $this->translate('3 Months'),
+ strtotime('midnight 4 months ago') => $this->translate('4 Months'),
+ strtotime('midnight 8 months ago') => $this->translate('8 Months'),
+ strtotime('midnight 12 months ago') => $this->translate('1 Year'),
+ strtotime('midnight 24 months ago') => $this->translate('2 Years')
+ )
+ )
+ );
+ $this->addElement(
+ 'select',
+ 'to',
+ array(
+ 'label' => $this->translate('To'),
+ 'value' => $this->getRequest()->getParam('to', time()),
+ 'multiOptions' => array(
+ time() => $this->translate('Today')
+ )
+ )
+ );
+
+ $objectType = $this->getRequest()->getParam('objecttype', 'services');
+ $this->addElement(
+ 'select',
+ 'objecttype',
+ array(
+ 'label' => $this->translate('Object type'),
+ 'value' => $objectType,
+ 'multiOptions' => array(
+ 'services' => $this->translate('Services'),
+ 'hosts' => $this->translate('Hosts')
+ )
+ )
+ );
+ if ($objectType === 'services') {
+ $serviceState = $this->getRequest()->getParam('state', 'cnt_critical_hard');
+ if (in_array($serviceState, array('cnt_down_hard', 'cnt_unreachable_hard', 'cnt_up'))) {
+ $serviceState = 'cnt_critical_hard';
+ }
+ $this->addElement(
+ 'select',
+ 'state',
+ array(
+ 'label' => $this->translate('State'),
+ 'value' => $serviceState,
+ 'multiOptions' => array(
+ 'cnt_critical_hard' => $this->translate('Critical'),
+ 'cnt_warning_hard' => $this->translate('Warning'),
+ 'cnt_unknown_hard' => $this->translate('Unknown'),
+ 'cnt_ok' => $this->translate('Ok')
+ )
+ )
+ );
+ } else {
+ $hostState = $this->getRequest()->getParam('state', 'cnt_down_hard');
+ if (in_array($hostState, array('cnt_ok', 'cnt_critical_hard', 'cnt_warning', 'cnt_unknown'))) {
+ $hostState = 'cnt_down_hard';
+ }
+ $this->addElement(
+ 'select',
+ 'state',
+ array(
+ 'label' => $this->translate('State'),
+ 'value' => $hostState,
+ 'multiOptions' => array(
+ 'cnt_up' => $this->translate('Up'),
+ 'cnt_down_hard' => $this->translate('Down'),
+ 'cnt_unreachable_hard' => $this->translate('Unreachable')
+ )
+ )
+ );
+ }
+ }
+}