Merge branch 'feature/send-commands-4441'

resolves #4441
This commit is contained in:
Jannis Moßhammer 2013-08-06 09:58:42 +02:00
commit cc77a55435
31 changed files with 1444 additions and 328 deletions

View File

@ -32,33 +32,42 @@ use \Icinga\Protocol\Commandpipe\Exception\InvalidCommandException;
use \Icinga\Protocol\Commandpipe\Comment;
/**
* Class Acknowledgement
* @package Icinga\Protocol\Commandpipe
* Container for a host/service Acknowledgement
*/
class Acknowledgement implements IComment
{
/**
* The expire time of this acknowledgement or -1 if no expire time is used
*
* @var int
*/
public $expireTime = -1;
private $expireTime = -1;
/**
* Whether to set the notify flag of the acknowledgment
*
* @var bool
*/
public $notify = false;
private $notify = false;
/**
* @var Comment|null
* The comment text of this acknowledgment
*
* @var Comment
*/
public $comment = null;
private $comment;
/**
* true if this is a sticky acknowledgment
*
* @var bool
*/
public $sticky;
/**
* @param int $time
* Set the expire time of this acknowledgment to $time
*
* @param int $time The new expire time as a UNIX timestamp
*/
public function setExpireTime($time)
{
@ -66,7 +75,9 @@ class Acknowledgement implements IComment
}
/**
* @param boolean $bool
* Set the notify flag of this object
*
* @param boolean $bool True if notify should be set, otherwise false
*/
public function setNotify($bool)
{
@ -74,10 +85,12 @@ class Acknowledgement implements IComment
}
/**
* @param Comment $comment
* @param bool $notify
* @param $expire
* @param bool $sticky
* Create a new acknowledgment container
*
* @param Comment $comment The comment to use for the acknowledgement
* @param bool $notify Whether to set the notify flag
* @param int $expire The expire time or -1 of not expiring
* @param bool $sticky Whether to set the sticky flag
*/
public function __construct(Comment $comment, $notify = false, $expire = -1, $sticky = false)
{
@ -88,9 +101,11 @@ class Acknowledgement implements IComment
}
/**
* @param $type
* @return string
* @throws Exception\InvalidCommandException
* Return the ACKNOWLEDGE_?_PROBLEM string to be used for submitting an external icinga command
*
* @param string $type Either CommandPipe::TYPE_HOST or CommandPipe::TYPE_SERVICE
* @return string The command string to be submitted to the command pipe
* @throws InvalidCommandException
*/
public function getFormatString($type)
{

View File

@ -30,141 +30,121 @@ namespace Icinga\Protocol\Commandpipe;
use Icinga\Application\Logger as IcingaLogger;
use Icinga\Protocol\Commandpipe\Transport\Transport;
use Icinga\Protocol\Commandpipe\Transport\LocalPipe;
use Icinga\Protocol\Commandpipe\Transport\SecureShell;
/**
* Class CommandPipe
* @package Icinga\Protocol\Commandpipe
* Class to the access icinga CommandPipe via a @see Icinga\Protocol\Commandpipe\Transport.php
*
* Will be configured using the instances.ini
*/
class CommandPipe
{
/**
* @var mixed
*/
private $path;
/**
* @var mixed
*/
private $name;
/**
* @var bool|mixed
*/
private $user = false;
/**
* @var bool|mixed
*/
private $host = false;
/**
* @var int|mixed
*/
private $port = 22;
/**
* The name of this class as defined in the instances.ini
*
* @var string
*/
public $fopen_mode = "w";
private $name = "";
/**
* The underlying @see Icinga\Protocol\Commandpipe\Transport.php class handling communication with icinga
*
* @var Icinga\Protocol\Commandpipe\Transport
*/
private $transport = null;
/**
* Constant identifying a monitoring object as host
*/
const TYPE_HOST = "HOST";
/**
*
* Constant identifying a monitoring object as service
*/
const TYPE_SERVICE = "SVC";
/**
*
* Constant identifying a monitoring object as hostgroup
*/
const TYPE_HOSTGROUP = "HOSTGROUP";
/**
*
* Constant identifying a monitoring object as servicegroups
*/
const TYPE_SERVICEGROUP = "SERVICEGROUP";
/**
* Notification option (use logical OR for combination)
*
* Broadcast (send notification to all normal and all escalated contacts for the service)
*/
const NOTIFY_BROADCAST = 1;
/**
* Notification option (use logical OR for combination)
*
* notification is sent out regardless of current time, whether or not notifications are enabled, etc.
*/
const NOTIFY_FORCED = 2;
/**
* Notification option (use logical OR for combination)
*
* Increment current notification # for the service(this is not done by default for custom notifications)
*/
const NOTIFY_INCREMENT = 4;
/**
* Create a new CommandPipe class which accesses the icinga.cmd pipe as defined in $config
*
* @param \Zend_Config $config
*/
public function __construct(\Zend_Config $config)
{
$this->path = $config->path;
$this->getTransportForConfiguration($config);
$this->name = $config->name;
}
/**
* Setup the @see Icinga\Protocol\Commandpipe\Transport.php class that will be used for accessing the command pipe
*
* Currently this method uses SecureShell when a host is given, otherwise it assumes the pipe is accessible
* via the machines filesystem
*
* @param \Zend_Config $config The configuration as defined in the instances.ini
*/
private function getTransportForConfiguration(\Zend_Config $config)
{
if (isset($config->host)) {
$this->host = $config->host;
}
if (isset($config->port)) {
$this->port = $config->port;
}
if (isset($config->user)) {
$this->user = $config->user;
$this->transport = new SecureShell();
$this->transport->setEndpoint($config);
} else {
$this->transport = new LocalPipe();
$this->transport->setEndpoint($config);
}
}
/**
* @param $command
* @throws \RuntimeException
* Send the command string $command to the icinga pipe
*
* This method just delegates the send command to the underlying transport
*
* @param String $command The command string to send, without the timestamp
*/
public function send($command)
{
if (!$this->host) {
IcingaLogger::debug(
"Attempting to send external icinga command $command to local command file {$this->path}"
);
$file = @fopen($this->path, $this->fopen_mode);
if (!$file) {
throw new \RuntimeException("Could not open icinga pipe at $file : " . print_r(error_get_last(), true));
}
fwrite($file, "[" . time() . "] " . $command . PHP_EOL);
IcingaLogger::debug('Writing [' . time() . '] ' . $command . PHP_EOL);
fclose($file);
} else {
// send over ssh
$retCode = 0;
$output = array();
IcingaLogger::debug(
'Icinga instance is on different host, attempting to send command %s via ssh to %s:%s/%s',
$command,
$this->host,
$this->port,
$this->path
);
$hostConnector = $this->user ? $this->user . "@" . $this->host : $this->host;
exec(
"ssh $hostConnector -p{$this->port} \"echo '[" . time() . "] "
. escapeshellcmd(
$command
)
. "' > {$this->path}\"",
$output,
$retCode
);
IcingaLogger::debug(
"$:ssh $hostConnector -p{$this->port} \"echo '[" . time() . "] " . escapeshellcmd(
$command
) . "' > {$this->path}\""
);
IcingaLogger::debug("Code code %s: %s ", $retCode, $output);
if ($retCode != 0) {
throw new \RuntimeException(
'Could not send command to remote icinga host: '
. implode(
"\n",
$output
)
. " (returncode $retCode)"
);
}
}
$this->transport->send($command);
}
/**
* @param $objects
* @param IComment $acknowledgementOrComment
* Acknowledge a set of monitoring objects
*
* $objects can be a mixed array of host and service objects
*
* @param array $objects An array of host and service objects
* @param IComment $acknowledgementOrComment An acknowledgement or comment object to use as the comment
*/
public function acknowledge($objects, IComment $acknowledgementOrComment)
{
@ -184,7 +164,9 @@ class CommandPipe
}
/**
* @param $objects
* Remove the acknowledgements of the provided objects
*
* @param array $objects An array of mixed service and host objects whose acknowledgments will be removed
*/
public function removeAcknowledge($objects)
{
@ -198,15 +180,23 @@ class CommandPipe
}
/**
* @param $objects
* @param $state
* @param $output
* Submit passive check result for all provided objects
*
* @param array $objects An array of hosts and services to submit the passive check result to
* @param int $state The state to set for the monitoring objects
* @param string $output The output string to set as the check result
* @param string $perfdata The optional perfdata to submit as the check result
*/
public function submitCheckResult($objects, $state, $output)
public function submitCheckResult($objects, $state, $output, $perfdata = "")
{
if ($perfdata) {
$output = $output."|".$perfdata;
}
foreach ($objects as $object) {
if (isset($object->service_description)) {
$this->send("PROCESS_SVC_CHECK_RESULT;$object->host_name;$object->service_description;$state;$output");
$this->send(
"PROCESS_SERVICE_CHECK_RESULT;$object->host_name;$object->service_description;$state;$output"
);
} else {
$this->send("PROCESS_HOST_CHECK_RESULT;$object->host_name;$state;$output");
}
@ -214,9 +204,11 @@ class CommandPipe
}
/**
* @param $objects
* @param bool $time
* @param bool $withChilds
* Reschedule a forced check for all provided objects
*
* @param array $objects An array of hosts and services to reschedule
* @param int|bool $time The time to submit, if empty time() will be used
* @param bool $withChilds Whether only childs should be rescheduled
*/
public function scheduleForcedCheck($objects, $time = false, $withChilds = false)
{
@ -234,9 +226,11 @@ class CommandPipe
}
/**
* @param $objects
* @param bool $time
* @param bool $withChilds
* Reschedule a check for all provided objects
*
* @param array $objects An array of hosts and services to reschedule
* @param int|bool $time The time to submit, if empty time() will be used
* @param bool $withChilds Whether only childs should be rescheduled
*/
public function scheduleCheck($objects, $time = false, $withChilds = false)
{
@ -254,8 +248,10 @@ class CommandPipe
}
/**
* @param array $objects
* @param Comment $comment
* Add a comment to all submitted objects
*
* @param array $objects An array of hosts and services to add a comment for
* @param Comment $comment The comment object to add
*/
public function addComment(array $objects, Comment $comment)
{
@ -272,7 +268,10 @@ class CommandPipe
}
/**
* @param $objectsOrComments
* Removes the submitted comments
*
* @param array $objectsOrComments An array of hosts and services (to remove all their comments)
* or single comment objects to remove
*/
public function removeComment($objectsOrComments)
{
@ -300,6 +299,7 @@ class CommandPipe
}
/**
* Globally enable notifications for this instance
*
*/
public function enableGlobalNotifications()
@ -308,6 +308,7 @@ class CommandPipe
}
/**
* Globally disable notifications for this instance
*
*/
public function disableGlobalNotifications()
@ -316,8 +317,10 @@ class CommandPipe
}
/**
* @param $object
* @return string
* Return the object type of the provided object (TYPE_SERVICE or TYPE_HOST)
*
* @param $object The object to identify
* @return string TYPE_SERVICE or TYPE_HOST
*/
private function getObjectType($object)
{
@ -329,8 +332,10 @@ class CommandPipe
}
/**
* @param $objects
* @param Downtime $downtime
* Schedule a downtime for all provided objects
*
* @param array $objects An array of monitoring objects to schedule the downtime for
* @param Downtime $downtime The downtime object to schedule
*/
public function scheduleDowntime($objects, Downtime $downtime)
{
@ -347,8 +352,10 @@ class CommandPipe
}
/**
* @param $objects
* @param int $starttime
* Remove downtimes for objects
*
* @param array $objects An array containing hosts, service or downtime objects
* @param int $starttime An optional starttime to use for the DEL_DOWNTIME_BY_HOST_NAME command
*/
public function removeDowntime($objects, $starttime = 0)
{
@ -370,6 +377,7 @@ class CommandPipe
}
/**
* Restart the icinga instance
*
*/
public function restartIcinga()
@ -378,8 +386,10 @@ class CommandPipe
}
/**
* @param $objects
* @param PropertyModifier $flags
* Modify monitoring flags for the provided objects
*
* @param array $objects An arry of service and/or host objects to modify
* @param PropertyModifier $flags The Monitoring attributes to modify
*/
public function setMonitoringProperties($objects, PropertyModifier $flags)
{
@ -396,7 +406,9 @@ class CommandPipe
}
/**
* @param $objects
* Enable active checks for all provided objects
*
* @param array $objects An array containing services and hosts to enable active checks for
*/
public function enableActiveChecks($objects)
{
@ -411,11 +423,13 @@ class CommandPipe
}
/**
* @param $objects
* Disable active checks for all provided objects
*
* @param array $objects An array containing services and hosts to disable active checks
*/
public function disableActiveChecks($objects)
{
$this->modifyMonitoringProperties(
$this->setMonitoringProperties(
$objects,
new PropertyModifier(
array(
@ -426,7 +440,9 @@ class CommandPipe
}
/**
* @param $objects
* Enable passive checks for all provided objects
*
* @param array $objects An array containing services and hosts to enable passive checks for
*/
public function enablePassiveChecks($objects)
{
@ -441,11 +457,13 @@ class CommandPipe
}
/**
* @param $objects
* Enable passive checks for all provided objects
*
* @param array $objects An array containing services and hosts to enable passive checks for
*/
public function disablePassiveChecks($objects)
{
$this->modifyMonitoringProperties(
$this->setMonitoringProperties(
$objects,
new PropertyModifier(
array(
@ -456,7 +474,10 @@ class CommandPipe
}
/**
* @param $objects
* Enable flap detection for all provided objects
*
* @param array $objects An array containing services and hosts to enable flap detection
*
*/
public function enableFlappingDetection($objects)
{
@ -471,7 +492,10 @@ class CommandPipe
}
/**
* @param $objects
* Disable flap detection for all provided objects
*
* @param array $objects An array containing services and hosts to disable flap detection
*
*/
public function disableFlappingDetection($objects)
{
@ -486,7 +510,10 @@ class CommandPipe
}
/**
* @param $objects
* Enable notifications for all provided objects
*
* @param array $objects An array containing services and hosts to enable notification
*
*/
public function enableNotifications($objects)
{
@ -501,7 +528,10 @@ class CommandPipe
}
/**
* @param $objects
* Disable flap detection for all provided objects
*
* @param array $objects An array containing services and hosts to disable notifications
*
*/
public function disableNotifications($objects)
{
@ -516,7 +546,9 @@ class CommandPipe
}
/**
* @param $objects
* Enable freshness checks for all provided objects
*
* @param array $objects An array of hosts and/or services
*/
public function enableFreshnessChecks($objects)
{
@ -531,7 +563,9 @@ class CommandPipe
}
/**
* @param $objects
* Disable freshness checks for all provided objects
*
* @param array $objects An array of hosts and/or services
*/
public function disableFreshnessChecks($objects)
{
@ -546,7 +580,9 @@ class CommandPipe
}
/**
* @param $objects
* Enable event handler for all provided objects
*
* @param array $objects An array of hosts and/or services
*/
public function enableEventHandler($objects)
{
@ -561,7 +597,9 @@ class CommandPipe
}
/**
* @param $objects
* Disable event handler for all provided objects
*
* @param array $objects An array of hosts and/or services
*/
public function disableEventHandler($objects)
{
@ -576,7 +614,9 @@ class CommandPipe
}
/**
* @param $objects
* Enable performance data parsing for all provided objects
*
* @param array $objects An array of hosts and/or services
*/
public function enablePerfdata($objects)
{
@ -590,6 +630,11 @@ class CommandPipe
);
}
/**
* Disable performance data parsing for all provided objects
*
* @param array $objects An array of hosts and/or services
*/
public function disablePerfdata($objects)
{
$this->setMonitoringProperties(
@ -601,4 +646,202 @@ class CommandPipe
)
);
}
/**
* Start obsessing over provided services/hosts
*
* @param array $objects An array of hosts and/or services
*/
public function startObsessing($objects)
{
foreach ($objects as $object) {
$type = $this->getObjectType($object);
$msg = "START_OBSESSING_OVER_". (($type == self::TYPE_SERVICE) ? 'SVC' : 'HOST');
$msg .= ';'.$object->host_name;
if ($type == self::TYPE_SERVICE) {
$msg .= ';'.$object->service_description;
}
$this->send($msg);
}
}
/**
* Stop obsessing over provided services/hosts
*
* @param array $objects An array of hosts and/or services
*/
public function stopObsessing($objects)
{
foreach ($objects as $object) {
$type = $this->getObjectType($object);
$msg = "STOP_OBSESSING_OVER_". (($type == self::TYPE_SERVICE) ? 'SVC' : 'HOST');
$msg .= ';'.$object->host_name;
if ($type == self::TYPE_SERVICE) {
$msg .= ';'.$object->service_description;
}
$this->send($msg);
}
}
/**
* Start obsessing over provided services/hosts
*
* @param array $objects An array of hosts and/or services
*/
public function startObsessing($objects)
{
foreach ($objects as $object) {
$type = $this->getObjectType($object);
$msg = "START_OBSESSING_OVER_". (($type == self::TYPE_SERVICE) ? 'SVC' : 'HOST');
$msg .= ';'.$object->host_name;
if ($type == self::TYPE_SERVICE) {
$msg .= ';'.$object->service_description;
}
$this->send($msg);
}
}
/**
* Stop obsessing over provided services/hosts
*
* @param array $objects An array of hosts and/or services
*/
public function stopObsessing($objects)
{
foreach ($objects as $object) {
$type = $this->getObjectType($object);
$msg = "STOP_OBSESSING_OVER_". (($type == self::TYPE_SERVICE) ? 'SVC' : 'HOST');
$msg .= ';'.$object->host_name;
if ($type == self::TYPE_SERVICE) {
$msg .= ';'.$object->service_description;
}
$this->send($msg);
}
}
/**
* Send a custom host or service notification
*
* @param $objects monitoring objects to send this notification to
* @param Comment $comment comment to use in the notification
* @param int [$...] Optional list of Notification flags which will be used as the option parameter
*/
public function sendCustomNotification($objects, Comment $comment, $optionsVarList = 0/*, ...*/)
{
$args = func_get_args();
// logical OR for all notification options
for ($i = 3; $i < count($args); $i++) {
$optionsVarList |= $args[$i];
}
foreach ($objects as $object) {
$type = $this->getObjectType($object);
$msg = 'SEND_CUSTOM_'.(($type == self::TYPE_SERVICE) ? 'SVC' : 'HOST' ).'_NOTIFICATION';
$msg .= ';'.$object->host_name;
if ($type == self::TYPE_SERVICE) {
$msg .= ';'.$object->service_description;
}
$msg .= ';'.$optionsVarList;
$msg .= ';'.$comment->author;
$msg .= ';'.$comment->comment;
$this->send($msg);
}
}
/**
* Disable notifications for all services of the provided hosts
*
* @param array $objects An array of hosts
*/
public function disableNotificationsForServices($objects)
{
foreach ($objects as $host) {
$msg = 'DISABLE_HOST_SVC_NOTIFICATIONS;'.$host->host_name;
$this->send($msg);
}
}
/**
* Enable notifications for all services of the provided hosts
*
* @param array $objects An array of hosts
*/
public function enableNotificationsForServices($objects)
{
foreach ($objects as $host) {
$msg = 'ENABLE_HOST_SVC_NOTIFICATIONS;'.$host->host_name;
$this->send($msg);
}
}
/**
* Disable active checks for all services of the provided hosts
*
* @param array $objects An array of hosts
*/
public function disableActiveChecksWithChildren($objects)
{
foreach ($objects as $host) {
$msg = 'DISABLE_HOST_SVC_CHECKS;'.$host->host_name;
$this->send($msg);
}
}
/**
* Enable active checks for all services of the provided hosts
*
* @param array $objects An array of hosts
*/
public function enableActiveChecksWithChildren($objects)
{
foreach ($objects as $host) {
$msg = 'ENABLE_HOST_SVC_CHECKS;'.$host->host_name;
$this->send($msg);
}
}
/**
* Reset modified attributes for all provided objects
*
* @param array $objects An array of hosts and services
*/
public function resetAttributes($objects)
{
foreach ($objects as $object) {
$type = $this->getObjectType($object);
if ($type === self::TYPE_SERVICE) {
$this->send('CHANGE_SVC_MODATTR;'.$object->host_name.';'.$object->service_description.';0');
} else {
$this->send('CHANGE_HOST_MODATTR;'.$object->host_name.';0');
}
}
}
/**
* Delay notifications for all provided hosts and services for $time seconds
*
* @param array $objects An array of hosts and services
* @param int $time The number of seconds to delay notifications for
*/
public function delayNotification($objects, $time)
{
foreach ($objects as $object) {
$type = $this->getObjectType($object);
if ($type === self::TYPE_SERVICE) {
$this->send('DELAY_SVC_NOTIFICATION;'.$object->host_name.';'.$object->service_description.';'.$time);
} else {
$this->send('DELAY_HOST_NOTIFICATION;'.$object->host_name.';'.$time);
}
}
}
/**
* Return the transport handler that handles actual sending of commands
*
* @return Transport
*/
public function getTransport()
{
return $this->transport;
}
}

View File

@ -29,30 +29,38 @@
namespace Icinga\Protocol\Commandpipe;
/**
* Class Comment
* @package Icinga\Protocol\Commandpipe
* Container for comment information that can be send to icinga's external command pipe
*
*/
class Comment implements IComment
{
/**
* Whether the persistent flag should be submitted with this command
*
* @var bool
*/
public $persistent = false;
/**
* @var string
* The author of this comment
*
* @var string
*/
public $author = "";
/**
* @var string
* The comment text to use
*
* @var string
*/
public $comment = "";
/**
* @param $author
* @param $comment
* @param bool $persistent
* Create a new comment object
*
* @param string $author The author name to use for this object
* @param string $comment The comment text to use
* @param bool $persistent Whether this comment should persist icinga restarts
*/
public function __construct($author, $comment, $persistent = false)
{
@ -62,9 +70,13 @@ class Comment implements IComment
}
/**
* @param $type
* @return string
* @throws InvalidCommandException
* Return this comment as an ADD_?_COMMENT external command string that can directly be send to the command pipe
*
* @param string $type either CommandPipe::TYPE_HOST or CommandPipe::TYPE_SERVICE
*
* @return string The ADD_HOST_COMMENT or ADD_SVC_COMMENT command, without the timestamp
*
* @throws InvalidCommandException When $type is unknown
*/
public function getFormatString($type)
{

View File

@ -29,63 +29,135 @@
namespace Icinga\Protocol\Commandpipe;
/**
* Class Downtime
* @package Icinga\Protocol\Commandpipe
* Container class containing downtime information
*
*/
class Downtime
{
/**
* @var mixed
* Propagate this downtime for all child objects
*/
const TYPE_WITH_CHILDREN = 'AND_PROPAGATE_';
/**
* Propagate this downtime for all child objects as triggered downtime
*/
const TYPE_WITH_CHILDREN_TRIGGERED = 'AND_PROPAGATE_TRIGGERED_';
/**
* Schedule downtime for the services of the given hos
*/
const TYPE_HOST_SVC = 'HOST_SVC';
/**
* Timestamp representing the downtime's start
*
* @var int
*/
public $startTime;
/**
* @var mixed
* Timestamp representing the downtime's end
*
* @var int
*/
public $endTime;
/**
* @var mixed
* Whether this is a fixed downtime
*
* @var boolean
*/
private $fixed = false;
/**
* @var mixed
* The duration of the downtime in seconds if flexible
*
* @var int
*/
public $duration;
/**
* @var mixed
* The comment object of the downtime
*
* @var Comment
*/
public $comment;
/**
* @param $start
* @param $end
* @param Comment $comment
* @param int $duration
* The downtime id that triggers this downtime (0 = no triggered downtime)
*
* @var int
*/
public function __construct($start, $end, Comment $comment, $duration = 0)
public $trigger_id = 0;
/**
* Internal information for the exact type of the downtime
*
* E.g. with children, with children and triggered, services etc.
*
* @var string
*/
private $subtype = '';
/**
* Create a new downtime container
*
* @param int $start A timestamp that defines the downtime's start time
* @param int $end A timestamp that defines the downtime's end time
* @param Comment $comment A comment that will be used when scheduling the downtime
* @param int $duration The duration of this downtime in seconds.
* Duration > 0 will make this a flexible downtime
* @param int $trigger_id An id of the downtime that triggers this downtime.
* 0 means this is not a triggered downtime
*/
public function __construct($start, $end, Comment $comment, $duration = 0, $trigger_id = 0)
{
$this->startTime = $start;
$this->endTime = $end;
$this->comment = $comment;
if ($duration != 0) {
if ($duration == 0) {
$this->fixed = true;
}
$this->duration = intval($duration);
$this->trigger_id = intval($trigger_id);
}
/**
* @param $type
* @return string
* Return the SCHEDULE_?_DOWNTIME representing this class for the given $type
*
* @param string $type CommandPipe::TYPE_SERVICE to trigger a service downtime or CommandPipe::TYPE_HOST to
* trigger a host downtime
* @return string A schedule downtime command representing the state of this class
*
*/
public function getFormatString($type)
{
return 'SCHEDULE_' . $type . '_DOWNTIME;%s'
. ($type == CommandPipe::TYPE_SERVICE ? ';%s;' : ';')
. $this->startTime . ';' . $this->endTime
. ';' . ($this->fixed ? '1' : '0') . ';' . $this->duration . ';0;'
. $this->comment->author . ';' . $this->comment->comment;
if ($this->subtype == self::TYPE_HOST_SVC) {
$type = "";
}
return 'SCHEDULE_'
. $this->subtype
. $type
. '_DOWNTIME;'
. '%s;'
. ($type == CommandPipe::TYPE_SERVICE ? '%s;' : '')
. $this->startTime . ';'
. $this->endTime . ';'
. ($this->fixed ? '1' : '0') . ';'
. $this->trigger_id . ';'
. $this->duration . ';'
. $this->comment->author . ';'
. $this->comment->comment;
}
/**
* Set the exact type of this downtime (see the TYPE_ constants)
*
* @param $type The type of to use for this downtime
*/
public function setType($type)
{
$this->subtype = $type;
}
}

View File

@ -29,8 +29,7 @@
namespace Icinga\Protocol\Commandpipe\Exception;
/**
* Class InvalidCommandException
* @package Icinga\Protocol\Commandpipe\Exception
* Exception class for unknown/invalid external commands
*/
class InvalidCommandException extends \Exception
{

View File

@ -29,8 +29,8 @@
namespace Icinga\Protocol\Commandpipe;
/**
* Class IComment
* @package Icinga\Protocol\Commandpipe
* Interface flagging a class as being a comment
*
*/
interface IComment
{

View File

@ -29,60 +29,62 @@
namespace Icinga\Protocol\Commandpipe;
/**
* Class PropertyModifier
* @package Icinga\Protocol\Commandpipe
* Container class to modify a few monitoring attributes at oncee
*
*/
class PropertyModifier
{
/**
*
* Set an attribute to be enabled in the command
*/
const STATE_ENABLE = 1;
/**
*
* Set an attribute to be disabled in the command
*/
const STATE_DISABLE = 0;
/**
*
* Set an attribute to not be modified in the command
*/
const STATE_KEEP = -1;
/**
*
* Template for enabling/disabling flap detection
*/
const FLAPPING = "%s_FLAP_DETECTION";
/**
*
* Template for enabling/disabling active checks
*/
const ACTIVE = "%s_CHECK";
/**
*
* Template for enabling/disabling passive checks
*/
const PASSIVE = "PASSIVE_%s_CHECKS";
/**
*
* Template for enabling/disabling notification
*/
const NOTIFICATIONS = "%s_NOTIFICATIONS";
/**
*
* Template for enabling/disabling freshness checks
*/
const FRESHNESS = "%s_FRESHNESS_CHECKS";
/**
*
* Template for enabling/disabling event handler
*/
const EVENTHANDLER = "%s_EVENT_HANDLER";
/**
* The state that will be applied when fetching this container for an object
*
* @var array
*/
public $flags = array(
private $flags = array(
self::FLAPPING => self::STATE_KEEP,
self::ACTIVE => self::STATE_KEEP,
self::PASSIVE => self::STATE_KEEP,
@ -92,7 +94,9 @@ class PropertyModifier
);
/**
* @param array $flags
* Create a new PropertyModified object using the given flags
*
* @param array $flags Flags to enable/disable/keep different monitoring attributes
*/
public function __construct(array $flags)
{
@ -104,8 +108,10 @@ class PropertyModifier
}
/**
* @param $type
* @return array
* Return this object as a template for the given object type
*
* @param $type Either CommandPipe::TYPE_HOST or CommandPipe::TYPE_SERVICE
* @return array An array of external command templates for the given type representing the containers state
*/
public function getFormatString($type)
{

View File

@ -0,0 +1,84 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Protocol\Commandpipe\Transport;
use Icinga\Application\Logger;
/**
* CommandPipe Transport class that writes to a file accessible by the filesystem
*/
class LocalPipe implements Transport
{
/**
* The path of the icinga commandpipe
*
* @var String
*/
private $path;
/**
* The mode to use for fopen()
*
* @var string
*/
private $openMode = "w";
/**
* @see Transport::setEndpoint()
*/
public function setEndpoint(\Zend_Config $config)
{
$this->path = isset($config->path) ? $config->path : '/usr/local/icinga/var/rw/icinga.cmd';
}
/**
* @see Transport::send()
*/
public function send($message)
{
Logger::debug('Attempting to send external icinga command %s to local command file ', $message, $this->path);
$file = @fopen($this->path, $this->openMode);
if (!$file) {
throw new \RuntimeException('Could not open icinga pipe at $file : ' . print_r(error_get_last(), true));
}
fwrite($file, '[' . time() . '] ' . $message . PHP_EOL);
Logger::debug('Writing [' . time() . '] ' . $message . PHP_EOL);
fclose($file);
}
/**
* Overwrite the open mode (useful for testing)
*
* @param string $mode A open mode supported by fopen()
*/
public function setOpenMode($mode)
{
$this->openMode = $mode;
}
}

View File

@ -0,0 +1,124 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Protocol\Commandpipe\Transport;
use Icinga\Application\Logger;
/**
* Command pipe transport class that uses ssh for connecting to a remote filesystem with the icinga.cmd pipe
* The remote host must have KeyAuth enabled for this user
*
*/
class SecureShell implements Transport
{
/**
* The remote host to connect to
*
* @var string
*/
private $host = 'localhost';
/**
* The location of the icinga pipe on the remote host
*
* @var string
*/
private $path = "/usr/local/icinga/var/rw/icinga.cmd";
/**
* The SSH port of the remote host
*
* @var int
*/
private $port = 22;
/**
* The user to authenticate with on the remote host
*
* @var String
*/
private $user = null;
/**
* @see Transport::setEndpoint()
*
*/
public function setEndpoint(\Zend_Config $config)
{
$this->host = isset($config->host) ? $config->host : "localhost";
$this->port = isset($config->port) ? $config->port : 22;
$this->user = isset($config->user) ? $config->user : null;
$this->password = isset($config->password) ? $config->password : null;
$this->path = isset($config->path) ? $config->path : "/usr/local/icinga/var/rw/icinga.cmd";
}
/**
* @see Transport::send()
*
*/
public function send($command)
{
$retCode = 0;
$output = array();
Logger::debug(
'Icinga instance is on different host, attempting to send command %s via ssh to %s:%s/%s',
$command,
$this->host,
$this->port,
$this->path
);
$hostConnector = $this->user ? $this->user . "@" . $this->host : $this->host;
exec(
'ssh -o BatchMode=yes -o KbdInteractiveAuthentication=no'
. $hostConnector.' -p'.$this->port.' "echo \'['. time() .'] '
. escapeshellcmd(
$command
)
. '\' > '.$this->path.'" > /dev/null 2> /dev/null & ',
$output,
$retCode
);
Logger::debug(
'ssh '.$hostConnector.' -p'.$this->port.' "echo \'['. time() .'] '
. escapeshellcmd(
$command
)
. '\' > '.$this->path.'"'
);
Logger::debug("Return code %s: %s ", $retCode, $output);
if ($retCode != 0) {
$msg = 'Could not send command to remote icinga host: '
. implode(PHP_EOL, $output)
. " (returncode $retCode)";
Logger::error($msg);
throw new \RuntimeException($msg);
}
}
}

View File

@ -0,0 +1,50 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Protocol\Commandpipe\Transport;
/**
* Interface for Transport classes handling the concrete access to the command pipe
*
*/
interface Transport
{
/**
* Overwrite the target file of this Transport class using the given config from instances.ini
*
* @param \Zend_Config $config A configuration file containing a 'path' setting
*/
public function setEndpoint(\Zend_Config $config);
/**
* Write the given external command to the command pipe
*
* @param string $message The command to send, without the timestamp (this will be added here)
*/
public function send($message);
}

View File

@ -29,14 +29,15 @@
// {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Application\Benchmark;
use Icinga\Application\Icinga;
use Icinga\Backend;
use Icinga\Application\Config;
use Icinga\Application\Logger;
use Icinga\Authentication\Manager;
use Icinga\Web\Form;
use Icinga\Web\ModuleActionController;
use Icinga\Protocol\Commandpipe\Comment;
use Icinga\Protocol\Commandpipe\CommandPipe;
use Icinga\Protocol\Commandpipe\Acknowledgement;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\MissingParameterException;
use Monitoring\Form\Command\AcknowledgeForm;
@ -97,18 +98,19 @@ class Monitoring_CommandController extends ModuleActionController
{
if ($this->issetForm()) {
if ($this->form->isPostAndValid()) {
$this->_helper->viewRenderer->setNoRender(true);
$this->_helper->layout()->disableLayout();
}
$this->view->form = $this->form;
}
parent::postDispatch();
}
/**
* Controller configuration
*
* @throws Icinga\Exception\ConfigurationError
*/
public function init()
@ -116,9 +118,7 @@ class Monitoring_CommandController extends ModuleActionController
if ($this->_request->isPost()) {
$instance = $this->_request->getPost("instance");
$targetConfig = Config::module('monitoring', 'instances');
if ($instance) {
if ($targetConfig->get($instance)) {
$this->target = new CommandPipe($targetConfig->get($instance));
@ -137,37 +137,60 @@ class Monitoring_CommandController extends ModuleActionController
}
if ($this->getRequest()->getActionName() !== 'list') {
// Reduce template writing mess
$this->_helper->viewRenderer->setRender(self::DEFAULT_VIEW_SCRIPT);
}
}
/**
* Retrieve all existing targets for host- and service combination
* @param string $hostname
* @param string $servicename
* @return array
*
* @param $hostOnly Ignore the service parameters
* (for example when using commands that only make sense for hosts)
*
* @return array Array of monitoring objects
*
* @throws Icinga\Exception\MissingParameterException
*/
private function selectCommandTargets($hostname, $servicename = null)
private function selectCommandTargets($hostOnly = false)
{
$target = "hostlist";
$filter = array();
if (!$hostname && !$servicename) {
throw new MissingParameterException("Missing host and service definition");
$query = null;
$fields = array(
'host_name',
'host_state'
);
try {
$hostname = $this->getParam('host', null);
$servicename = $this->getParam('service', null);
$filter = array();
if (!$hostname && !$servicename) {
throw new MissingParameterException("No target given for this command");
}
if ($hostname) {
$filter["host_name"] = $hostname;
}
if ($servicename && !$hostOnly) {
$filter["service_description"] = $servicename;
$fields[] = "service_description";
$fields[] = "service_state";
}
;
$query = Backend::getInstance()->select()->from("status", $fields);
return $query->applyFilters($filter)->fetchAll();
} catch (\Exception $e) {
Logger::error(
"CommandController: SQL Query '%s' failed (message %s) ",
$query ? (string) $query->getQuery()->dump() : '--', $e->getMessage()
);
return array();
}
if ($hostname) {
$filter["host_name"] = $hostname;
}
if ($servicename) {
$filter["service_description"] = $servicename;
$target = "servicelist";
}
return Backend::getInstance()->select()->from($target)->applyFilters($filter)->fetchAll();
}
/**
* Displays a list of all commands
*
* This method uses reflection on the sourcecode to determine all *Action classes and return
* a list of them (ignoring the listAction)
*
*/
public function listAction()
{
@ -183,16 +206,48 @@ class Monitoring_CommandController extends ModuleActionController
$this->view->commands = $commands;
}
/**
* Tell the controller that at least one of the parameters in $supported is required to be availabe
*
* @param array $supported An array of properties to check for existence in the POST or GET parameter list
*
* @throws Exception When non of the supported parameters is given
*/
private function setSupportedParameters(array $supported)
{
$given = array_intersect_key(array_flip($supported), $this->getRequest()->getParams());
if (empty($given)) {
throw new \Exception('Missing parameter, supported: '.implode(', ', $supported));
}
if (isset($given["host"])) {
$this->view->objects = $this->selectCommandTargets(!in_array("service", $supported));
if (empty($this->view->objects)) {
throw new \Exception("No objects found for your command");
}
} else if (in_array("downtimeid", $supported)) {
$this->view->objects = array();
$downtimes = $this->getParam("downtimeid");
if (!is_array($downtimes)) {
$downtimes = array($downtimes);
}
foreach ($downtimes as $downtimeId) {
$this->view->objects[] = (object) array("downtime_id" => $downtimeId);
}
}
}
// ------------------------------------------------------------------------
// Commands for hosts / services
// ------------------------------------------------------------------------
/**
* Handle command disableactivechecks
* @throws Icinga\Exception\ProgrammingError
*
*/
public function disableactivechecksAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Disable active checks'));
@ -200,16 +255,17 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->disableActiveChecks($this->view->objects);
}
}
/**
* Handle command enableactivechecks
* @throws Icinga\Exception\ProgrammingError
*
*/
public function enableactivechecksAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Enable active checks'));
@ -217,32 +273,34 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->enableActiveChecks($this->view->objects);
}
}
/**
* Handle command reschedulenextcheck
* @throws Icinga\Exception\ProgrammingError
*
*/
public function reschedulenextcheckAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new RescheduleNextCheckForm();
$form->setRequest($this->getRequest());
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->scheduleCheck($this->view->objects);
}
}
/**
* Handle command submitpassivecheckresult
* @throws Icinga\Exception\ProgrammingError
*
*/
public function submitpassivecheckresultAction()
{
$this->setSupportedParameters(array('host', 'service'));
$type = SubmitPassiveCheckResultForm::TYPE_SERVICE;
$form = new SubmitPassiveCheckResultForm();
@ -252,16 +310,17 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->submitCheckResult($this->view->objects, $form->getState(), $form->getOutput(), $form->getPerformancedata());
}
}
/**
* Handle command stopobsessing
* @throws Icinga\Exception\ProgrammingError
*
*/
public function stopobsessingAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Stop obsessing'));
@ -269,16 +328,17 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->stopObsessing($this->view->objects);
}
}
/**
* Handle command startobsessing
* @throws Icinga\Exception\ProgrammingError
*
*/
public function startobsessingAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Start obsessing'));
@ -286,16 +346,17 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->startObsessing($this->view->objects);
}
}
/**
* Handle command stopacceptingpassivechecks
* @throws Icinga\Exception\ProgrammingError
*
*/
public function stopacceptingpassivechecksAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Stop accepting passive checks'));
@ -303,16 +364,17 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->disablePassiveChecks($this->view->objects);
}
}
/**
* Handle command startacceptingpassivechecks
* @throws Icinga\Exception\ProgrammingError
*
*/
public function startacceptingpassivechecksAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Start accepting passive checks'));
@ -320,16 +382,17 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->enableActiveChecks($this->view->objects);
}
}
/**
* Handle command disablenotifications
* @throws Icinga\Exception\ProgrammingError
*
*/
public function disablenotificationsAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Disable notifications'));
@ -337,13 +400,13 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->disableNotifications($this->view->objects);
}
}
/**
* Handle command enablenotifications
* @throws Icinga\Exception\ProgrammingError
*
*/
public function enablenotificationsAction()
{
@ -354,63 +417,73 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->enableNotifications($this->view->objects);
}
}
/**
* Handle command sendcustomnotification
* @throws Icinga\Exception\ProgrammingError
*
*/
public function sendcustomnotificationAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new CustomNotificationForm();
$form->setRequest($this->getRequest());
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$author = $this->getRequest()->getUser()->getUsername();
$this->target->sendCustomNotification(
$this->view->objects,
new Comment($author, $form->getComment()),
$form->getOptions()
);
}
}
/**
* Handle command scheduledowntime
* @throws Icinga\Exception\ProgrammingError
*
*/
public function scheduledowntimeAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ScheduleDowntimeForm();
$form->setRequest($this->getRequest());
$form->setWithChildren(false);
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->scheduleDowntime($this->view->objects, $form->getDowntime());
}
}
/**
* Handle command scheduledowntimeswithchildren
*
* @throws Icinga\Exception\ProgrammingError
*/
public function scheduledowntimeswithchildrenAction()
{
$this->setSupportedParameters(array('host'));
$form = new ScheduleDowntimeForm();
$form->setRequest($this->getRequest());
$form->setWithChildren(true);
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->scheduleDowntime($this->view->objects, $form->getDowntime());
}
}
/**
* Handle command removedowntimeswithchildren
* @throws Icinga\Exception\ProgrammingError
*
*/
public function removedowntimeswithchildrenAction()
{
$this->setSupportedParameters(array('host'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Remove downtime(s)'));
@ -418,16 +491,17 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->removeDowntime($this->view->objects);
}
}
/**
* Handle command disablenotificationswithchildren
* @throws Icinga\Exception\ProgrammingError
*
*/
public function disablenotificationswithchildrenAction()
{
$this->setSupportedParameters(array('host'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Disable notifications'));
@ -435,16 +509,18 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->disableNotifications($this->view->objects);
$this->target->disableNotificationsForServices($this->view->objects);
}
}
/**
* Handle command enablenotificationswithchildren
* @throws Icinga\Exception\ProgrammingError
*
*/
public function enablenotificationswithchildrenAction()
{
$this->setSupportedParameters(array('host'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Enable notifications'));
@ -452,16 +528,18 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->enableNotifications($this->view->objects);
$this->target->enableNotificationsForServices($this->view->objects);
}
}
/**
* Handle command reschedulenextcheckwithchildren
* @throws Icinga\Exception\ProgrammingError
*
*/
public function reschedulenextcheckwithchildrenAction()
{
$this->setSupportedParameters(array('host'));
$form = new RescheduleNextCheckForm();
$form->setRequest($this->getRequest());
@ -470,16 +548,23 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
if ($form->isForced()) {
$this->target->scheduleForcedCheck($this->view->objects, time());
$this->target->scheduleForcedCheck($this->view->objects, time(), true);
} else {
$this->target->scheduleCheck($this->view->objects, time());
$this->target->scheduleCheck($this->view->objects, time(), true);
}
}
}
/**
* Handle command disableactivecheckswithchildren
* @throws Icinga\Exception\ProgrammingError
*
*/
public function disableactivecheckswithchildrenAction()
{
$this->setSupportedParameters(array('host'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Disable active checks'));
@ -487,16 +572,18 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->disableActiveChecks($this->view->objects);
$this->target->disableActiveChecksWithChildren($this->view->objects);
}
}
/**
* Handle command enableactivecheckswithchildren
* @throws Icinga\Exception\ProgrammingError
*
*/
public function enableactivecheckswithchildrenAction()
{
$this->setSupportedParameters(array('host'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Enable active checks'));
@ -504,16 +591,18 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->enableActiveChecks($this->view->objects);
$this->target->enableActiveChecksWithChildren($this->view->objects);
}
}
/**
* Handle command disableeventhandler
* @throws Icinga\Exception\ProgrammingError
*
*/
public function disableeventhandlerAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Disable event handler'));
@ -521,16 +610,17 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->disableEventHandler($this->view->objects);
}
}
/**
* Handle command enableeventhandler
* @throws Icinga\Exception\ProgrammingError
*
*/
public function enableeventhandlerAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Enable event handler'));
@ -538,16 +628,17 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->enableEventHandler($this->view->objects);
}
}
/**
* Handle command disableflapdetection
* @throws Icinga\Exception\ProgrammingError
*
*/
public function disableflapdetectionAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Disable flapping detection'));
@ -555,16 +646,17 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->disableFlappingDetection($this->view->objects);
}
}
/**
* Handle command enableflapdetection
* @throws Icinga\Exception\ProgrammingError
*
*/
public function enableflapdetectionAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Enable flapping detection'));
@ -572,32 +664,34 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->enableFlappingDetection($this->view->objects);
}
}
/**
* Handle command addcomment
* @throws Icinga\Exception\ProgrammingError
*
*/
public function addcommentAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new CommentForm();
$form->setRequest($this->getRequest());
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->addComment($this->view->objects, $form->getComment());
}
}
/**
* Handle command resetattributes
* @throws Icinga\Exception\ProgrammingError
*
*/
public function resetattributesAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Reset attributes'));
@ -605,32 +699,34 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->resetAttributes($this->view->objects);
}
}
/**
* Handle command acknowledgeproblem
* @throws Icinga\Exception\ProgrammingError
*
*/
public function acknowledgeproblemAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new AcknowledgeForm();
$form->setRequest($this->getRequest());
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->acknowledge($this->view->objects, $form->getAcknowledgement());
}
}
/**
* Handle command removeacknowledgement
* @throws Icinga\Exception\ProgrammingError
*
*/
public function removeacknowledgementAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new ConfirmationForm();
$form->setRequest($this->getRequest());
$form->setSubmitLabel(t('Remove problem acknowledgement'));
@ -638,32 +734,34 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->removeAcknowledge($this->view->objects);
}
}
/**
* Handle command delaynotification
* @throws Icinga\Exception\ProgrammingError
*
*/
public function delaynotificationAction()
{
$this->setSupportedParameters(array('host', 'service'));
$form = new DelayNotificationForm();
$form->setRequest($this->getRequest());
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->delayNotification($this->view->objects, $form->getDelayTime());
}
}
/**
* Handle command removedowntime
* @throws Icinga\Exception\ProgrammingError
*
*/
public function removedowntimeAction()
{
$this->setSupportedParameters(array('downtimeid'));
$form = new ConfirmationWithIdentifierForm();
$form->setRequest($this->getRequest());
@ -675,7 +773,7 @@ class Monitoring_CommandController extends ModuleActionController
$this->setForm($form);
if ($form->isPostAndValid() === true) {
throw new \Icinga\Exception\ProgrammingError('Command sender not implemented: '. __FUNCTION__);
$this->target->removeDowntime($this->view->objects);
}
}
}

View File

@ -32,7 +32,8 @@ use Icinga\Web\Form\Element\DateTime;
use \DateTime as PhpDateTime;
use \DateInterval;
use Icinga\Web\Form\Element\Note;
use Icinga\Protocol\Commandpipe\Acknowledgement;
use Icinga\Protocol\Commandpipe\Comment;
/**
* Form for acknowledge commands
*/
@ -142,4 +143,24 @@ class AcknowledgeForm extends ConfirmationForm
$expireTime->addValidator($this->createDateTimeValidator(), true);
}
}
public function getAcknowledgement()
{
$expireTime = -1;
if ($this->getValue('expire')) {
$time = new PhpDateTime($this->getValue('expiretime'));
$expireTime = $time->getTimestamp();
}
return new Acknowledgement(
new Comment(
$this->getAuthorName(),
$this->getValue('comment'),
$this->getValue('persistent')
),
$this->getValue('notify'),
$expireTime,
$this->getValue('sticky')
);
}
}

View File

@ -28,6 +28,7 @@
namespace Monitoring\Form\Command;
use Icinga\Protocol\Commandpipe\Comment;
/**
* Form for adding comment commands
*/
@ -64,4 +65,9 @@ class CommentForm extends ConfirmationForm
parent::create();
}
public function getComment()
{
return new Comment($this->getAuthorName(), $this->getValue('comment'), $this->getValue('persistent'));
}
}

View File

@ -68,12 +68,14 @@ class ConfirmationForm extends Form
/**
* Array of messages
*
* @var string[]
*/
private $notes = array();
/**
* Setter for cancel label
*
* @param string $cancelLabel
*/
public function setCancelLabel($cancelLabel)
@ -83,6 +85,7 @@ class ConfirmationForm extends Form
/**
* Getter for cancel label
*
* @return string
*/
public function getCancelLabel()
@ -92,6 +95,7 @@ class ConfirmationForm extends Form
/**
* Setter for submit label
*
* @param string $submitLabel
*/
public function setSubmitLabel($submitLabel)
@ -101,6 +105,7 @@ class ConfirmationForm extends Form
/**
* Getter for submit label
*
* @return string
*/
public function getSubmitLabel()
@ -110,6 +115,7 @@ class ConfirmationForm extends Form
/**
* Add message to stack
*
* @param string $message
*/
public function addNote($message)
@ -119,6 +125,7 @@ class ConfirmationForm extends Form
/**
* Purge messages from stack
*
*/
public function clearNotes()
{
@ -127,6 +134,7 @@ class ConfirmationForm extends Form
/**
* Getter for notes
*
* @return string[]
*/
public function getNotes()
@ -148,6 +156,7 @@ class ConfirmationForm extends Form
/**
* Add elements to this form (used by extending classes)
*
* @see Form::create
*/
protected function create()
@ -191,15 +200,19 @@ class ConfirmationForm extends Form
/**
* Get the author name
* TODO(mh): This should work on the request, at present it's fix
*/
protected function getAuthorName()
{
return 'Iwan IV. Wassiljewitsch, der Schreckliche';
if (is_a($this->getRequest(), "Zend_Controller_Request_HttpTestCase")) {
return "Test user";
}
return $this->getRequest()->getUser()->getUsername();
}
/**
* Creator for author field
*
* @return Zend_Form_Element_Hidden
*/
protected function createAuthorField()

View File

@ -73,4 +73,21 @@ class CustomNotificationForm extends ConfirmationForm
parent::create();
}
public function getComment()
{
return $this->getValue('comment');
}
public function getOptions()
{
$value = 0;
if ($this->getValue('force')) {
$value |= 2;
}
if ($this->getValue('broadcast')) {
$value |= 1;
}
return $value;
}
}

View File

@ -70,4 +70,9 @@ class DelayNotificationForm extends ConfirmationForm
parent::create();
}
public function getDelayTime()
{
return $this->getValue('minutes')*60;
}
}

View File

@ -79,4 +79,9 @@ class RescheduleNextCheckForm extends WithChildrenCommandForm
parent::create();
}
public function isForced()
{
return $this->getValue('forcecheck') == true;
}
}

View File

@ -29,6 +29,8 @@
namespace Monitoring\Form\Command;
use Icinga\Web\Form\Element\DateTime;
use Icinga\Protocol\Commandpipe\Downtime;
use Icinga\Protocol\Commandpipe\Comment;
use \DateTime as PhpDateTime;
use \DateInterval;
use \Zend_Form_Element_Text;
@ -58,6 +60,7 @@ class ScheduleDowntimeForm extends WithChildrenCommandForm
/**
* Build an array of timestamps
*
* @return string[]
*/
private function generateDefaultTimestamps()
@ -76,6 +79,7 @@ class ScheduleDowntimeForm extends WithChildrenCommandForm
/**
* Generate translated multi options based on type constants
*
* @return array
*/
private function getDowntimeTypeOptions()
@ -88,6 +92,7 @@ class ScheduleDowntimeForm extends WithChildrenCommandForm
/**
* Interface method to build the form
*
* @see ConfirmationForm::create
*/
protected function create()
@ -104,6 +109,10 @@ class ScheduleDowntimeForm extends WithChildrenCommandForm
)
);
/**
* @TODO: Display downtime list (Bug #4496)
*
*/
$this->addElement(
'text',
'triggered',
@ -242,6 +251,7 @@ class ScheduleDowntimeForm extends WithChildrenCommandForm
/**
* Change validators at runtime
*
* @see Form::preValidation
* @param array $data
*/
@ -265,4 +275,45 @@ class ScheduleDowntimeForm extends WithChildrenCommandForm
$minutes->addValidator($greaterThanValidator, true);
}
}
/**
* Return the downtime submitted in this form
*
* @return Downtime
*/
public function getDowntime()
{
$comment = new Comment(
$this->getRequest()->getUser()->getUsername(),
$this->getValue('comment')
);
$duration = 0;
if ($this->getValue('type') === self::TYPE_FLEXIBLE) {
$duration = ($this->getValue('hours')*3600) + ($this->getValue('minutes')*60);
}
$starttime = new PhpDateTime($this->getValue('starttime'));
$endtime = new PhpDateTime($this->getValue('endtime'));
$downtime = new Downtime(
$starttime->getTimestamp(),
$endtime->getTimestamp(),
$comment,
$duration,
$this->getValue('triggered')
);
if (! $this->getWithChildren()) {
switch ($this->getValue('childobjects')) {
case 1:
$downtime->setType(Downtime::TYPE_WITH_CHILDREN_TRIGGERED);
break;
case 2:
$downtime->setType(Downtime::TYPE_WITH_CHILDREN);
break;
}
} else {
$downtime->setType(Downtime::TYPE_HOST_SVC);
}
return $downtime;
}
}

View File

@ -168,4 +168,20 @@ class SubmitPassiveCheckResultForm extends ConfirmationForm
parent::create();
}
public function getState()
{
return intval($this->getValue('pluginstate'));
}
public function getOutput()
{
return $this->getValue('checkoutput');
}
public function getPerformancedata()
{
return $this->getValue('performancedata');
}
}

View File

@ -39,7 +39,7 @@ class Zend_View_Helper_MonitoringFlags extends Zend_View_Helper_Abstract
private static $keys = array(
'passive_checks_enabled' => 'Passive checks',
'active_checks_enabled' => 'Active checks',
'obsess_over_host' => 'Obsessing',
'obsessing' => 'Obsessing',
'notifications_enabled' => 'Notifications',
'event_handler_enabled' => 'Event handler',
'flap_detection_enabled' => 'Flap detection',

View File

@ -1,4 +1,30 @@
<?php if (isset($this->objects) && !empty($this->objects) && isset($this->objects[0]->host_name)): ?>
<table class="table table-bordered table-striped table-condensed">
<legend>Affected objects</legend>
<thead>
<tr>
<th>Host name</th>
<th>Service name</th>
</tr>
</thead>
<tbody>
<?php foreach ($this->objects as $object): ?>
<tr>
<td><?= $object->host_name; ?></td>
<td><?= (isset($object->service_description) ? $object->service_description : ''); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
<?php if ($this->form): ?>
<div style="border: 1px #cc0000 solid; padding: 5px; margin: 10px 0 0 10px; max-width: 600px;">
<?= $this->form; ?>
<div class="clearfix"></div>
</div>
</div>
<?php endif; ?>

View File

@ -0,0 +1,37 @@
# The instance.ini configuration file
## Abstract
The instance.ini defines how icingaweb accesses the command pipe of your icinga process in order to submit external
commands. When you are at the root of your icingaweb installation you can find it under ./config/modules/monitoring/instances.ini.
## Syntax
You can define multiple instances in the instances.ini, icingaweb will use the first one as the default instance.
Every instance starts with a section header containing the name of the instance, followed by the config directives for
this instance in the standard ini format used by icingaweb.
## Using a local icinga pipe
A local icinga instance can be easily setup and only requires the 'path' parameter:
[icinga]
path=/usr/local/icinga/var/rw/icinga.cmd
When sending commands to the icinga instance, icingaweb just opens the file found underneath 'path' and writes the external
command to it.
## Using ssh for accessing an icinga pipe
When providing at least a host directive to the instances.ini, SSH will be used for accessing the pipe. You must have
setup key authentication at the endpoint and allow your icingweb's user to access the machine without a password at this time:
[icinga]
path=/usr/local/icinga/var/rw/icinga.cmd ; the path on the remote machine where the icinga.cmd can be found
host=my.remote.machine.com ; the hostname or address of the remote machine
port=22 ; the port to use (22 if none is given)
user=jdoe ; the user to authenticate with

View File

@ -149,7 +149,7 @@ class AbstractBackend implements DatasourceInterface
'host_scheduled_downtime_depth',
'host_failure_prediction_enabled',
'host_process_performance_data',
'host_obsess_over_host',
'host_obsessing',
'host_modified_host_attributes',
'host_event_handler',
'host_check_command',
@ -230,7 +230,7 @@ class AbstractBackend implements DatasourceInterface
'service_scheduled_downtime_depth',
'service_failure_prediction_enabled',
'service_process_performance_data',
'service_obsess_over_service',
'service_obsessing',
'service_modified_service_attributes',
'service_event_handler',
'service_check_command',

View File

@ -60,7 +60,7 @@ class StatusQuery extends AbstractQuery
'host_scheduled_downtime_depth' => 'hs.scheduled_downtime_depth',
'host_failure_prediction_enabled' => 'hs.failure_prediction_enabled',
'host_process_performance_data' => 'hs.process_performance_data',
'host_obsess_over_host' => 'hs.obsess_over_host',
'host_obsessing' => 'hs.obsess_over_host',
'host_modified_host_attributes' => 'hs.modified_host_attributes',
'host_event_handler' => 'hs.event_handler',
'host_check_command' => 'hs.check_command',
@ -160,7 +160,7 @@ class StatusQuery extends AbstractQuery
'service_scheduled_downtime_depth' => 'ss.scheduled_downtime_depth',
'service_failure_prediction_enabled' => 'ss.failure_prediction_enabled',
'service_process_performance_data' => 'ss.process_performance_data',
'service_obsess_over_service' => 'ss.obsess_over_service',
'service_obsessing' => 'ss.obsess_over_service',
'service_modified_service_attributes' => 'ss.modified_service_attributes',
'service_event_handler' => 'ss.event_handler',
'service_check_command' => 'ss.check_command',

View File

@ -729,8 +729,8 @@ class Meta
} else {
unset($commands[self::CMD_START_ACCEPTING_PASSIVE_CHECKS]);
}
$obsess = 'obsess_over_'.$type;
if ($object->$obsess === '1') {
if ($object->obsessing === '1') {
unset($commands[self::CMD_START_OBSESSING]);
} else {
unset($commands[self::CMD_STOP_OBSESSING]);

View File

@ -54,7 +54,7 @@ class HostStruct extends \stdClass
public $host_scheduled_downtime_depth = '1';
public $host_failure_prediction_enabled = '1';
public $host_process_performance_data = '1';
public $host_obsess_over_host = '1';
public $host_obsessing = '1';
public $host_modified_host_attributes = '14';
public $host_event_handler = '';
public $host_normal_check_interval = '5';

View File

@ -13,7 +13,7 @@ class MonitoringFlagsTest extends \PHPUnit_Framework_TestCase
$testArray = array(
'host_passive_checks_enabled' => '0',
'host_active_checks_enabled' => '0',
'host_obsess_over_host' => '1',
'host_obsessing' => '1',
'host_notifications_enabled' => '0',
'host_event_handler_enabled' => '1',
'host_flap_detection_enabled' => '1',
@ -41,7 +41,7 @@ class MonitoringFlagsTest extends \PHPUnit_Framework_TestCase
$testArray = array(
'service_passive_checks_enabled' => '0',
'service_active_checks_enabled' => '1',
'service_obsess_over_host' => '0',
'service_obsessing' => '0',
'service_notifications_enabled' => '1',
'service_event_handler_enabled' => '1',
'service_flap_detection_enabled' => '0',
@ -68,7 +68,7 @@ class MonitoringFlagsTest extends \PHPUnit_Framework_TestCase
{
$testArray = array(
'service_active_checks_enabled' => '1',
'service_obsess_over_host' => '1',
'service_obsessing' => '1',
'DING DING' => '$$$',
'DONG DONG' => '###'
);

View File

@ -50,7 +50,7 @@ class HostStruct4Properties extends \stdClass
public $host_scheduled_downtime_depth = '1';
public $host_failure_prediction_enabled = '1';
public $host_process_performance_data = '1';
public $host_obsess_over_host = '1';
public $host_obsessing = '1';
public $host_modified_host_attributes = '14';
public $host_event_handler = '';
public $host_normal_check_interval = '5';

View File

@ -51,7 +51,7 @@ class HostStruct extends \stdClass
public $host_scheduled_downtime_depth = '1';
public $host_failure_prediction_enabled = '1';
public $host_process_performance_data = '1';
public $host_obsess_over_host = '1';
public $host_obsessing = '1';
public $host_modified_host_attributes = '14';
public $host_event_handler = '';
public $host_normal_check_interval = '5';
@ -158,7 +158,7 @@ class MetaTest extends \PHPUnit_Framework_TestCase
$object = new HostStruct();
$object->host_obsess_over_host = '0';
$object->host_obsessing = '0';
$object->host_flap_detection_enabled = '0';
$object->host_active_checks_enabled = '0';

View File

@ -0,0 +1,34 @@
<?php
/**
* Created by JetBrains PhpStorm.
* User: moja
* Date: 7/31/13
* Time: 1:29 PM
* To change this template use File | Settings | File Templates.
*/
namespace Tests\Icinga\Protocol\Commandpipe;
require_once("./library/Icinga/LibraryLoader.php");
use Test\Icinga\LibraryLoader;
class CommandPipeLoader extends LibraryLoader {
public static function requireLibrary()
{
require_once("Zend/Config.php");
require_once("Zend/Log.php");
require_once("../../library/Icinga/Application/Logger.php");
require_once("../../library/Icinga/Protocol/Commandpipe/IComment.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Comment.php");
require_once("../../library/Icinga/Protocol/Commandpipe/CommandPipe.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Acknowledgement.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Downtime.php");
require_once("../../library/Icinga/Protocol/Commandpipe/PropertyModifier.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Exception/InvalidCommandException.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Transport/Transport.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Transport/SecureShell.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Transport/LocalPipe.php");
}
}

View File

@ -1,35 +1,45 @@
<?php
namespace Tests\Icinga\Protocol\Commandpipe;
require_once(__DIR__.'/CommandPipeLoader.php');
CommandPipeLoader::requireLibrary();
use Icinga\Protocol\Commandpipe\Comment as Comment;
use Icinga\Protocol\Commandpipe\Acknowledgement as Acknowledgement;
use Icinga\Protocol\Commandpipe\Downtime as Downtime;
use Icinga\Protocol\Commandpipe\Commandpipe as Commandpipe;
use \Icinga\Protocol\Commandpipe\PropertyModifier as MONFLAG;
require_once("Zend/Config.php");
require_once("Zend/Log.php");
require_once("../../library/Icinga/Application/Logger.php");
require_once("../../library/Icinga/Protocol/Commandpipe/IComment.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Comment.php");
require_once("../../library/Icinga/Protocol/Commandpipe/CommandPipe.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Acknowledgement.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Downtime.php");
require_once("../../library/Icinga/Protocol/Commandpipe/PropertyModifier.php");
require_once("../../library/Icinga/Protocol/Commandpipe/Exception/InvalidCommandException.php");
use Icinga\Protocol\Ldap\Exception;
if(!defined("EXTCMD_TEST_BIN"))
define("EXTCMD_TEST_BIN", "./bin/extcmd_test");
/**
* Several tests for the command pipe component
*
* Uses the helper script extcmd_test, which is basically the extracted command
* parser functions from the icinga core
*
*
*/
class CommandPipeTest extends \PHPUnit_Framework_TestCase
{
/**
* Return the path of the test pipe used in these tests
*
* @return string
*/
public function getPipeName()
{
return sys_get_temp_dir()."/icinga_test_pipe";
}
private function getTestPipe()
/**
* Return a @see Icinga\Protocal\CommandPipe\CommandPipe instance set up for the local test pipe
*
* @return Commandpipe
*/
private function getLocalTestPipe()
{
$tmpPipe = $this->getPipeName();
$this->cleanup();
@ -45,26 +55,76 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
return $pipe;
}
/**
* Return a @see Icinga\Protocal\CommandPipe\CommandPipe instance set up for the local test pipe, but with ssh as the transport layer
*
* @return Commandpipe
*/
private function getSSHTestPipe()
{
$tmpPipe = $this->getPipeName();
$this->cleanup();
touch($tmpPipe);
$cfg = new \Zend_Config(array(
"path" => $tmpPipe,
"user" => "vagrant",
"password" => "vagrant",
"host" => 'localhost',
"port" => 22,
"name" => "test"
));
$comment = new Comment("Autor","Comment");
$pipe = new Commandpipe($cfg);
return $pipe;
}
/**
* Remove the testpipe if it exists
*
*/
private function cleanup() {
if(file_exists($this->getPipeName()))
unlink($this->getPipeName());
}
/**
* Query the extcmd_test script with $command or the command pipe and test whether the result is $exceptedString and
* has a return code of 0.
*
* Note:
* - if no string is given, only the return code is tested
* - if no command is given, the content of the test commandpipe is used
*
* This helps testing whether commandpipe serialization works correctly
*
* @param bool $expectedString The string that is expected to be returned from the extcmd_test binary
* (optional, leave it to just test for the return code)
* @param bool $command The commandstring to send (optional, leave it for using the command pipe content)
*/
private function assertCommandSucceeded($expectedString = false,$command = false) {
$resultCode = null;
$resultArr = array();
$receivedCmd = exec(EXTCMD_TEST_BIN." ".escapeshellarg($command ? $command : file_get_contents($this->getPipeName())),$resultArr,$resultCode);
$this->assertEquals(0,$resultCode,"Submit of external command returned error : ".$receivedCmd);
$this->assertEquals(0, $resultCode, "Submit of external command returned error : ".$receivedCmd);
if (!$expectedString)
return;
$this->assertEquals(
$expectedString,
$receivedCmd
$receivedCmd,
'Asserting that the command icinga received matches the command we send'
);
}
/**
* Test whether a single host acknowledgment is serialized and send correctly
*
* @throws \Exception|Exception
*/
public function testAcknowledgeSingleHost()
{
$pipe = $this->getTestPipe();
$pipe = $this->getLocalTestPipe();
try {
$ack = new Acknowledgement(new Comment("I can","sends teh ack"));
$pipe->acknowledge(array(
@ -80,12 +140,17 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$this->cleanup();
}
/**
* Test whether multiple host and service acknowledgments are serialized and send correctly
*
* @throws \Exception|Exception
*/
public function testAcknowledgeMultipleObjects()
{
$pipe = $this->getTestPipe();
$pipe = $this->getLocalTestPipe();
try {
$ack = new Comment("I can","sends teh ack");
$pipe->fopen_mode = "a";
$pipe->getTransport()->setOpenMode("a");
$pipe->acknowledge(array(
(object) array(
"host_name" => "hostA"
@ -100,8 +165,7 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
),$ack);
$result = explode("\n",file_get_contents($this->getPipeName()));
$this->assertCount(5,$result);
$this->assertCount(5, $result, "Asserting the correct number of commands being written to the command pipe");
$this->assertCommandSucceeded("ACKNOWLEDGE_HOST_PROBLEM;hostA;0;0;0;I can;sends teh ack",$result[0]);
$this->assertCommandSucceeded("ACKNOWLEDGE_HOST_PROBLEM;hostB;0;0;0;I can;sends teh ack",$result[1]);
@ -115,9 +179,14 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$this->cleanup();
}
/**
* Test whether a single host comment is correctly serialized and send to the command pipe
*
* @throws \Exception|Exception
*/
public function testAddHostComment()
{
$pipe = $this->getTestPipe();
$pipe = $this->getLocalTestPipe();
try {
$pipe->addComment(array((object) array("host_name" => "hostA")),
new Comment("Autor","Comment")
@ -130,9 +199,14 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$this->cleanup();
}
/**
* Test whether removing all hostcomments is correctly serialized and send to the command pipe
*
* @throws \Exception|Exception
*/
public function testRemoveAllHostComment()
{
$pipe = $this->getTestPipe();
$pipe = $this->getLocalTestPipe();
try {
$pipe->removeComment(array(
(object) array(
@ -147,9 +221,14 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$this->cleanup();
}
/**
* Test whether removing a single host comment is correctly serialized and send to the command pipe
*
* @throws \Exception|Exception
*/
public function testRemoveSpecificComment()
{
$pipe = $this->getTestPipe();
$pipe = $this->getLocalTestPipe();
try {
$pipe->removeComment(array((object) array("comment_id"=>34,"host_name"=>"test")));
$this->assertCommandSucceeded("DEL_HOST_COMMENT;34");
@ -160,11 +239,16 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$this->cleanup();
}
/**
* Test whether a multiple reschedules for services and hosts are correctly serialized and send to the commandpipe
*
* @throws \Exception|Exception
*/
public function testScheduleChecks()
{
$pipe = $this->getTestPipe();
$pipe = $this->getLocalTestPipe();
try {
$pipe->fopen_mode = "a"; // append so we have multiple results
$pipe->getTransport()->setOpenMode("a"); // append so we have multiple results
$t = time();
// normal reschedule
$pipe->scheduleCheck(array(
@ -182,7 +266,7 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
),$t,true);
$result = explode("\n",file_get_contents($this->getPipeName()));
$this->assertCount(6,$result);
$this->assertCount(6,$result, "Asserting a correct number of commands being written to the commandpipe");
$this->assertCommandSucceeded("SCHEDULE_HOST_CHECK;test;".$t,$result[0]);
$this->assertCommandSucceeded("SCHEDULE_SVC_CHECK;test;svc1;".$t,$result[1]);
@ -198,11 +282,16 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$this->cleanup();
}
/**
* Test whether modifying monitoringflags of a host and service is correctly serialized and send to the command pipe
*
* @throws \Exception|Exception
*/
public function testObjectStateModifications()
{
$pipe = $this->getTestPipe();
$pipe = $this->getLocalTestPipe();
try {
$pipe->fopen_mode = "a";
$pipe->getTransport()->setOpenMode("a");
$pipe->setMonitoringProperties(array(
(object) array(
"host_name" => "Testhost"
@ -223,7 +312,7 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$result = explode("\n",file_get_contents($this->getPipeName()));
array_pop($result); // remove empty last line
$this->assertCount(12,$result);
$this->assertCount(12,$result, "Asserting a correct number of commands being written to the commandpipe");
foreach ($result as $command) {
$this->assertCommandSucceeded(false,$command);
}
@ -235,9 +324,14 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$this->cleanup();
}
/**
* Test whether enabling and disabling global notifications are send correctly to the pipe
*
* @throws \Exception|Exception
*/
public function testGlobalNotificationTrigger()
{
$pipe = $this->getTestPipe();
$pipe = $this->getLocalTestPipe();
try {
$pipe->enableGlobalNotifications();
$this->assertCommandSucceeded("ENABLE_NOTIFICATIONS;");
@ -250,9 +344,14 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$this->cleanup();
}
/**
* Test whether host and servicedowntimes are correctly scheduled
*
* @throws \Exception|Exception
*/
public function testScheduleDowntime()
{
$pipe = $this->getTestPipe();
$pipe = $this->getLocalTestPipe();
try {
$downtime = new Downtime(25,26,new Comment("me","test"));
$pipe->scheduleDowntime(array(
@ -260,7 +359,7 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
"host_name" => "Testhost"
)
),$downtime);
$this->assertCommandSucceeded("SCHEDULE_HOST_DOWNTIME;Testhost;25;26;0;0;0;me;test");
$this->assertCommandSucceeded("SCHEDULE_HOST_DOWNTIME;Testhost;25;26;1;0;0;me;test");
$pipe->scheduleDowntime(array(
(object) array(
@ -268,7 +367,7 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
"service_description" => "svc"
)
),$downtime);
$this->assertCommandSucceeded("SCHEDULE_SVC_DOWNTIME;Testhost;svc;25;26;0;0;0;me;test");
$this->assertCommandSucceeded("SCHEDULE_SVC_DOWNTIME;Testhost;svc;25;26;1;0;0;me;test");
} catch (Exception $e) {
$this->cleanup();
@ -277,11 +376,16 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$this->cleanup();
}
/**
* Test whether the removal of downtimes is correctly serialized and send to the commandpipe for hosts and services
*
* @throws \Exception|Exception
*/
public function testRemoveDowntime()
{
$pipe = $this->getTestPipe();
$pipe = $this->getLocalTestPipe();
try {
$pipe->fopen_mode = "a";
$pipe->getTransport()->setOpenMode("a");
$pipe->removeDowntime(array(
(object) array(
"host_name" => "Testhost"
@ -298,7 +402,7 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
));
$result = explode("\n",file_get_contents($this->getPipeName()));
array_pop($result); // remove empty last line
$this->assertCount(3,$result);
$this->assertCount(3,$result, "Asserting a correct number of commands being written to the commandpipe");
$this->assertCommandSucceeded("DEL_DOWNTIME_BY_HOST_NAME;Testhost",$result[0]);
$this->assertCommandSucceeded("DEL_DOWNTIME_BY_HOST_NAME;host;svc",$result[1]);
$this->assertCommandSucceeded("DEL_SVC_DOWNTIME;123",$result[2]);
@ -310,4 +414,82 @@ class CommandPipeTest extends \PHPUnit_Framework_TestCase
$this->cleanup();
}
/**
* Test whether custom servicenotifications are correctly send to the commandpipe without options
*
* @throws \Exception
*/
public function testSendCustomServiceNotification()
{
$pipe = $this->getLocalTestPipe();
try {
$comment = new Comment("author", "commenttext");
$pipe->sendCustomNotification(array(
(object) array(
"host_name" => "host1",
"service_description" => "service1"
)
), $comment);
$this->assertCommandSucceeded(
"SEND_CUSTOM_SVC_NOTIFICATION;host1;service1;0;author;commenttext"
);
} catch (Exception $e) {
$this->cleanup();
throw $e;
}
$this->cleanup();
}
/**
* Test whether custom hostnotifications are correctly send to the commandpipe with a varlist of options
*
* @throws \Exception
*/
public function testSendCustomHostNotificationWithOptions()
{
$pipe = $this->getLocalTestPipe();
try {
$comment = new Comment('author', 'commenttext');
$pipe->sendCustomNotification(array(
(object) array(
'host_name' => 'host'
)
), $comment, Commandpipe::NOTIFY_FORCED, Commandpipe::NOTIFY_BROADCAST, Commandpipe::NOTIFY_INCREMENT);
$this->assertCommandSucceeded(
'SEND_CUSTOM_HOST_NOTIFICATION;host;7;author;commenttext'
);
} catch (Exception $e) {
$this->cleanup();
throw $e;
}
$this->cleanup();
}
/**
* Test sending of commands via SSH (currently disabled)
*
* @throws \Exception|Exception
*/
public function testSSHCommands()
{
$this->markTestSkipped("This test assumes running in a vagrant VM with key-auth");
if (!is_dir("/vagrant")) {
}
$pipe = $this->getSSHTestPipe();
try {
$ack = new Acknowledgement(new Comment("I can","sends teh ack"));
$pipe->acknowledge(array(
(object) array(
"host_name" => "hostA"
)
),$ack);
$this->assertCommandSucceeded("ACKNOWLEDGE_HOST_PROBLEM;hostA;0;0;0;I can;sends teh ack");
} catch(Exception $e) {
$this->cleanup();
throw $e;
}
$this->cleanup();
}
}