summaryrefslogtreecommitdiffstats
path: root/modules/monitoring/library/Monitoring/Command
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:39:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:39:39 +0000
commit8ca6cc32b2c789a3149861159ad258f2cb9491e3 (patch)
tree2492de6f1528dd44eaa169a5c1555026d9cb75ec /modules/monitoring/library/Monitoring/Command
parentInitial commit. (diff)
downloadicingaweb2-upstream/2.11.4.tar.xz
icingaweb2-upstream/2.11.4.zip
Adding upstream version 2.11.4.upstream/2.11.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'modules/monitoring/library/Monitoring/Command')
-rw-r--r--modules/monitoring/library/Monitoring/Command/IcingaApiCommand.php126
-rw-r--r--modules/monitoring/library/Monitoring/Command/IcingaCommand.php21
-rw-r--r--modules/monitoring/library/Monitoring/Command/Instance/DisableNotificationsExpireCommand.php42
-rw-r--r--modules/monitoring/library/Monitoring/Command/Instance/ToggleInstanceFeatureCommand.php122
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/AcknowledgeProblemCommand.php144
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/AddCommentCommand.php80
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/ApiScheduleHostDowntimeCommand.php40
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/CommandAuthor.php38
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/DeleteCommentCommand.php110
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/DeleteDowntimeCommand.php110
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/ObjectCommand.php61
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/ProcessCheckResultCommand.php176
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/PropagateHostDowntimeCommand.php48
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/RemoveAcknowledgementCommand.php21
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/ScheduleHostCheckCommand.php48
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/ScheduleHostDowntimeCommand.php75
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceCheckCommand.php92
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceDowntimeCommand.php190
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/SendCustomNotificationCommand.php82
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/ToggleObjectFeatureCommand.php113
-rw-r--r--modules/monitoring/library/Monitoring/Command/Object/WithCommentCommand.php42
-rw-r--r--modules/monitoring/library/Monitoring/Command/Renderer/IcingaApiCommandRenderer.php324
-rw-r--r--modules/monitoring/library/Monitoring/Command/Renderer/IcingaCommandFileCommandRenderer.php478
-rw-r--r--modules/monitoring/library/Monitoring/Command/Renderer/IcingaCommandRendererInterface.php11
-rw-r--r--modules/monitoring/library/Monitoring/Command/Transport/ApiCommandTransport.php291
-rw-r--r--modules/monitoring/library/Monitoring/Command/Transport/CommandTransport.php170
-rw-r--r--modules/monitoring/library/Monitoring/Command/Transport/CommandTransportInterface.php22
-rw-r--r--modules/monitoring/library/Monitoring/Command/Transport/LocalCommandFile.php168
-rw-r--r--modules/monitoring/library/Monitoring/Command/Transport/RemoteCommandFile.php465
29 files changed, 3710 insertions, 0 deletions
diff --git a/modules/monitoring/library/Monitoring/Command/IcingaApiCommand.php b/modules/monitoring/library/Monitoring/Command/IcingaApiCommand.php
new file mode 100644
index 0000000..c33157f
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/IcingaApiCommand.php
@@ -0,0 +1,126 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command;
+
+class IcingaApiCommand
+{
+ /**
+ * Command data
+ *
+ * @var array
+ */
+ protected $data;
+
+ /**
+ * Name of the endpoint
+ *
+ * @var string
+ */
+ protected $endpoint;
+
+ /**
+ * Next Icinga API command to be sent, if any
+ *
+ * @var static
+ */
+ protected $next;
+
+ /**
+ * Create a new Icinga 2 API command
+ *
+ * @param string $endpoint
+ * @param array $data
+ *
+ * @return static
+ */
+ public static function create($endpoint, array $data)
+ {
+ $command = new static();
+ $command
+ ->setEndpoint($endpoint)
+ ->setData($data);
+ return $command;
+ }
+
+ /**
+ * Get the command data
+ *
+ * @return array
+ */
+ public function getData()
+ {
+ return $this->data;
+ }
+
+ /**
+ * Set the command data
+ *
+ * @param array $data
+ *
+ * @return $this
+ */
+ public function setData($data)
+ {
+ $this->data = $data;
+
+ return $this;
+ }
+
+ /**
+ * Get the name of the endpoint
+ *
+ * @return string
+ */
+ public function getEndpoint()
+ {
+ return $this->endpoint;
+ }
+
+ /**
+ * Set the name of the endpoint
+ *
+ * @param string $endpoint
+ *
+ * @return $this
+ */
+ public function setEndpoint($endpoint)
+ {
+ $this->endpoint = $endpoint;
+
+ return $this;
+ }
+
+ /**
+ * Get whether another Icinga API command should be sent after this one
+ *
+ * @return bool
+ */
+ public function hasNext()
+ {
+ return $this->next !== null;
+ }
+
+ /**
+ * Get the next Icinga API command
+ *
+ * @return IcingaApiCommand
+ */
+ public function getNext()
+ {
+ return $this->next;
+ }
+
+ /**
+ * Set the next Icinga API command
+ *
+ * @param IcingaApiCommand $next
+ *
+ * @return IcingaApiCommand
+ */
+ public function setNext(IcingaApiCommand $next)
+ {
+ $this->next = $next;
+ return $next;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/IcingaCommand.php b/modules/monitoring/library/Monitoring/Command/IcingaCommand.php
new file mode 100644
index 0000000..49ce586
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/IcingaCommand.php
@@ -0,0 +1,21 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command;
+
+/**
+ * Base class for commands sent to an Icinga instance
+ */
+abstract class IcingaCommand
+{
+ /**
+ * Get the name of the command
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ $nsParts = explode('\\', get_called_class());
+ return substr_replace(end($nsParts), '', -7); // Remove 'Command' Suffix
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Instance/DisableNotificationsExpireCommand.php b/modules/monitoring/library/Monitoring/Command/Instance/DisableNotificationsExpireCommand.php
new file mode 100644
index 0000000..1d3ce9d
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Instance/DisableNotificationsExpireCommand.php
@@ -0,0 +1,42 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Instance;
+
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+
+/**
+ * Disable host and service notifications w/ expire time on an Icinga instance
+ */
+class DisableNotificationsExpireCommand extends IcingaCommand
+{
+ /**
+ * The time when notifications should be re-enabled after disabling
+ *
+ * @var int|null Unix timestamp
+ */
+ protected $expireTime;
+
+ /**
+ * Set time when notifications should be re-enabled after disabling
+ *
+ * @param $expireTime int Unix timestamp
+ *
+ * @return $this
+ */
+ public function setExpireTime($expireTime)
+ {
+ $this->expireTime = (int) $expireTime;
+ return $this;
+ }
+
+ /**
+ * Get the date and time when notifications should be re-enabled after disabling
+ *
+ * @return int|null Unix timestamp
+ */
+ public function getExpireTime()
+ {
+ return $this->expireTime;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Instance/ToggleInstanceFeatureCommand.php b/modules/monitoring/library/Monitoring/Command/Instance/ToggleInstanceFeatureCommand.php
new file mode 100644
index 0000000..8a8a8ca
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Instance/ToggleInstanceFeatureCommand.php
@@ -0,0 +1,122 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Instance;
+
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+
+/**
+ * Enable or disable a feature of an Icinga instance
+ */
+class ToggleInstanceFeatureCommand extends IcingaCommand
+{
+ /**
+ * Feature for enabling or disabling active host checks on an Icinga instance
+ */
+ const FEATURE_ACTIVE_HOST_CHECKS = 'active_host_checks_enabled';
+
+ /**
+ * Feature for enabling or disabling active service checks on an Icinga instance
+ */
+ const FEATURE_ACTIVE_SERVICE_CHECKS = 'active_service_checks_enabled';
+
+ /**
+ * Feature for enabling or disabling host and service event handlers on an Icinga instance
+ */
+ const FEATURE_EVENT_HANDLERS = 'event_handlers_enabled';
+
+ /**
+ * Feature for enabling or disabling host and service flap detection on an Icinga instance
+ */
+ const FEATURE_FLAP_DETECTION = 'flap_detection_enabled';
+
+ /**
+ * Feature for enabling or disabling host and service notifications on an Icinga instance
+ */
+ const FEATURE_NOTIFICATIONS = 'notifications_enabled';
+
+ /**
+ * Feature for enabling or disabling processing of host checks via the OCHP command on an Icinga instance
+ */
+ const FEATURE_HOST_OBSESSING = 'obsess_over_hosts';
+
+ /**
+ * Feature for enabling or disabling processing of service checks via the OCHP command on an Icinga instance
+ */
+ const FEATURE_SERVICE_OBSESSING = 'obsess_over_services';
+
+ /**
+ * Feature for enabling or disabling passive host checks on an Icinga instance
+ */
+ const FEATURE_PASSIVE_HOST_CHECKS = 'passive_host_checks_enabled';
+
+ /**
+ * Feature for enabling or disabling passive service checks on an Icinga instance
+ */
+ const FEATURE_PASSIVE_SERVICE_CHECKS = 'passive_service_checks_enabled';
+
+ /**
+ * Feature for enabling or disabling the processing of host and service performance data on an Icinga instance
+ */
+ const FEATURE_PERFORMANCE_DATA = 'process_performance_data';
+
+ /**
+ * Feature that is to be enabled or disabled
+ *
+ * @var string
+ */
+ protected $feature;
+
+ /**
+ * Whether the feature should be enabled or disabled
+ *
+ * @var bool
+ */
+ protected $enabled;
+
+ /**
+ * Set the feature that is to be enabled or disabled
+ *
+ * @param string $feature
+ *
+ * @return $this
+ */
+ public function setFeature($feature)
+ {
+ $this->feature = (string) $feature;
+ return $this;
+ }
+
+ /**
+ * Get the feature that is to be enabled or disabled
+ *
+ * @return string
+ */
+ public function getFeature()
+ {
+ return $this->feature;
+ }
+
+ /**
+ * Set whether the feature should be enabled or disabled
+ *
+ * @param bool $enabled
+ *
+ * @return $this
+ */
+ public function setEnabled($enabled = true)
+ {
+ $this->enabled = (bool) $enabled;
+ return $this;
+ }
+
+ /**
+ * Get whether the feature should be enabled or disabled
+ *
+ * @return bool
+ */
+ public function getEnabled()
+ {
+ return $this->enabled;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/AcknowledgeProblemCommand.php b/modules/monitoring/library/Monitoring/Command/Object/AcknowledgeProblemCommand.php
new file mode 100644
index 0000000..2001e78
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/AcknowledgeProblemCommand.php
@@ -0,0 +1,144 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Acknowledge a host or service problem
+ */
+class AcknowledgeProblemCommand extends WithCommentCommand
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Module\Monitoring\Command\Object\ObjectCommand::$allowedObjects For the property documentation.
+ */
+ protected $allowedObjects = array(
+ self::TYPE_HOST,
+ self::TYPE_SERVICE
+ );
+
+ /**
+ * Whether the acknowledgement is sticky
+ *
+ * Sticky acknowledgements remain until the host or service recovers. Non-sticky acknowledgements will be
+ * automatically removed when the host or service state changes.
+ *
+ * @var bool
+ */
+ protected $sticky = false;
+
+ /**
+ * Whether to send a notification about the acknowledgement
+
+ * @var bool
+ */
+ protected $notify = false;
+
+ /**
+ * Whether the comment associated with the acknowledgement is persistent
+ *
+ * Persistent comments are not lost the next time the monitoring host restarts.
+ *
+ * @var bool
+ */
+ protected $persistent = false;
+
+ /**
+ * Optional time when the acknowledgement should expire
+ *
+ * @var int|null
+ */
+ protected $expireTime;
+
+ /**
+ * Set whether the acknowledgement is sticky
+ *
+ * @param bool $sticky
+ *
+ * @return $this
+ */
+ public function setSticky($sticky = true)
+ {
+ $this->sticky = (bool) $sticky;
+ return $this;
+ }
+
+ /**
+ * Is the acknowledgement sticky?
+ *
+ * @return bool
+ */
+ public function getSticky()
+ {
+ return $this->sticky;
+ }
+
+ /**
+ * Set whether to send a notification about the acknowledgement
+ *
+ * @param bool $notify
+ *
+ * @return $this
+ */
+ public function setNotify($notify = true)
+ {
+ $this->notify = (bool) $notify;
+ return $this;
+ }
+
+ /**
+ * Get whether to send a notification about the acknowledgement
+ *
+ * @return bool
+ */
+ public function getNotify()
+ {
+ return $this->notify;
+ }
+
+ /**
+ * Set whether the comment associated with the acknowledgement is persistent
+ *
+ * @param bool $persistent
+ *
+ * @return $this
+ */
+ public function setPersistent($persistent = true)
+ {
+ $this->persistent = (bool) $persistent;
+ return $this;
+ }
+
+ /**
+ * Is the comment associated with the acknowledgement is persistent?
+ *
+ * @return bool
+ */
+ public function getPersistent()
+ {
+ return $this->persistent;
+ }
+
+ /**
+ * Set the time when the acknowledgement should expire
+ *
+ * @param int $expireTime
+ *
+ * @return $this
+ */
+ public function setExpireTime($expireTime)
+ {
+ $this->expireTime = (int) $expireTime;
+ return $this;
+ }
+
+ /**
+ * Get the time when the acknowledgement should expire
+ *
+ * @return int|null
+ */
+ public function getExpireTime()
+ {
+ return $this->expireTime;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/AddCommentCommand.php b/modules/monitoring/library/Monitoring/Command/Object/AddCommentCommand.php
new file mode 100644
index 0000000..9e3151f
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/AddCommentCommand.php
@@ -0,0 +1,80 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Add a comment to a host or service
+ */
+class AddCommentCommand extends WithCommentCommand
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Module\Monitoring\Command\Object\ObjectCommand::$allowedObjects For the property documentation.
+ */
+ protected $allowedObjects = array(
+ self::TYPE_HOST,
+ self::TYPE_SERVICE
+ );
+
+ /**
+ * Whether the comment is persistent
+ *
+ * Persistent comments are not lost the next time the monitoring host restarts.
+ */
+ protected $persistent;
+
+ /**
+ * Optional time when the acknowledgement should expire
+ *
+ * @var int|null
+ */
+ protected $expireTime;
+
+ /**
+ * Set whether the comment is persistent
+ *
+ * @param bool $persistent
+ *
+ * @return $this
+ */
+ public function setPersistent($persistent = true)
+ {
+ $this->persistent = $persistent;
+ return $this;
+ }
+
+ /**
+ * Is the comment persistent?
+ *
+ * @return bool
+ */
+ public function getPersistent()
+ {
+ return $this->persistent;
+ }
+
+ /**
+ * Set the time when the acknowledgement should expire
+ *
+ * @param int $expireTime
+ *
+ * @return $this
+ */
+ public function setExpireTime($expireTime)
+ {
+ $this->expireTime = (int) $expireTime;
+
+ return $this;
+ }
+
+ /**
+ * Get the time when the acknowledgement should expire
+ *
+ * @return int|null
+ */
+ public function getExpireTime()
+ {
+ return $this->expireTime;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/ApiScheduleHostDowntimeCommand.php b/modules/monitoring/library/Monitoring/Command/Object/ApiScheduleHostDowntimeCommand.php
new file mode 100644
index 0000000..6495375
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/ApiScheduleHostDowntimeCommand.php
@@ -0,0 +1,40 @@
+<?php
+/* Icinga Web 2 | (c) 2021 Icinga GmbH | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Schedule host downtime command for API command transport and Icinga >= 2.11.0 that
+ * sends all_services and child_options in a single request
+ */
+class ApiScheduleHostDowntimeCommand extends ScheduleHostDowntimeCommand
+{
+ /** @var int Whether no, triggered, or non-triggered child downtimes should be scheduled */
+ protected $childOptions;
+
+ protected $forAllServicesNative = true;
+
+ /**
+ * Get child options, i.e. whether no, triggered, or non-triggered child downtimes should be scheduled
+ *
+ * @return int
+ */
+ public function getChildOptions()
+ {
+ return $this->childOptions;
+ }
+
+ /**
+ * Set child options, i.e. whether no, triggered, or non-triggered child downtimes should be scheduled
+ *
+ * @param int $childOptions
+ *
+ * @return $this
+ */
+ public function setChildOptions($childOptions)
+ {
+ $this->childOptions = $childOptions;
+
+ return $this;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/CommandAuthor.php b/modules/monitoring/library/Monitoring/Command/Object/CommandAuthor.php
new file mode 100644
index 0000000..577e3df
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/CommandAuthor.php
@@ -0,0 +1,38 @@
+<?php
+
+/* Icinga Web 2 | (c) 2020 Icinga GmbH | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+trait CommandAuthor
+{
+ /**
+ * Author of the command
+ *
+ * @var string
+ */
+ protected $author;
+
+ /**
+ * Set the author
+ *
+ * @param string $author
+ *
+ * @return $this
+ */
+ public function setAuthor($author)
+ {
+ $this->author = (string) $author;
+ return $this;
+ }
+
+ /**
+ * Get the author
+ *
+ * @return string
+ */
+ public function getAuthor()
+ {
+ return $this->author;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/DeleteCommentCommand.php b/modules/monitoring/library/Monitoring/Command/Object/DeleteCommentCommand.php
new file mode 100644
index 0000000..348175a
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/DeleteCommentCommand.php
@@ -0,0 +1,110 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+
+/**
+ * Delete a host or service comment
+ */
+class DeleteCommentCommand extends IcingaCommand
+{
+ use CommandAuthor;
+
+ /**
+ * ID of the comment that is to be deleted
+ *
+ * @var int
+ */
+ protected $commentId;
+
+ /**
+ * Name of the comment (Icinga 2.4+)
+ *
+ * Required for removing the comment via Icinga 2's API.
+ *
+ * @var string
+ */
+ protected $commentName;
+
+ /**
+ * Whether the command affects a service comment
+ *
+ * @var boolean
+ */
+ protected $isService = false;
+
+ /**
+ * Get the ID of the comment that is to be deleted
+ *
+ * @return int
+ */
+ public function getCommentId()
+ {
+ return $this->commentId;
+ }
+
+ /**
+ * Set the ID of the comment that is to be deleted
+ *
+ * @param int $commentId
+ *
+ * @return $this
+ */
+ public function setCommentId($commentId)
+ {
+ $this->commentId = (int) $commentId;
+ return $this;
+ }
+
+ /**
+ * Get the name of the comment (Icinga 2.4+)
+ *
+ * Required for removing the comment via Icinga 2's API.
+ *
+ * @return string
+ */
+ public function getCommentName()
+ {
+ return $this->commentName;
+ }
+
+ /**
+ * Set the name of the comment (Icinga 2.4+)
+ *
+ * Required for removing the comment via Icinga 2's API.
+ *
+ * @param string $commentName
+ *
+ * @return $this
+ */
+ public function setCommentName($commentName)
+ {
+ $this->commentName = $commentName;
+ return $this;
+ }
+
+ /**
+ * Get whether the command affects a service comment
+ *
+ * @return boolean
+ */
+ public function getIsService()
+ {
+ return $this->isService;
+ }
+
+ /**
+ * Set whether the command affects a service comment
+ *
+ * @param bool $isService
+ *
+ * @return $this
+ */
+ public function setIsService($isService = true)
+ {
+ $this->isService = (bool) $isService;
+ return $this;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/DeleteDowntimeCommand.php b/modules/monitoring/library/Monitoring/Command/Object/DeleteDowntimeCommand.php
new file mode 100644
index 0000000..a314864
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/DeleteDowntimeCommand.php
@@ -0,0 +1,110 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+
+/**
+ * Delete a host or service downtime
+ */
+class DeleteDowntimeCommand extends IcingaCommand
+{
+ use CommandAuthor;
+
+ /**
+ * ID of the downtime that is to be deleted
+ *
+ * @var int
+ */
+ protected $downtimeId;
+
+ /**
+ * Name of the downtime (Icinga 2.4+)
+ *
+ * Required for removing the downtime via Icinga 2's API.
+ *
+ * @var string
+ */
+ protected $downtimeName;
+
+ /**
+ * Whether the command affects a service downtime
+ *
+ * @var boolean
+ */
+ protected $isService = false;
+
+ /**
+ * Get the ID of the downtime that is to be deleted
+ *
+ * @return int
+ */
+ public function getDowntimeId()
+ {
+ return $this->downtimeId;
+ }
+
+ /**
+ * Set the ID of the downtime that is to be deleted
+ *
+ * @param int $downtimeId
+ *
+ * @return $this
+ */
+ public function setDowntimeId($downtimeId)
+ {
+ $this->downtimeId = (int) $downtimeId;
+ return $this;
+ }
+
+ /**
+ * Get the name of the downtime (Icinga 2.4+)
+ *
+ * Required for removing the downtime via Icinga 2's API.
+ *
+ * @return string
+ */
+ public function getDowntimeName()
+ {
+ return $this->downtimeName;
+ }
+
+ /**
+ * Set the name of the downtime (Icinga 2.4+)
+ *
+ * Required for removing the downtime via Icinga 2's API.
+ *
+ * @param string $downtimeName
+ *
+ * @return $this
+ */
+ public function setDowntimeName($downtimeName)
+ {
+ $this->downtimeName = $downtimeName;
+ return $this;
+ }
+
+ /**
+ * Get whether the command affects a service
+ *
+ * @return bool
+ */
+ public function getIsService()
+ {
+ return $this->isService;
+ }
+
+ /**
+ * Set whether the command affects a service
+ *
+ * @param bool $isService
+ *
+ * @return $this
+ */
+ public function setIsService($isService = true)
+ {
+ $this->isService = (bool) $isService;
+ return $this;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/ObjectCommand.php b/modules/monitoring/library/Monitoring/Command/Object/ObjectCommand.php
new file mode 100644
index 0000000..43ab645
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/ObjectCommand.php
@@ -0,0 +1,61 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+use Icinga\Module\Monitoring\Object\MonitoredObject;
+
+/**
+ * Base class for commands that involve a monitored object, i.e. a host or service
+ */
+abstract class ObjectCommand extends IcingaCommand
+{
+ /**
+ * Type host
+ */
+ const TYPE_HOST = MonitoredObject::TYPE_HOST;
+
+ /**
+ * Type service
+ */
+ const TYPE_SERVICE = MonitoredObject::TYPE_SERVICE;
+
+ /**
+ * Allowed Icinga object types for the command
+ *
+ * @var string[]
+ */
+ protected $allowedObjects = array();
+
+ /**
+ * Involved object
+ *
+ * @var MonitoredObject
+ */
+ protected $object;
+
+ /**
+ * Set the involved object
+ *
+ * @param MonitoredObject $object
+ *
+ * @return $this
+ */
+ public function setObject(MonitoredObject $object)
+ {
+ $object->assertOneOf($this->allowedObjects);
+ $this->object = $object;
+ return $this;
+ }
+
+ /**
+ * Get the involved object
+ *
+ * @return MonitoredObject
+ */
+ public function getObject()
+ {
+ return $this->object;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/ProcessCheckResultCommand.php b/modules/monitoring/library/Monitoring/Command/Object/ProcessCheckResultCommand.php
new file mode 100644
index 0000000..cd2db33
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/ProcessCheckResultCommand.php
@@ -0,0 +1,176 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+use InvalidArgumentException;
+use LogicException;
+
+/**
+ * Submit a passive check result for a host or service
+ */
+class ProcessCheckResultCommand extends ObjectCommand
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Module\Monitoring\Command\Object\ObjectCommand::$allowedObjects For the property documentation.
+ */
+ protected $allowedObjects = array(
+ self::TYPE_HOST,
+ self::TYPE_SERVICE
+ );
+
+ /**
+ * Host up
+ */
+ const HOST_UP = 0;
+
+ /**
+ * Host down
+ */
+ const HOST_DOWN = 1;
+
+ /**
+ * Host unreachable
+ */
+ const HOST_UNREACHABLE = 2; // TODO: Icinga 2.x does not support submitting results with this state, yet
+
+ /**
+ * Service ok
+ */
+ const SERVICE_OK = 0;
+
+ /**
+ * Service warning
+ */
+ const SERVICE_WARNING = 1;
+
+ /**
+ * Service critical
+ */
+ const SERVICE_CRITICAL = 2;
+
+ /**
+ * Service unknown
+ */
+ const SERVICE_UNKNOWN = 3;
+
+ /**
+ * Possible status codes for passive host and service checks
+ *
+ * @var array
+ */
+ public static $statusCodes = array(
+ self::TYPE_HOST => array(
+ self::HOST_UP, self::HOST_DOWN, self::HOST_UNREACHABLE
+ ),
+ self::TYPE_SERVICE => array(
+ self::SERVICE_OK, self::SERVICE_WARNING, self::SERVICE_CRITICAL, self::SERVICE_UNKNOWN
+ )
+ );
+
+ /**
+ * Status code of the host or service check result
+ *
+ * @var int
+ */
+ protected $status;
+
+ /**
+ * Text output of the host or service check result
+ *
+ * @var string
+ */
+ protected $output;
+
+ /**
+ * Optional performance data of the host or service check result
+ *
+ * @var string
+ */
+ protected $performanceData;
+
+
+ /**
+ * Set the status code of the host or service check result
+ *
+ * @param int $status
+ *
+ * @return $this
+ *
+ * @throws LogicException If the object is null
+ * @throws InvalidArgumentException If status is not one of the valid status codes for the object's type
+ */
+ public function setStatus($status)
+ {
+ if ($this->object === null) {
+ throw new LogicException('You\'re required to call setObject() before calling setStatus()');
+ }
+ $status = (int) $status;
+ if (! in_array($status, self::$statusCodes[$this->object->getType()])) {
+ throw new InvalidArgumentException(sprintf(
+ 'The status code %u you provided is not one of the valid status codes for type %s',
+ $status,
+ $this->object->getType()
+ ));
+ }
+ $this->status = $status;
+ return $this;
+ }
+
+ /**
+ * Get the status code of the host or service check result
+ *
+ * @return int
+ */
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ /**
+ * Set the text output of the host or service check result
+ *
+ * @param string $output
+ *
+ * @return $this
+ */
+ public function setOutput($output)
+ {
+ $this->output = (string) $output;
+ return $this;
+ }
+
+ /**
+ * Get the text output of the host or service check result
+ *
+ * @return string
+ */
+ public function getOutput()
+ {
+ return $this->output;
+ }
+
+ /**
+ * Set the performance data of the host or service check result
+ *
+ * @param string $performanceData
+ *
+ * @return $this
+ */
+ public function setPerformanceData($performanceData)
+ {
+ $this->performanceData = (string) $performanceData;
+ return $this;
+ }
+
+ /**
+ * Get the performance data of the host or service check result
+ *
+ * @return string
+ */
+ public function getPerformanceData()
+ {
+ return $this->performanceData;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/PropagateHostDowntimeCommand.php b/modules/monitoring/library/Monitoring/Command/Object/PropagateHostDowntimeCommand.php
new file mode 100644
index 0000000..3fd350c
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/PropagateHostDowntimeCommand.php
@@ -0,0 +1,48 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Schedule and propagate host downtime
+ */
+class PropagateHostDowntimeCommand extends ScheduleServiceDowntimeCommand
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Module\Monitoring\Command\Object\ObjectCommand::$allowedObjects For the property documentation.
+ */
+ protected $allowedObjects = array(
+ self::TYPE_HOST
+ );
+
+ /**
+ * Whether the downtime for child hosts are all set to be triggered by this' host downtime
+ *
+ * @var bool
+ */
+ protected $triggered = false;
+
+ /**
+ * Set whether the downtime for child hosts are all set to be triggered by this' host downtime
+ *
+ * @param bool $triggered
+ *
+ * @return $this
+ */
+ public function setTriggered($triggered = true)
+ {
+ $this->triggered = (bool) $triggered;
+ return $this;
+ }
+
+ /**
+ * Get whether the downtime for child hosts are all set to be triggered by this' host downtime
+ *
+ * @return bool
+ */
+ public function getTriggered()
+ {
+ return $this->triggered;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/RemoveAcknowledgementCommand.php b/modules/monitoring/library/Monitoring/Command/Object/RemoveAcknowledgementCommand.php
new file mode 100644
index 0000000..31c8180
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/RemoveAcknowledgementCommand.php
@@ -0,0 +1,21 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Remove a problem acknowledgement from a host or service
+ */
+class RemoveAcknowledgementCommand extends ObjectCommand
+{
+ use CommandAuthor;
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Module\Monitoring\Command\Object\ObjectCommand::$allowedObjects For the property documentation.
+ */
+ protected $allowedObjects = array(
+ self::TYPE_HOST,
+ self::TYPE_SERVICE
+ );
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/ScheduleHostCheckCommand.php b/modules/monitoring/library/Monitoring/Command/Object/ScheduleHostCheckCommand.php
new file mode 100644
index 0000000..8a0a2cb
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/ScheduleHostCheckCommand.php
@@ -0,0 +1,48 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Schedule a host check
+ */
+class ScheduleHostCheckCommand extends ScheduleServiceCheckCommand
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Module\Monitoring\Command\Object\ObjectCommand::$allowedObjects For the property documentation.
+ */
+ protected $allowedObjects = array(
+ self::TYPE_HOST
+ );
+
+ /**
+ * Whether to schedule a check of all services associated with a particular host
+ *
+ * @var bool
+ */
+ protected $ofAllServices = false;
+
+ /**
+ * Set whether to schedule a check of all services associated with a particular host
+ *
+ * @param bool $ofAllServices
+ *
+ * @return $this
+ */
+ public function setOfAllServices($ofAllServices = true)
+ {
+ $this->ofAllServices = (bool) $ofAllServices;
+ return $this;
+ }
+
+ /**
+ * Get whether to schedule a check of all services associated with a particular host
+ *
+ * @return bool
+ */
+ public function getOfAllServices()
+ {
+ return $this->ofAllServices;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/ScheduleHostDowntimeCommand.php b/modules/monitoring/library/Monitoring/Command/Object/ScheduleHostDowntimeCommand.php
new file mode 100644
index 0000000..3ac37d3
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/ScheduleHostDowntimeCommand.php
@@ -0,0 +1,75 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Schedule a host downtime
+ */
+class ScheduleHostDowntimeCommand extends ScheduleServiceDowntimeCommand
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Module\Monitoring\Command\Object\ObjectCommand::$allowedObjects For the property documentation.
+ */
+ protected $allowedObjects = array(
+ self::TYPE_HOST
+ );
+
+ /**
+ * Whether to schedule a downtime for all services associated with a particular host
+ *
+ * @var bool
+ */
+ protected $forAllServices = false;
+
+ /** @var bool Whether to send the all_services API parameter */
+ protected $forAllServicesNative;
+
+ /**
+ * Set whether to schedule a downtime for all services associated with a particular host
+ *
+ * @param bool $forAllServices
+ *
+ * @return $this
+ */
+ public function setForAllServices($forAllServices = true)
+ {
+ $this->forAllServices = (bool) $forAllServices;
+ return $this;
+ }
+
+ /**
+ * Get whether to schedule a downtime for all services associated with a particular host
+ *
+ * @return bool
+ */
+ public function getForAllServices()
+ {
+ return $this->forAllServices;
+ }
+
+ /**
+ * Get whether to send the all_services API parameter
+ *
+ * @return bool
+ */
+ public function isForAllServicesNative()
+ {
+ return $this->forAllServicesNative;
+ }
+
+ /**
+ * Get whether to send the all_services API parameter
+ *
+ * @param bool $forAllServicesNative
+ *
+ * @return $this
+ */
+ public function setForAllServicesNative($forAllServicesNative = true)
+ {
+ $this->forAllServicesNative = (bool) $forAllServicesNative;
+
+ return $this;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceCheckCommand.php b/modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceCheckCommand.php
new file mode 100644
index 0000000..8880984
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceCheckCommand.php
@@ -0,0 +1,92 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Schedule a service check
+ */
+class ScheduleServiceCheckCommand extends ObjectCommand
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected $allowedObjects = array(
+ self::TYPE_SERVICE
+ );
+
+ /**
+ * Time when the next check of a host or service is to be scheduled
+ *
+ * If active checks are disabled on a host- or service-specific or program-wide basis or the host or service is
+ * already scheduled to be checked at an earlier time, etc. The check may not actually be scheduled at the time
+ * specified. This behaviour can be overridden by setting `ScheduledCheck::$forced' to true.
+ *
+ * @var int Unix timestamp
+ */
+ protected $checkTime;
+
+ /**
+ * Whether the check is forced
+ *
+ * Forced checks are performed regardless of what time it is (e.g. time period restrictions are ignored) and whether
+ * or not active checks are enabled on a host- or service-specific or program-wide basis.
+ *
+ * @var bool
+ */
+ protected $forced = false;
+
+ /**
+ * Set the time when the next check of a host or service is to be scheduled
+ *
+ * @param int $checkTime Unix timestamp
+ *
+ * @return $this
+ */
+ public function setCheckTime($checkTime)
+ {
+ $this->checkTime = (int) $checkTime;
+ return $this;
+ }
+
+ /**
+ * Get the time when the next check of a host or service is to be scheduled
+ *
+ * @return int Unix timestamp
+ */
+ public function getCheckTime()
+ {
+ return $this->checkTime;
+ }
+
+ /**
+ * Set whether the check is forced
+ *
+ * @param bool $forced
+ *
+ * @return $this
+ */
+ public function setForced($forced = true)
+ {
+ $this->forced = (bool) $forced;
+ return $this;
+ }
+
+ /**
+ * Get whether the check is forced
+ *
+ * @return bool
+ */
+ public function getForced()
+ {
+ return $this->forced;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'ScheduleCheck';
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceDowntimeCommand.php b/modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceDowntimeCommand.php
new file mode 100644
index 0000000..a023ab5
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceDowntimeCommand.php
@@ -0,0 +1,190 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Schedule a service downtime
+ */
+class ScheduleServiceDowntimeCommand extends AddCommentCommand
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Module\Monitoring\Command\Object\ObjectCommand::$allowedObjects For the property documentation.
+ */
+ protected $allowedObjects = array(
+ self::TYPE_SERVICE
+ );
+
+ /**
+ * Downtime starts at the exact time specified
+ *
+ * If `Downtime::$fixed' is set to false, the time between `Downtime::$start' and `Downtime::$end' at which a
+ * host or service transitions to a problem state determines the time at which the downtime actually starts.
+ * The downtime will then last for `Downtime::$duration' seconds.
+ *
+ * @var int Unix timestamp
+ */
+ protected $start;
+
+ /**
+ * Downtime ends at the exact time specified
+ *
+ * If `Downtime::$fixed' is set to false, the time between `Downtime::$start' and `Downtime::$end' at which a
+ * host or service transitions to a problem state determines the time at which the downtime actually starts.
+ * The downtime will then last for `Downtime::$duration' seconds.
+ *
+ * @var int Unix timestamp
+ */
+ protected $end;
+
+ /**
+ * Whether it's a fixed or flexible downtime
+ *
+ * @var bool
+ */
+ protected $fixed = true;
+
+ /**
+ * ID of the downtime which triggers this downtime
+ *
+ * The start of this downtime is triggered by the start of the other scheduled host or service downtime.
+ *
+ * @var int|null
+ */
+ protected $triggerId;
+
+ /**
+ * The duration in seconds the downtime must last if it's a flexible downtime
+ *
+ * If `Downtime::$fixed' is set to false, the downtime will last for the duration in seconds specified, even
+ * if the host or service recovers before the downtime expires.
+ *
+ * @var int|null
+ */
+ protected $duration;
+
+ /**
+ * Set the time when the downtime should start
+ *
+ * @param int $start Unix timestamp
+ *
+ * @return $this
+ */
+ public function setStart($start)
+ {
+ $this->start = (int) $start;
+ return $this;
+ }
+
+ /**
+ * Get the time when the downtime should start
+ *
+ * @return int Unix timestamp
+ */
+ public function getStart()
+ {
+ return $this->start;
+ }
+
+ /**
+ * Set the time when the downtime should end
+ *
+ * @param int $end Unix timestamp
+ *
+ * @return $this
+ */
+ public function setEnd($end)
+ {
+ $this->end = (int) $end;
+ return $this;
+ }
+
+ /**
+ * Get the time when the downtime should end
+ *
+ * @return int Unix timestamp
+ */
+ public function getEnd()
+ {
+ return $this->end;
+ }
+
+ /**
+ * Set whether it's a fixed or flexible downtime
+ *
+ * @param boolean $fixed
+ *
+ * @return $this
+ */
+ public function setFixed($fixed = true)
+ {
+ $this->fixed = (bool) $fixed;
+ return $this;
+ }
+
+ /**
+ * Is the downtime fixed?
+ *
+ * @return boolean
+ */
+ public function getFixed()
+ {
+ return $this->fixed;
+ }
+
+ /**
+ * Set the ID of the downtime which triggers this downtime
+ *
+ * @param int $triggerId
+ *
+ * @return $this
+ */
+ public function setTriggerId($triggerId)
+ {
+ $this->triggerId = (int) $triggerId;
+ return $this;
+ }
+
+ /**
+ * Get the ID of the downtime which triggers this downtime
+ *
+ * @return int|null
+ */
+ public function getTriggerId()
+ {
+ return $this->triggerId;
+ }
+
+ /**
+ * Set the duration in seconds the downtime must last if it's a flexible downtime
+ *
+ * @param int $duration
+ *
+ * @return $this
+ */
+ public function setDuration($duration)
+ {
+ $this->duration = (int) $duration;
+ return $this;
+ }
+
+ /**
+ * Get the duration in seconds the downtime must last if it's a flexible downtime
+ *
+ * @return int|null
+ */
+ public function getDuration()
+ {
+ return $this->duration;
+ }
+
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Module\Monitoring\Command\Object\IcingaCommand::getName() For the method documentation.
+ */
+ public function getName()
+ {
+ return 'ScheduleDowntime';
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/SendCustomNotificationCommand.php b/modules/monitoring/library/Monitoring/Command/Object/SendCustomNotificationCommand.php
new file mode 100644
index 0000000..ac8889c
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/SendCustomNotificationCommand.php
@@ -0,0 +1,82 @@
+<?php
+/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Send custom notifications for a host or service
+ */
+class SendCustomNotificationCommand extends WithCommentCommand
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected $allowedObjects = array(
+ self::TYPE_HOST,
+ self::TYPE_SERVICE
+ );
+
+ /**
+ * Whether the notification is forced
+ *
+ * Forced notifications are sent out regardless of time restrictions and whether or not notifications are enabled.
+ *
+ * @var bool
+ */
+ protected $forced;
+
+ /**
+ * Whether to broadcast the notification
+ *
+ * Broadcast notifications are sent out to all normal and escalated contacts.
+ *
+ * @var bool
+ */
+ protected $broadcast;
+
+ /**
+ * Get whether to force the notification
+ *
+ * @return bool
+ */
+ public function getForced()
+ {
+ return $this->forced;
+ }
+
+ /**
+ * Set whether to force the notification
+ *
+ * @param bool $forced
+ *
+ * @return $this
+ */
+ public function setForced($forced = true)
+ {
+ $this->forced = $forced;
+ return $this;
+ }
+
+ /**
+ * Get whether to broadcast the notification
+ *
+ * @return bool
+ */
+ public function getBroadcast()
+ {
+ return $this->broadcast;
+ }
+
+ /**
+ * Set whether to broadcast the notification
+ *
+ * @param bool $broadcast
+ *
+ * @return $this
+ */
+ public function setBroadcast($broadcast = true)
+ {
+ $this->broadcast = $broadcast;
+ return $this;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/ToggleObjectFeatureCommand.php b/modules/monitoring/library/Monitoring/Command/Object/ToggleObjectFeatureCommand.php
new file mode 100644
index 0000000..e3ba8a2
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/ToggleObjectFeatureCommand.php
@@ -0,0 +1,113 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Enable or disable a feature of an Icinga object, i.e. host or service
+ */
+class ToggleObjectFeatureCommand extends ObjectCommand
+{
+ /**
+ * (non-PHPDoc)
+ * @see \Icinga\Module\Monitoring\Command\Object\ObjectCommand::$allowedObjects For the property documentation.
+ */
+ protected $allowedObjects = array(
+ self::TYPE_HOST,
+ self::TYPE_SERVICE
+ );
+
+ /**
+ * Feature for enabling or disabling active checks of a host or service
+ */
+ const FEATURE_ACTIVE_CHECKS = 'active_checks_enabled';
+
+ /**
+ * Feature for enabling or disabling passive checks of a host or service
+ */
+ const FEATURE_PASSIVE_CHECKS = 'passive_checks_enabled';
+
+ /**
+ * Feature for enabling or disabling processing of host or service checks via the OCHP command for a host or service
+ */
+ const FEATURE_OBSESSING = 'obsessing';
+
+ /**
+ * Feature for enabling or disabling notifications for a host or service
+ *
+ * Notifications will be sent out only if notifications are enabled on a program-wide basis as well.
+ */
+ const FEATURE_NOTIFICATIONS = 'notifications_enabled';
+
+ /**
+ * Feature for enabling or disabling event handler for a host or service
+ */
+ const FEATURE_EVENT_HANDLER = 'event_handler_enabled';
+
+ /**
+ * Feature for enabling or disabling flap detection for a host or service.
+ *
+ * In order to enable flap detection flap detection must be enabled on a program-wide basis as well.
+ */
+ const FEATURE_FLAP_DETECTION = 'flap_detection_enabled';
+
+ /**
+ * Feature that is to be enabled or disabled
+ *
+ * @var string
+ */
+ protected $feature;
+
+ /**
+ * Whether the feature should be enabled or disabled
+ *
+ * @var bool
+ */
+ protected $enabled;
+
+ /**
+ * Set the feature that is to be enabled or disabled
+ *
+ * @param string $feature
+ *
+ * @return $this
+ */
+ public function setFeature($feature)
+ {
+ $this->feature = (string) $feature;
+ return $this;
+ }
+
+ /**
+ * Get the feature that is to be enabled or disabled
+ *
+ * @return string
+ */
+ public function getFeature()
+ {
+ return $this->feature;
+ }
+
+ /**
+ * Set whether the feature should be enabled or disabled
+ *
+ * @param bool $enabled
+ *
+ * @return $this
+ */
+ public function setEnabled($enabled = true)
+ {
+ $this->enabled = (bool) $enabled;
+ return $this;
+ }
+
+ /**
+ * Get whether the feature should be enabled or disabled
+ *
+ * @return bool
+ */
+ public function getEnabled()
+ {
+ return $this->enabled;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Object/WithCommentCommand.php b/modules/monitoring/library/Monitoring/Command/Object/WithCommentCommand.php
new file mode 100644
index 0000000..aa2e439
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Object/WithCommentCommand.php
@@ -0,0 +1,42 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Object;
+
+/**
+ * Base class for commands adding comments
+ */
+abstract class WithCommentCommand extends ObjectCommand
+{
+ use CommandAuthor;
+
+ /**
+ * Comment
+ *
+ * @var string
+ */
+ protected $comment;
+
+ /**
+ * Set the comment
+ *
+ * @param string $comment
+ *
+ * @return $this
+ */
+ public function setComment($comment)
+ {
+ $this->comment = (string) $comment;
+ return $this;
+ }
+
+ /**
+ * Get the comment
+ *
+ * @return string
+ */
+ public function getComment()
+ {
+ return $this->comment;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Renderer/IcingaApiCommandRenderer.php b/modules/monitoring/library/Monitoring/Command/Renderer/IcingaApiCommandRenderer.php
new file mode 100644
index 0000000..8370314
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Renderer/IcingaApiCommandRenderer.php
@@ -0,0 +1,324 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Renderer;
+
+use Icinga\Module\Monitoring\Backend\MonitoringBackend;
+use Icinga\Module\Monitoring\Command\IcingaApiCommand;
+use Icinga\Module\Monitoring\Command\Instance\ToggleInstanceFeatureCommand;
+use Icinga\Module\Monitoring\Command\Object\AcknowledgeProblemCommand;
+use Icinga\Module\Monitoring\Command\Object\AddCommentCommand;
+use Icinga\Module\Monitoring\Command\Object\ApiScheduleHostDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
+use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\ProcessCheckResultCommand;
+use Icinga\Module\Monitoring\Command\Object\PropagateHostDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\RemoveAcknowledgementCommand;
+use Icinga\Module\Monitoring\Command\Object\ScheduleHostDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceCheckCommand;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\SendCustomNotificationCommand;
+use Icinga\Module\Monitoring\Command\Object\ToggleObjectFeatureCommand;
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+use Icinga\Module\Monitoring\Object\MonitoredObject;
+use InvalidArgumentException;
+
+/**
+ * Icinga command renderer for the Icinga command file
+ */
+class IcingaApiCommandRenderer implements IcingaCommandRendererInterface
+{
+ /**
+ * Name of the Icinga application object
+ *
+ * @var string
+ */
+ protected $app = 'app';
+
+ /**
+ * Get the name of the Icinga application object
+ *
+ * @return string
+ */
+ public function getApp()
+ {
+ return $this->app;
+ }
+
+ /**
+ * Set the name of the Icinga application object
+ *
+ * @param string $app
+ *
+ * @return $this
+ */
+ public function setApp($app)
+ {
+ $this->app = $app;
+
+ return $this;
+ }
+
+ /**
+ * Apply filter to query data
+ *
+ * @param array $data
+ * @param MonitoredObject $object
+ *
+ * @return array
+ */
+ protected function applyFilter(array &$data, MonitoredObject $object)
+ {
+ if ($object->getType() === $object::TYPE_HOST) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ $data['host'] = $object->getName();
+ } else {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $data['service'] = sprintf('%s!%s', $object->getHost()->getName(), $object->getName());
+ }
+ }
+
+ /**
+ * Render a command
+ *
+ * @param IcingaCommand $command
+ *
+ * @return IcingaApiCommand
+ */
+ public function render(IcingaCommand $command)
+ {
+ $renderMethod = 'render' . $command->getName();
+ if (! method_exists($this, $renderMethod)) {
+ die($renderMethod);
+ }
+ return $this->$renderMethod($command);
+ }
+
+ public function renderAddComment(AddCommentCommand $command)
+ {
+ $endpoint = 'actions/add-comment';
+ $data = array(
+ 'author' => $command->getAuthor(),
+ 'comment' => $command->getComment()
+ );
+
+ if ($command->getExpireTime() !== null) {
+ $data['expiry'] = $command->getExpireTime();
+ }
+
+ $this->applyFilter($data, $command->getObject());
+ return IcingaApiCommand::create($endpoint, $data);
+ }
+
+ public function renderSendCustomNotification(SendCustomNotificationCommand $command)
+ {
+ $endpoint = 'actions/send-custom-notification';
+ $data = array(
+ 'author' => $command->getAuthor(),
+ 'comment' => $command->getComment(),
+ 'force' => $command->getForced()
+ );
+ $this->applyFilter($data, $command->getObject());
+ return IcingaApiCommand::create($endpoint, $data);
+ }
+
+ public function renderProcessCheckResult(ProcessCheckResultCommand $command)
+ {
+ $endpoint = 'actions/process-check-result';
+ $data = array(
+ 'exit_status' => $command->getStatus(),
+ 'plugin_output' => $command->getOutput(),
+ 'performance_data' => $command->getPerformanceData()
+ );
+ $this->applyFilter($data, $command->getObject());
+ return IcingaApiCommand::create($endpoint, $data);
+ }
+
+ public function renderScheduleCheck(ScheduleServiceCheckCommand $command)
+ {
+ $endpoint = 'actions/reschedule-check';
+ $data = array(
+ 'next_check' => $command->getCheckTime(),
+ 'force' => $command->getForced()
+ );
+ $this->applyFilter($data, $command->getObject());
+ return IcingaApiCommand::create($endpoint, $data);
+ }
+
+ public function renderScheduleDowntime(ScheduleServiceDowntimeCommand $command)
+ {
+ $endpoint = 'actions/schedule-downtime';
+ $data = array(
+ 'author' => $command->getAuthor(),
+ 'comment' => $command->getComment(),
+ 'start_time' => $command->getStart(),
+ 'end_time' => $command->getEnd(),
+ 'duration' => $command->getDuration(),
+ 'fixed' => $command->getFixed(),
+ 'trigger_name' => $command->getTriggerId()
+ );
+ $commandData = $data;
+
+ if ($command instanceof PropagateHostDowntimeCommand) {
+ $commandData['child_options'] = $command->getTriggered() ? 1 : 2;
+ } elseif ($command instanceof ApiScheduleHostDowntimeCommand) {
+ // We assume that it has previously been verified that the Icinga version is
+ // equal to or greater than 2.11.0
+ $commandData['child_options'] = $command->getChildOptions();
+ }
+
+ $allServicesCompat = false;
+ if ($command instanceof ScheduleHostDowntimeCommand) {
+ if ($command->isForAllServicesNative()) {
+ // We assume that it has previously been verified that the Icinga version is
+ // equal to or greater than 2.11.0
+ $commandData['all_services'] = $command->getForAllServices();
+ } else {
+ $allServicesCompat = $command->getForAllServices();
+ }
+ }
+
+ $this->applyFilter($commandData, $command->getObject());
+ $apiCommand = IcingaApiCommand::create($endpoint, $commandData);
+
+ if ($allServicesCompat) {
+ $commandData = $data + [
+ 'type' => 'Service',
+ 'filter' => 'host.name == host_name',
+ 'filter_vars' => [
+ 'host_name' => $command->getObject()->getName()
+ ]
+ ];
+ $apiCommand->setNext(IcingaApiCommand::create($endpoint, $commandData));
+ }
+
+ return $apiCommand;
+ }
+
+ public function renderAcknowledgeProblem(AcknowledgeProblemCommand $command)
+ {
+ $endpoint = 'actions/acknowledge-problem';
+ $data = array(
+ 'author' => $command->getAuthor(),
+ 'comment' => $command->getComment(),
+ 'sticky' => $command->getSticky(),
+ 'notify' => $command->getNotify(),
+ 'persistent' => $command->getPersistent()
+ );
+ if ($command->getExpireTime() !== null) {
+ $data['expiry'] = $command->getExpireTime();
+ }
+ $this->applyFilter($data, $command->getObject());
+ return IcingaApiCommand::create($endpoint, $data);
+ }
+
+ public function renderToggleObjectFeature(ToggleObjectFeatureCommand $command)
+ {
+ if ($command->getEnabled() === true) {
+ $enabled = true;
+ } else {
+ $enabled = false;
+ }
+ switch ($command->getFeature()) {
+ case ToggleObjectFeatureCommand::FEATURE_ACTIVE_CHECKS:
+ $attr = 'enable_active_checks';
+ break;
+ case ToggleObjectFeatureCommand::FEATURE_PASSIVE_CHECKS:
+ $attr = 'enable_passive_checks';
+ break;
+ case ToggleObjectFeatureCommand::FEATURE_NOTIFICATIONS:
+ $attr = 'enable_notifications';
+ break;
+ case ToggleObjectFeatureCommand::FEATURE_EVENT_HANDLER:
+ $attr = 'enable_event_handler';
+ break;
+ case ToggleObjectFeatureCommand::FEATURE_FLAP_DETECTION:
+ $attr = 'enable_flapping';
+ break;
+ default:
+ throw new InvalidArgumentException($command->getFeature());
+ }
+ $endpoint = 'objects/';
+ $object = $command->getObject();
+ if ($object->getType() === ToggleObjectFeatureCommand::TYPE_HOST) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ $endpoint .= 'hosts';
+ } else {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $endpoint .= 'services';
+ }
+ $data = array(
+ 'attrs' => array(
+ $attr => $enabled
+ )
+ );
+ $this->applyFilter($data, $object);
+ return IcingaApiCommand::create($endpoint, $data);
+ }
+
+ public function renderDeleteComment(DeleteCommentCommand $command)
+ {
+ $endpoint = 'actions/remove-comment';
+ $data = [
+ 'author' => $command->getAuthor(),
+ 'comment' => $command->getCommentName()
+ ];
+ return IcingaApiCommand::create($endpoint, $data);
+ }
+
+ public function renderDeleteDowntime(DeleteDowntimeCommand $command)
+ {
+ $endpoint = 'actions/remove-downtime';
+ $data = [
+ 'author' => $command->getAuthor(),
+ 'downtime' => $command->getDowntimeName()
+ ];
+ return IcingaApiCommand::create($endpoint, $data);
+ }
+
+ public function renderRemoveAcknowledgement(RemoveAcknowledgementCommand $command)
+ {
+ $endpoint = 'actions/remove-acknowledgement';
+ $data = ['author' => $command->getAuthor()];
+ $this->applyFilter($data, $command->getObject());
+ return IcingaApiCommand::create($endpoint, $data);
+ }
+
+ public function renderToggleInstanceFeature(ToggleInstanceFeatureCommand $command)
+ {
+ $endpoint = 'objects/icingaapplications/' . $this->getApp();
+ if ($command->getEnabled() === true) {
+ $enabled = true;
+ } else {
+ $enabled = false;
+ }
+ switch ($command->getFeature()) {
+ case ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS:
+ $attr = 'enable_host_checks';
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS:
+ $attr = 'enable_service_checks';
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS:
+ $attr = 'enable_event_handlers';
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION:
+ $attr = 'enable_flapping';
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_NOTIFICATIONS:
+ $attr = 'enable_notifications';
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA:
+ $attr = 'enable_perfdata';
+ break;
+ default:
+ throw new InvalidArgumentException($command->getFeature());
+ }
+ $data = array(
+ 'attrs' => array(
+ $attr => $enabled
+ )
+ );
+ return IcingaApiCommand::create($endpoint, $data);
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Renderer/IcingaCommandFileCommandRenderer.php b/modules/monitoring/library/Monitoring/Command/Renderer/IcingaCommandFileCommandRenderer.php
new file mode 100644
index 0000000..97d1314
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Renderer/IcingaCommandFileCommandRenderer.php
@@ -0,0 +1,478 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Renderer;
+
+use Icinga\Module\Monitoring\Command\Instance\DisableNotificationsExpireCommand;
+use Icinga\Module\Monitoring\Command\Instance\ToggleInstanceFeatureCommand;
+use Icinga\Module\Monitoring\Command\Object\AcknowledgeProblemCommand;
+use Icinga\Module\Monitoring\Command\Object\AddCommentCommand;
+use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
+use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\ProcessCheckResultCommand;
+use Icinga\Module\Monitoring\Command\Object\PropagateHostDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\RemoveAcknowledgementCommand;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceCheckCommand;
+use Icinga\Module\Monitoring\Command\Object\ScheduleServiceDowntimeCommand;
+use Icinga\Module\Monitoring\Command\Object\SendCustomNotificationCommand;
+use Icinga\Module\Monitoring\Command\Object\ToggleObjectFeatureCommand;
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+use InvalidArgumentException;
+
+/**
+ * Icinga command renderer for the Icinga command file
+ */
+class IcingaCommandFileCommandRenderer implements IcingaCommandRendererInterface
+{
+ /**
+ * Escape a command string
+ *
+ * @param string $commandString
+ *
+ * @return string
+ */
+ protected function escape($commandString)
+ {
+ return str_replace(array("\r", "\n"), array('\r', '\n'), $commandString);
+ }
+
+ /**
+ * Render a command
+ *
+ * @param IcingaCommand $command
+ * @param int|null $now
+ *
+ * @return string
+ */
+ public function render(IcingaCommand $command, $now = null)
+ {
+ $renderMethod = 'render' . $command->getName();
+ if (! method_exists($this, $renderMethod)) {
+ die($renderMethod);
+ }
+ if ($now === null) {
+ $now = time();
+ }
+ return sprintf('[%u] %s', $now, $this->escape($this->$renderMethod($command)));
+ }
+
+ public function renderAddComment(AddCommentCommand $command)
+ {
+ $object = $command->getObject();
+ if ($command->getObject()->getType() === $command::TYPE_HOST) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ $commandString = sprintf(
+ 'ADD_HOST_COMMENT;%s',
+ $object->getName()
+ );
+ } else {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $commandString = sprintf(
+ 'ADD_SVC_COMMENT;%s;%s',
+ $object->getHost()->getName(),
+ $object->getName()
+ );
+ }
+ return sprintf(
+ '%s;%u;%s;%s',
+ $commandString,
+ $command->getPersistent(),
+ $command->getAuthor(),
+ $command->getComment()
+ );
+ }
+
+ public function renderSendCustomNotification(SendCustomNotificationCommand $command)
+ {
+ $object = $command->getObject();
+ if ($command->getObject()->getType() === $command::TYPE_HOST) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ $commandString = sprintf(
+ 'SEND_CUSTOM_HOST_NOTIFICATION;%s',
+ $object->getName()
+ );
+ } else {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $commandString = sprintf(
+ 'SEND_CUSTOM_SVC_NOTIFICATION;%s;%s',
+ $object->getHost()->getName(),
+ $object->getName()
+ );
+ }
+ $options = 0; // 0 for no options
+ if ($command->getBroadcast() === true) {
+ $options |= 1;
+ }
+ if ($command->getForced() === true) {
+ $options |= 2;
+ }
+ return sprintf(
+ '%s;%u;%s;%s',
+ $commandString,
+ $options,
+ $command->getAuthor(),
+ $command->getComment()
+ );
+ }
+
+ public function renderProcessCheckResult(ProcessCheckResultCommand $command)
+ {
+ $object = $command->getObject();
+ if ($command->getObject()->getType() === $command::TYPE_HOST) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ $commandString = sprintf(
+ 'PROCESS_HOST_CHECK_RESULT;%s',
+ $object->getName()
+ );
+ } else {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $commandString = sprintf(
+ 'PROCESS_SERVICE_CHECK_RESULT;%s;%s',
+ $object->getHost()->getName(),
+ $object->getName()
+ );
+ }
+ $output = $command->getOutput();
+ if ($command->getPerformanceData() !== null) {
+ $output .= '|' . $command->getPerformanceData();
+ }
+ return sprintf(
+ '%s;%u;%s',
+ $commandString,
+ $command->getStatus(),
+ $output
+ );
+ }
+
+ public function renderScheduleCheck(ScheduleServiceCheckCommand $command)
+ {
+ $object = $command->getObject();
+ if ($command->getObject()->getType() === $command::TYPE_HOST) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ /** @var \Icinga\Module\Monitoring\Command\Object\ScheduleHostCheckCommand $command */
+ if ($command->getOfAllServices() === true) {
+ if ($command->getForced() === true) {
+ $commandName = 'SCHEDULE_FORCED_HOST_SVC_CHECKS';
+ } else {
+ $commandName = 'SCHEDULE_HOST_SVC_CHECKS';
+ }
+ } else {
+ if ($command->getForced() === true) {
+ $commandName = 'SCHEDULE_FORCED_HOST_CHECK';
+ } else {
+ $commandName = 'SCHEDULE_HOST_CHECK';
+ }
+ }
+ $commandString = sprintf(
+ '%s;%s',
+ $commandName,
+ $object->getName()
+ );
+ } else {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $commandString = sprintf(
+ '%s;%s;%s',
+ $command->getForced() === true ? 'SCHEDULE_FORCED_SVC_CHECK' : 'SCHEDULE_SVC_CHECK',
+ $object->getHost()->getName(),
+ $object->getName()
+ );
+ }
+ return sprintf(
+ '%s;%u',
+ $commandString,
+ $command->getCheckTime()
+ );
+ }
+
+ public function renderScheduleDowntime(ScheduleServiceDowntimeCommand $command)
+ {
+ $object = $command->getObject();
+ if ($command->getObject()->getType() === $command::TYPE_HOST) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ /** @var \Icinga\Module\Monitoring\Command\Object\ScheduleHostDowntimeCommand $command */
+ if ($command instanceof PropagateHostDowntimeCommand) {
+ /** @var \Icinga\Module\Monitoring\Command\Object\PropagateHostDowntimeCommand $command */
+ $commandName = $command->getTriggered() === true ? 'SCHEDULE_AND_PROPAGATE_TRIGGERED_HOST_DOWNTIME'
+ : 'SCHEDULE_AND_PROPAGATE_HOST_DOWNTIME';
+ } elseif ($command->getForAllServices() === true) {
+ $commandName = 'SCHEDULE_HOST_SVC_DOWNTIME';
+ } else {
+ $commandName = 'SCHEDULE_HOST_DOWNTIME';
+ }
+ $commandString = sprintf(
+ '%s;%s',
+ $commandName,
+ $object->getName()
+ );
+ } else {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $commandString = sprintf(
+ '%s;%s;%s',
+ 'SCHEDULE_SVC_DOWNTIME',
+ $object->getHost()->getName(),
+ $object->getName()
+ );
+ }
+ return sprintf(
+ '%s;%u;%u;%u;%u;%u;%s;%s',
+ $commandString,
+ $command->getStart(),
+ $command->getEnd(),
+ $command->getFixed(),
+ $command->getTriggerId(),
+ $command->getDuration(),
+ $command->getAuthor(),
+ $command->getComment()
+ );
+ }
+
+ public function renderAcknowledgeProblem(AcknowledgeProblemCommand $command)
+ {
+ $object = $command->getObject();
+ if ($command->getObject()->getType() === $command::TYPE_HOST) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ $commandString = sprintf(
+ '%s;%s',
+ $command->getExpireTime() !== null ? 'ACKNOWLEDGE_HOST_PROBLEM_EXPIRE' : 'ACKNOWLEDGE_HOST_PROBLEM',
+ $object->getName()
+ );
+ } else {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $commandString = sprintf(
+ '%s;%s;%s',
+ $command->getExpireTime() !== null ? 'ACKNOWLEDGE_SVC_PROBLEM_EXPIRE' : 'ACKNOWLEDGE_SVC_PROBLEM',
+ $object->getHost()->getName(),
+ $object->getName()
+ );
+ }
+ $commandString = sprintf(
+ '%s;%u;%u;%u',
+ $commandString,
+ $command->getSticky() ? 2 : 0,
+ $command->getNotify(),
+ $command->getPersistent()
+ );
+ if ($command->getExpireTime() !== null) {
+ $commandString = sprintf(
+ '%s;%u',
+ $commandString,
+ $command->getExpireTime()
+ );
+ }
+ return sprintf(
+ '%s;%s;%s',
+ $commandString,
+ $command->getAuthor(),
+ $command->getComment()
+ );
+ }
+
+ public function renderToggleObjectFeature(ToggleObjectFeatureCommand $command)
+ {
+ if ($command->getEnabled() === true) {
+ $commandPrefix = 'ENABLE';
+ } else {
+ $commandPrefix = 'DISABLE';
+ }
+ switch ($command->getFeature()) {
+ case ToggleObjectFeatureCommand::FEATURE_ACTIVE_CHECKS:
+ $commandFormat = sprintf('%s_%%s_CHECK', $commandPrefix);
+ break;
+ case ToggleObjectFeatureCommand::FEATURE_PASSIVE_CHECKS:
+ $commandFormat = sprintf('%s_PASSIVE_%%s_CHECKS', $commandPrefix);
+ break;
+ case ToggleObjectFeatureCommand::FEATURE_OBSESSING:
+ if ($command->getEnabled() === true) {
+ $commandPrefix = 'START';
+ } else {
+ $commandPrefix = 'STOP';
+ }
+ $commandFormat = sprintf('%s_OBSESSING_OVER_%%s', $commandPrefix);
+ break;
+ case ToggleObjectFeatureCommand::FEATURE_NOTIFICATIONS:
+ $commandFormat = sprintf('%s_%%s_NOTIFICATIONS', $commandPrefix);
+ break;
+ case ToggleObjectFeatureCommand::FEATURE_EVENT_HANDLER:
+ $commandFormat = sprintf('%s_%%s_EVENT_HANDLER', $commandPrefix);
+ break;
+ case ToggleObjectFeatureCommand::FEATURE_FLAP_DETECTION:
+ $commandFormat = sprintf('%s_%%s_FLAP_DETECTION', $commandPrefix);
+ break;
+ default:
+ throw new InvalidArgumentException($command->getFeature());
+ }
+ $object = $command->getObject();
+ if ($object->getType() === ToggleObjectFeatureCommand::TYPE_HOST) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ $commandString = sprintf(
+ $commandFormat . ';%s',
+ 'HOST',
+ $object->getName()
+ );
+ } else {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $commandString = sprintf(
+ $commandFormat . ';%s;%s',
+ 'SVC',
+ $object->getHost()->getName(),
+ $object->getName()
+ );
+ }
+ return $commandString;
+ }
+
+ public function renderDeleteComment(DeleteCommentCommand $command)
+ {
+ return sprintf(
+ '%s;%u',
+ $command->getIsService() ? 'DEL_SVC_COMMENT' : 'DEL_HOST_COMMENT',
+ $command->getCommentId()
+ );
+ }
+
+ public function renderDeleteDowntime(DeleteDowntimeCommand $command)
+ {
+ return sprintf(
+ '%s;%u',
+ $command->getIsService() ? 'DEL_SVC_DOWNTIME' : 'DEL_HOST_DOWNTIME',
+ $command->getDowntimeId()
+ );
+ }
+
+ public function renderRemoveAcknowledgement(RemoveAcknowledgementCommand $command)
+ {
+ $object = $command->getObject();
+ if ($command->getObject()->getType() === $command::TYPE_HOST) {
+ /** @var \Icinga\Module\Monitoring\Object\Host $object */
+ $commandString = sprintf(
+ '%s;%s',
+ 'REMOVE_HOST_ACKNOWLEDGEMENT',
+ $object->getName()
+ );
+ } else {
+ /** @var \Icinga\Module\Monitoring\Object\Service $object */
+ $commandString = sprintf(
+ '%s;%s;%s',
+ 'REMOVE_SVC_ACKNOWLEDGEMENT',
+ $object->getHost()->getName(),
+ $object->getName()
+ );
+ }
+ return $commandString;
+ }
+
+ public function renderDisableNotificationsExpire(DisableNotificationsExpireCommand $command)
+ {
+ return sprintf(
+ '%s;%u;%u',
+ 'DISABLE_NOTIFICATIONS_EXPIRE_TIME',
+ time(),
+ $command->getExpireTime()
+ );
+ }
+
+ public function renderToggleInstanceFeature(ToggleInstanceFeatureCommand $command)
+ {
+ switch ($command->getFeature()) {
+ case ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS:
+ case ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS:
+ case ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING:
+ case ToggleInstanceFeatureCommand::FEATURE_SERVICE_OBSESSING:
+ case ToggleInstanceFeatureCommand::FEATURE_PASSIVE_HOST_CHECKS:
+ case ToggleInstanceFeatureCommand::FEATURE_PASSIVE_SERVICE_CHECKS:
+ if ($command->getEnabled() === true) {
+ $commandPrefix = 'START';
+ } else {
+ $commandPrefix = 'STOP';
+ }
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS:
+ case ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION:
+ case ToggleInstanceFeatureCommand::FEATURE_NOTIFICATIONS:
+ case ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA:
+ if ($command->getEnabled() === true) {
+ $commandPrefix = 'ENABLE';
+ } else {
+ $commandPrefix = 'DISABLE';
+ }
+ break;
+ default:
+ throw new InvalidArgumentException($command->getFeature());
+ }
+ switch ($command->getFeature()) {
+ case ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS:
+ $commandString = sprintf(
+ '%s_%s',
+ $commandPrefix,
+ 'EXECUTING_HOST_CHECKS'
+ );
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS:
+ $commandString = sprintf(
+ '%s_%s',
+ $commandPrefix,
+ 'EXECUTING_SVC_CHECKS'
+ );
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS:
+ $commandString = sprintf(
+ '%s_%s',
+ $commandPrefix,
+ 'EVENT_HANDLERS'
+ );
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION:
+ $commandString = sprintf(
+ '%s_%s',
+ $commandPrefix,
+ 'FLAP_DETECTION'
+ );
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_NOTIFICATIONS:
+ $commandString = sprintf(
+ '%s_%s',
+ $commandPrefix,
+ 'NOTIFICATIONS'
+ );
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING:
+ $commandString = sprintf(
+ '%s_%s',
+ $commandPrefix,
+ 'OBSESSING_OVER_HOST_CHECKS'
+ );
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_SERVICE_OBSESSING:
+ $commandString = sprintf(
+ '%s_%s',
+ $commandPrefix,
+ 'OBSESSING_OVER_SVC_CHECKS'
+ );
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_PASSIVE_HOST_CHECKS:
+ $commandString = sprintf(
+ '%s_%s',
+ $commandPrefix,
+ 'ACCEPTING_PASSIVE_HOST_CHECKS'
+ );
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_PASSIVE_SERVICE_CHECKS:
+ $commandString = sprintf(
+ '%s_%s',
+ $commandPrefix,
+ 'ACCEPTING_PASSIVE_SVC_CHECKS'
+ );
+ break;
+ case ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA:
+ $commandString = sprintf(
+ '%s_%s',
+ $commandPrefix,
+ 'PERFORMANCE_DATA'
+ );
+ break;
+ default:
+ throw new InvalidArgumentException($command->getFeature());
+ }
+ return $commandString;
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Renderer/IcingaCommandRendererInterface.php b/modules/monitoring/library/Monitoring/Command/Renderer/IcingaCommandRendererInterface.php
new file mode 100644
index 0000000..e3ef6ba
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Renderer/IcingaCommandRendererInterface.php
@@ -0,0 +1,11 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Renderer;
+
+/**
+ * Interface for Icinga command renderer
+ */
+interface IcingaCommandRendererInterface
+{
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Transport/ApiCommandTransport.php b/modules/monitoring/library/Monitoring/Command/Transport/ApiCommandTransport.php
new file mode 100644
index 0000000..06e6afd
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Transport/ApiCommandTransport.php
@@ -0,0 +1,291 @@
+<?php
+/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Transport;
+
+use Icinga\Application\Hook\AuditHook;
+use Icinga\Application\Logger;
+use Icinga\Exception\Json\JsonDecodeException;
+use Icinga\Module\Monitoring\Command\IcingaApiCommand;
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+use Icinga\Module\Monitoring\Command\Renderer\IcingaApiCommandRenderer;
+use Icinga\Module\Monitoring\Exception\CommandTransportException;
+use Icinga\Module\Monitoring\Exception\CurlException;
+use Icinga\Module\Monitoring\Web\Rest\RestRequest;
+use Icinga\Util\Json;
+
+/**
+ * Command transport over Icinga 2's REST API
+ */
+class ApiCommandTransport implements CommandTransportInterface
+{
+ /**
+ * Transport identifier
+ */
+ const TRANSPORT = 'api';
+
+ /**
+ * API host
+ *
+ * @var string
+ */
+ protected $host;
+
+ /**
+ * API password
+ *
+ * @var string
+ */
+ protected $password;
+
+ /**
+ * API port
+ *
+ * @var int
+ */
+ protected $port = 5665;
+
+ /**
+ * Command renderer
+ *
+ * @var IcingaApiCommandRenderer
+ */
+ protected $renderer;
+
+ /**
+ * API username
+ *
+ * @var string
+ */
+ protected $username;
+
+ /**
+ * Create a new API command transport
+ */
+ public function __construct()
+ {
+ $this->renderer = new IcingaApiCommandRenderer();
+ }
+
+ /**
+ * Set the name of the Icinga application object
+ *
+ * @param string $app
+ *
+ * @return $this
+ */
+ public function setApp($app)
+ {
+ $this->renderer->setApp($app);
+
+ return $this;
+ }
+
+ /**
+ * Get the API host
+ *
+ * @return string
+ */
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ /**
+ * Set the API host
+ *
+ * @param string $host
+ *
+ * @return $this
+ */
+ public function setHost($host)
+ {
+ $this->host = $host;
+
+ return $this;
+ }
+
+ /**
+ * Get the API password
+ *
+ * @return string
+ */
+ public function getPassword()
+ {
+ return $this->password;
+ }
+
+ /**
+ * Set the API password
+ *
+ * @param string $password
+ *
+ * @return $this
+ */
+ public function setPassword($password)
+ {
+ $this->password = $password;
+
+ return $this;
+ }
+
+ /**
+ * Get the API port
+ *
+ * @return int
+ */
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ /**
+ * Set the API port
+ *
+ * @param int $port
+ *
+ * @return $this
+ */
+ public function setPort($port)
+ {
+ $this->port = (int) $port;
+
+ return $this;
+ }
+
+ /**
+ * Get the API username
+ *
+ * @return string
+ */
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ /**
+ * Set the API username
+ *
+ * @param string $username
+ *
+ * @return $this
+ */
+ public function setUsername($username)
+ {
+ $this->username = $username;
+
+ return $this;
+ }
+
+ /**
+ * Get URI for endpoint
+ *
+ * @param string $endpoint
+ *
+ * @return string
+ */
+ protected function getUriFor($endpoint)
+ {
+ return sprintf('https://%s:%u/v1/%s', $this->getHost(), $this->getPort(), $endpoint);
+ }
+
+ protected function sendCommand(IcingaApiCommand $command)
+ {
+ Logger::debug(
+ 'Sending Icinga command "%s" to the API "%s:%u"',
+ $command->getEndpoint(),
+ $this->getHost(),
+ $this->getPort()
+ );
+
+ $data = $command->getData();
+ $payload = Json::encode($data);
+ AuditHook::logActivity(
+ 'monitoring/command',
+ "Issued command {$command->getEndpoint()} with the following payload: $payload",
+ $data
+ );
+
+ try {
+ $response = RestRequest::post($this->getUriFor($command->getEndpoint()))
+ ->authenticateWith($this->getUsername(), $this->getPassword())
+ ->sendJson()
+ ->noStrictSsl()
+ ->setPayload($command->getData())
+ ->send();
+ } catch (JsonDecodeException $e) {
+ throw new CommandTransportException(
+ 'Got invalid JSON response from the Icinga 2 API: %s',
+ $e->getMessage()
+ );
+ }
+
+ if (isset($response['error'])) {
+ throw new CommandTransportException(
+ 'Can\'t send external Icinga command: %u %s',
+ $response['error'],
+ $response['status']
+ );
+ }
+ $result = array_pop($response['results']);
+ if (! empty($result)
+ && ($result['code'] < 200 || $result['code'] >= 300)
+ ) {
+ throw new CommandTransportException(
+ 'Can\'t send external Icinga command: %u %s',
+ $result['code'],
+ $result['status']
+ );
+ }
+ if ($command->hasNext()) {
+ $this->sendCommand($command->getNext());
+ }
+ }
+
+ /**
+ * Send the Icinga command over the Icinga 2 API
+ *
+ * @param IcingaCommand $command
+ * @param int|null $now
+ *
+ * @throws CommandTransportException
+ */
+ public function send(IcingaCommand $command, $now = null)
+ {
+ $this->sendCommand($this->renderer->render($command));
+ }
+
+ /**
+ * Try to connect to the API
+ *
+ * @throws CommandTransportException In case of failure
+ */
+ public function probe()
+ {
+ $request = RestRequest::get($this->getUriFor(null))
+ ->authenticateWith($this->getUsername(), $this->getPassword())
+ ->noStrictSsl();
+
+ try {
+ $response = $request->send();
+ } catch (CurlException $e) {
+ throw new CommandTransportException(
+ 'Couldn\'t connect to the Icinga 2 API: %s',
+ $e->getMessage()
+ );
+ } catch (JsonDecodeException $e) {
+ throw new CommandTransportException(
+ 'Got invalid JSON response from the Icinga 2 API: %s',
+ $e->getMessage()
+ );
+ }
+
+ if (isset($response['error'])) {
+ throw new CommandTransportException(
+ 'Can\'t connect to the Icinga 2 API: %u %s',
+ $response['error'],
+ $response['status']
+ );
+ }
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Transport/CommandTransport.php b/modules/monitoring/library/Monitoring/Command/Transport/CommandTransport.php
new file mode 100644
index 0000000..aa47547
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Transport/CommandTransport.php
@@ -0,0 +1,170 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Transport;
+
+use Exception;
+use Icinga\Application\Config;
+use Icinga\Application\Logger;
+use Icinga\Data\ConfigObject;
+use Icinga\Exception\ConfigurationError;
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+use Icinga\Module\Monitoring\Command\Object\ObjectCommand;
+use Icinga\Module\Monitoring\Exception\CommandTransportException;
+
+/**
+ * Command transport
+ *
+ * This class is subject to change as we do not have environments yet (#4471).
+ */
+class CommandTransport implements CommandTransportInterface
+{
+ /**
+ * Transport configuration
+ *
+ * @var Config
+ */
+ protected static $config;
+
+ /**
+ * Get transport configuration
+ *
+ * @return Config
+ *
+ * @throws ConfigurationError
+ */
+ public static function getConfig()
+ {
+ if (static::$config === null) {
+ $config = Config::module('monitoring', 'commandtransports');
+ if ($config->isEmpty()) {
+ throw new ConfigurationError(
+ mt('monitoring', 'No command transports have been configured in "%s".'),
+ $config->getConfigFile()
+ );
+ }
+
+ static::$config = $config;
+ }
+
+ return static::$config;
+ }
+
+ /**
+ * Create a transport from config
+ *
+ * @param ConfigObject $config
+ *
+ * @return LocalCommandFile|RemoteCommandFile
+ *
+ * @throws ConfigurationError
+ */
+ public static function createTransport(ConfigObject $config)
+ {
+ $config = clone $config;
+ switch (strtolower($config->transport)) {
+ case RemoteCommandFile::TRANSPORT:
+ $transport = new RemoteCommandFile();
+ break;
+ case ApiCommandTransport::TRANSPORT:
+ $transport = new ApiCommandTransport();
+ break;
+ case LocalCommandFile::TRANSPORT:
+ case '': // Casting null to string is the empty string
+ $transport = new LocalCommandFile();
+ break;
+ default:
+ throw new ConfigurationError(
+ mt(
+ 'monitoring',
+ 'Cannot create command transport "%s". Invalid transport'
+ . ' defined in "%s". Use one of "%s", "%s" or "%s".'
+ ),
+ $config->transport,
+ static::getConfig()->getConfigFile(),
+ LocalCommandFile::TRANSPORT,
+ RemoteCommandFile::TRANSPORT,
+ ApiCommandTransport::TRANSPORT
+ );
+ }
+
+ unset($config->transport);
+ foreach ($config as $key => $value) {
+ $method = 'set' . ucfirst($key);
+ if (! method_exists($transport, $method)) {
+ // Ignore settings from config that don't have a setter on the transport instead of throwing an
+ // exception here because the transport should throw an exception if it's not fully set up
+ // when being about to send a command
+ continue;
+ }
+
+ $transport->$method($value);
+ }
+
+ return $transport;
+ }
+
+ /**
+ * Send the given command over an appropriate Icinga command transport
+ *
+ * This will try one configured transport after another until the command has been successfully sent.
+ *
+ * @param IcingaCommand $command The command to send
+ * @param int|null $now Timestamp of the command or null for now
+ *
+ * @throws CommandTransportException If sending the Icinga command failed
+ */
+ public function send(IcingaCommand $command, $now = null)
+ {
+ $errors = array();
+
+ foreach (static::getConfig() as $name => $transportConfig) {
+ $transport = static::createTransport($transportConfig);
+ if ($this->transferPossible($command, $transport)) {
+ try {
+ $transport->send($command, $now);
+ } catch (Exception $e) {
+ Logger::error($e);
+ $errors[] = sprintf('%s: %s.', $name, rtrim($e->getMessage(), '.'));
+ continue; // Try the next transport
+ }
+
+ return; // The command was successfully sent
+ }
+ }
+
+ if (! empty($errors)) {
+ throw new CommandTransportException(implode("\n", $errors));
+ }
+
+ throw new CommandTransportException(
+ mt(
+ 'monitoring',
+ 'Failed to send external Icinga command. No transport has been configured'
+ . ' for this instance. Please contact your Icinga Web administrator.'
+ )
+ );
+ }
+
+ /**
+ * Return whether it is possible to send the given command using the given transport
+ *
+ * @param IcingaCommand $command
+ * @param CommandTransportInterface $transport
+ *
+ * @return bool
+ */
+ protected function transferPossible($command, $transport)
+ {
+ if (! method_exists($transport, 'getInstance') || !$command instanceof ObjectCommand) {
+ return true;
+ }
+
+ $transportInstance = $transport->getInstance();
+ if (! $transportInstance || $transportInstance === 'none') {
+ return true;
+ }
+
+ return strtolower($transportInstance) === strtolower($command->getObject()->instance_name);
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Transport/CommandTransportInterface.php b/modules/monitoring/library/Monitoring/Command/Transport/CommandTransportInterface.php
new file mode 100644
index 0000000..e9cb086
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Transport/CommandTransportInterface.php
@@ -0,0 +1,22 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Transport;
+
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+
+/**
+ * Interface for Icinga command transports
+ */
+interface CommandTransportInterface
+{
+ /**
+ * Send an Icinga command over the Icinga command transport
+ *
+ * @param IcingaCommand $command The command to send
+ * @param int|null $now Timestamp of the command or null for now
+ *
+ * @throws \Icinga\Module\Monitoring\Exception\CommandTransportException If sending the Icinga command failed
+ */
+ public function send(IcingaCommand $command, $now = null);
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Transport/LocalCommandFile.php b/modules/monitoring/library/Monitoring/Command/Transport/LocalCommandFile.php
new file mode 100644
index 0000000..891a46f
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Transport/LocalCommandFile.php
@@ -0,0 +1,168 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Transport;
+
+use Exception;
+use RuntimeException;
+use Icinga\Application\Logger;
+use Icinga\Exception\ConfigurationError;
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+use Icinga\Module\Monitoring\Command\Renderer\IcingaCommandFileCommandRenderer;
+use Icinga\Module\Monitoring\Exception\CommandTransportException;
+use Icinga\Util\File;
+
+/**
+ * A local Icinga command file
+ */
+class LocalCommandFile implements CommandTransportInterface
+{
+ /**
+ * Transport identifier
+ */
+ const TRANSPORT = 'local';
+
+ /**
+ * The name of the Icinga instance this transport will transfer commands to
+ *
+ * @var string
+ */
+ protected $instanceName;
+
+ /**
+ * Path to the icinga command file
+ *
+ * @var String
+ */
+ protected $path;
+
+ /**
+ * Mode used to open the icinga command file
+ *
+ * @var string
+ */
+ protected $openMode = 'wn';
+
+ /**
+ * Command renderer
+ *
+ * @var IcingaCommandFileCommandRenderer
+ */
+ protected $renderer;
+
+ /**
+ * Create a new local command file command transport
+ */
+ public function __construct()
+ {
+ $this->renderer = new IcingaCommandFileCommandRenderer();
+ }
+
+ /**
+ * Set the name of the Icinga instance this transport will transfer commands to
+ *
+ * @param string $name
+ *
+ * @return $this
+ */
+ public function setInstance($name)
+ {
+ $this->instanceName = $name;
+ return $this;
+ }
+
+ /**
+ * Return the name of the Icinga instance this transport will transfer commands to
+ *
+ * @return string
+ */
+ public function getInstance()
+ {
+ return $this->instanceName;
+ }
+
+ /**
+ * Set the path to the local Icinga command file
+ *
+ * @param string $path
+ *
+ * @return $this
+ */
+ public function setPath($path)
+ {
+ $this->path = (string) $path;
+ return $this;
+ }
+
+ /**
+ * Get the path to the local Icinga command file
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Set the mode used to open the icinga command file
+ *
+ * @param string $openMode
+ *
+ * @return $this
+ */
+ public function setOpenMode($openMode)
+ {
+ $this->openMode = (string) $openMode;
+ return $this;
+ }
+
+ /**
+ * Get the mode used to open the icinga command file
+ *
+ * @return string
+ */
+ public function getOpenMode()
+ {
+ return $this->openMode;
+ }
+
+ /**
+ * Write the command to the local Icinga command file
+ *
+ * @param IcingaCommand $command
+ * @param int|null $now
+ *
+ * @throws ConfigurationError
+ * @throws CommandTransportException
+ */
+ public function send(IcingaCommand $command, $now = null)
+ {
+ if (! isset($this->path)) {
+ throw new ConfigurationError(
+ 'Can\'t send external Icinga Command. Path to the local command file is missing'
+ );
+ }
+ $commandString = $this->renderer->render($command, $now);
+ Logger::debug(
+ 'Sending external Icinga command "%s" to the local command file "%s"',
+ $commandString,
+ $this->path
+ );
+ try {
+ $file = new File($this->path, $this->openMode);
+ $file->fwrite($commandString . "\n");
+ } catch (Exception $e) {
+ $message = $e->getMessage();
+ if ($e instanceof RuntimeException && ($pos = strrpos($message, ':')) !== false) {
+ // Assume RuntimeException thrown by SplFileObject in the format: __METHOD__ . "({$filename}): Message"
+ $message = substr($message, $pos + 1);
+ }
+ throw new CommandTransportException(
+ 'Can\'t send external Icinga command to the local command file "%s": %s',
+ $this->path,
+ $message
+ );
+ }
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/Command/Transport/RemoteCommandFile.php b/modules/monitoring/library/Monitoring/Command/Transport/RemoteCommandFile.php
new file mode 100644
index 0000000..5426bb9
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Command/Transport/RemoteCommandFile.php
@@ -0,0 +1,465 @@
+<?php
+/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
+
+namespace Icinga\Module\Monitoring\Command\Transport;
+
+use Icinga\Application\Logger;
+use Icinga\Data\ResourceFactory;
+use Icinga\Exception\ConfigurationError;
+use Icinga\Module\Monitoring\Command\IcingaCommand;
+use Icinga\Module\Monitoring\Command\Renderer\IcingaCommandFileCommandRenderer;
+use Icinga\Module\Monitoring\Exception\CommandTransportException;
+
+/**
+ * A remote Icinga command file
+ *
+ * Key-based SSH login must be possible for the user to log in as on the remote host
+ */
+class RemoteCommandFile implements CommandTransportInterface
+{
+ /**
+ * Transport identifier
+ */
+ const TRANSPORT = 'remote';
+
+ /**
+ * The name of the Icinga instance this transport will transfer commands to
+ *
+ * @var string
+ */
+ protected $instanceName;
+
+ /**
+ * Remote host
+ *
+ * @var string
+ */
+ protected $host;
+
+ /**
+ * Port to connect to on the remote host
+ *
+ * @var int
+ */
+ protected $port = 22;
+
+ /**
+ * User to log in as on the remote host
+ *
+ * Defaults to current PHP process' user
+ *
+ * @var string
+ */
+ protected $user;
+
+ /**
+ * Path to the private key file for the key-based authentication
+ *
+ * @var string
+ */
+ protected $privateKey;
+
+ /**
+ * Path to the Icinga command file on the remote host
+ *
+ * @var string
+ */
+ protected $path;
+
+ /**
+ * Command renderer
+ *
+ * @var IcingaCommandFileCommandRenderer
+ */
+ protected $renderer;
+
+ /**
+ * SSH subprocess pipes
+ *
+ * @var array
+ */
+ protected $sshPipes;
+
+ /**
+ * SSH subprocess
+ *
+ * @var resource
+ */
+ protected $sshProcess;
+
+ /**
+ * Create a new remote command file command transport
+ */
+ public function __construct()
+ {
+ $this->renderer = new IcingaCommandFileCommandRenderer();
+ }
+
+ /**
+ * Set the name of the Icinga instance this transport will transfer commands to
+ *
+ * @param string $name
+ *
+ * @return $this
+ */
+ public function setInstance($name)
+ {
+ $this->instanceName = $name;
+ return $this;
+ }
+
+ /**
+ * Return the name of the Icinga instance this transport will transfer commands to
+ *
+ * @return string
+ */
+ public function getInstance()
+ {
+ return $this->instanceName;
+ }
+
+ /**
+ * Set the remote host
+ *
+ * @param string $host
+ *
+ * @return $this
+ */
+ public function setHost($host)
+ {
+ $this->host = (string) $host;
+ return $this;
+ }
+
+ /**
+ * Get the remote host
+ *
+ * @return string
+ */
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ /**
+ * Set the port to connect to on the remote host
+ *
+ * @param int $port
+ *
+ * @return $this
+ */
+ public function setPort($port)
+ {
+ $this->port = (int) $port;
+ return $this;
+ }
+
+ /**
+ * Get the port to connect on the remote host
+ *
+ * @return int
+ */
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ /**
+ * Set the user to log in as on the remote host
+ *
+ * @param string $user
+ *
+ * @return $this
+ */
+ public function setUser($user)
+ {
+ $this->user = (string) $user;
+ return $this;
+ }
+
+ /**
+ * Get the user to log in as on the remote host
+ *
+ * Defaults to current PHP process' user
+ *
+ * @return string|null
+ */
+ public function getUser()
+ {
+ return $this->user;
+ }
+
+ /**
+ * Set the path to the private key file
+ *
+ * @param string $privateKey
+ *
+ * @return $this
+ */
+ public function setPrivateKey($privateKey)
+ {
+ $this->privateKey = (string) $privateKey;
+ return $this;
+ }
+
+ /**
+ * Get the path to the private key
+ *
+ * @return string
+ */
+ public function getPrivateKey()
+ {
+ return $this->privateKey;
+ }
+
+ /**
+ * Use a given resource to set the user and the key
+ *
+ * @param string
+ *
+ * @throws ConfigurationError
+ */
+ public function setResource($resource = null)
+ {
+ $config = ResourceFactory::getResourceConfig($resource);
+
+ if (! isset($config->user)) {
+ throw new ConfigurationError(
+ t("Can't send external Icinga Command. Remote user is missing")
+ );
+ }
+ if (! isset($config->private_key)) {
+ throw new ConfigurationError(
+ t("Can't send external Icinga Command. The private key for the remote user is missing")
+ );
+ }
+
+ $this->setUser($config->user);
+ $this->setPrivateKey($config->private_key);
+ }
+
+ /**
+ * Set the path to the Icinga command file on the remote host
+ *
+ * @param string $path
+ *
+ * @return $this
+ */
+ public function setPath($path)
+ {
+ $this->path = (string) $path;
+ return $this;
+ }
+
+ /**
+ * Get the path to the Icinga command file on the remote host
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Write the command to the Icinga command file on the remote host
+ *
+ * @param IcingaCommand $command
+ * @param int|null $now
+ *
+ * @throws ConfigurationError
+ * @throws CommandTransportException
+ */
+ public function send(IcingaCommand $command, $now = null)
+ {
+ if (! isset($this->path)) {
+ throw new ConfigurationError(
+ 'Can\'t send external Icinga Command. Path to the remote command file is missing'
+ );
+ }
+ if (! isset($this->host)) {
+ throw new ConfigurationError('Can\'t send external Icinga Command. Remote host is missing');
+ }
+ $commandString = $this->renderer->render($command, $now);
+ Logger::debug(
+ 'Sending external Icinga command "%s" to the remote command file "%s:%u%s"',
+ $commandString,
+ $this->host,
+ $this->port,
+ $this->path
+ );
+ return $this->sendCommandString($commandString);
+ }
+
+ /**
+ * Get the SSH command
+ *
+ * @return string
+ */
+ protected function sshCommand()
+ {
+ $cmd = sprintf(
+ 'exec ssh -o BatchMode=yes -p %u',
+ $this->port
+ );
+ // -o BatchMode=yes for disabling interactive authentication methods
+
+ if (isset($this->user)) {
+ $cmd .= ' -l ' . escapeshellarg($this->user);
+ }
+
+ if (isset($this->privateKey)) {
+ // TODO: StrictHostKeyChecking=no for compat only, must be removed
+ $cmd .= ' -o StrictHostKeyChecking=no'
+ . ' -i ' . escapeshellarg($this->privateKey);
+ }
+
+ $cmd .= sprintf(
+ ' %s "cat > %s"',
+ escapeshellarg($this->host),
+ escapeshellarg($this->path)
+ );
+
+ return $cmd;
+ }
+
+ /**
+ * Send the command over SSH
+ *
+ * @param string $commandString
+ *
+ * @throws CommandTransportException
+ */
+ protected function sendCommandString($commandString)
+ {
+ if ($this->isSshAlive()) {
+ $ret = fwrite($this->sshPipes[0], $commandString . "\n");
+ if ($ret === false) {
+ $this->throwSshFailure('Cannot write to the remote command pipe');
+ } elseif ($ret !== strlen($commandString) + 1) {
+ $this->throwSshFailure(
+ 'Failed to write the whole command to the remote command pipe'
+ );
+ }
+ } else {
+ $this->throwSshFailure();
+ }
+ }
+
+ /**
+ * Get the pipes of the SSH subprocess
+ *
+ * @return array
+ */
+ protected function getSshPipes()
+ {
+ if ($this->sshPipes === null) {
+ $this->forkSsh();
+ }
+
+ return $this->sshPipes;
+ }
+
+ /**
+ * Get the SSH subprocess
+ *
+ * @return resource
+ */
+ protected function getSshProcess()
+ {
+ if ($this->sshProcess === null) {
+ $this->forkSsh();
+ }
+
+ return $this->sshProcess;
+ }
+
+ /**
+ * Get the status of the SSH subprocess
+ *
+ * @param string $what
+ *
+ * @return mixed
+ */
+ protected function getSshProcessStatus($what = null)
+ {
+ $status = proc_get_status($this->getSshProcess());
+ if ($what === null) {
+ return $status;
+ } else {
+ return $status[$what];
+ }
+ }
+
+ /**
+ * Get whether the SSH subprocess is alive
+ *
+ * @return bool
+ */
+ protected function isSshAlive()
+ {
+ return $this->getSshProcessStatus('running');
+ }
+
+ /**
+ * Fork SSH subprocess
+ *
+ * @throws CommandTransportException If fork fails
+ */
+ protected function forkSsh()
+ {
+ $descriptors = array(
+ 0 => array('pipe', 'r'),
+ 1 => array('pipe', 'w'),
+ 2 => array('pipe', 'w')
+ );
+
+ $this->sshProcess = proc_open($this->sshCommand(), $descriptors, $this->sshPipes);
+
+ if (! is_resource($this->sshProcess)) {
+ throw new CommandTransportException(
+ 'Can\'t send external Icinga command: Failed to fork SSH'
+ );
+ }
+ }
+
+ /**
+ * Read from STDERR
+ *
+ * @return string
+ */
+ protected function readStderr()
+ {
+ return stream_get_contents($this->sshPipes[2]);
+ }
+
+ /**
+ * Throw SSH failure
+ *
+ * @param string $msg
+ *
+ * @throws CommandTransportException
+ */
+ protected function throwSshFailure($msg = 'Can\'t send external Icinga command')
+ {
+ throw new CommandTransportException(
+ '%s: %s',
+ $msg,
+ $this->readStderr() . var_export($this->getSshProcessStatus(), true)
+ );
+ }
+
+ /**
+ * Close SSH pipes and SSH subprocess
+ */
+ public function __destruct()
+ {
+ if (is_resource($this->sshProcess)) {
+ fclose($this->sshPipes[0]);
+ fclose($this->sshPipes[1]);
+ fclose($this->sshPipes[2]);
+
+ proc_close($this->sshProcess);
+ }
+ }
+}