diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 0750c33db..81b446adf 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -228,7 +228,8 @@ class Monitoring_ListController extends MonitoringController 'notification_start_time', 'notification_contact', 'notification_information', - 'notification_command' + 'notification_command', + 'notification_internal_id' ) )->getQuery(); $this->view->notifications = $query->paginate(); diff --git a/modules/monitoring/application/controllers/MonitoringCommands.php b/modules/monitoring/application/controllers/MonitoringCommands.php new file mode 100644 index 000000000..0889dc670 --- /dev/null +++ b/modules/monitoring/application/controllers/MonitoringCommands.php @@ -0,0 +1,96 @@ + + * @author Icinga Development Team + */ +// {{{ICINGA_LICENSE_HEADER}}} + +use \Icinga\Module\Monitoring\Command\Meta; + +/** + * Class MonitoringCommands + * + * Helper which produces a list of command buttons + * depending on object states + */ +class Zend_View_Helper_MonitoringCommands extends Zend_View_Helper_Abstract +{ + /** + * Fetch all monitoring commands that are currently available for *all* + * given objects and render a html string that contains buttons to execute + * these commands. + * + * NOTE: This means that if you give multiple commands, the commands that + * are not available on every single host, will be left out. + * + * @param array|stdClass $object host or service object or something other + * @param string $type small or full + * + * @return string The rendered html + */ + public function monitoringCommands($object, $type) + { + $commands = new Meta(); + $definitions = $commands->getCommandForObject($object, $type); + $out = '
'; + $i = 0; + + foreach ($definitions as $definition) { + + if ($i % 5 === 0) { + $out .= '
'; + } + + if ($type === Meta::TYPE_FULL) { + $out .= '
'; + } + + $out .= sprintf( + '', + $definition->id, + $definition->shortDescription, + $definition->longDescription, + $definition->iconCls, + ($definition->btnCls) ? $definition->btnCls : 'btn-default' + ); + + if ($type === Meta::TYPE_FULL) { + $out .= '
'; + } + + $i++; + } + + $out .= '
'; + + $out .= '
'; + + if ($type === Meta::TYPE_FULL) { + return '
'. $out. '
'; + } + + return $out; + } +} diff --git a/modules/monitoring/application/controllers/MultiController.php b/modules/monitoring/application/controllers/MultiController.php index 27ef672a9..a6efcad25 100644 --- a/modules/monitoring/application/controllers/MultiController.php +++ b/modules/monitoring/application/controllers/MultiController.php @@ -28,7 +28,9 @@ // {{{ICINGA_LICENSE_HEADER}}} use \Icinga\Web\Controller\ActionController; - +use \Icinga\Module\Monitoring\Backend; +use \Icinga\Module\Monitoring\Object\Host; +use \Icinga\Module\Monitoring\Object\Service; /** * Displays aggregations collections of multiple objects. */ @@ -36,31 +38,78 @@ class Monitoring_MultiController extends ActionController { public function init() { - $this->view->objects = $this->getDetailQueries(); + $this->view->queries = $this->getDetailQueries(); + $this->backend = Backend::createBackend($this->_getParam('backend')); } public function hostAction() { - $this->view->hosts = $this->_getAllParams(); + $hosts = array(); + $warnings = array(); + + foreach ($this->view->queries as $index => $query) { + if (array_key_exists('host', $query)) { + $host = Host::fetch($this->backend, $query['host']); + $host->prefetch(); + $hosts[] = $host; + } else { + $warnings[] = 'Query ' . $index . ' misses property host.'; + } + } + $this->view->commands = array( + 'host' => array( + ), + 'service' => array( + + ), + 'notification' => array( + + ), + '' + ); + + $this->view->objects = $this->view->hosts = $hosts; + $this->view->warnings = $warnings; } - public function servicesAction() + public function serviceAction() { + $services = array(); + $warnings = array(); + + foreach ($this->view->queries as $index => $query) { + if (!array_key_exists('host', $query)) { + $warnings[] = 'Query ' . $index . ' misses property host.'; + continue; + } + if (!array_key_exists('service', $query)) { + $warnings[] = 'Query ' . $index . ' misses property service.'; + continue; + } + $service = Service::fetch($this->backend, $query['host'], $query['service']); + $service->prefetch(); + $services[] = $service; + } + + $this->view->objects = $this->view->services = $services; + $this->view->warnings = $warnings; } - public function notificationsAction() + public function notificationAction() { + } public function historyAction() { + } /** - * Fetch all queries from the 'detail' parameter and prepare - * them for further processing. + * Fetch all requests from the 'detail' parameter. * - * @return array An array containing all requests and their filter values. + * @return array An array of request that contain + * the filter arguments as properties. */ private function getDetailQueries() { @@ -79,4 +128,6 @@ class Monitoring_MultiController extends ActionController } return $objects; } -} \ No newline at end of file + + +} diff --git a/modules/monitoring/application/views/helpers/CommandButton.php b/modules/monitoring/application/views/helpers/CommandButton.php new file mode 100644 index 000000000..a4431e60d --- /dev/null +++ b/modules/monitoring/application/views/helpers/CommandButton.php @@ -0,0 +1,234 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{ICINGA_LICENSE_HEADER}}} + +/** + * Class Zend_View_Helper_CommandButton + */ +class Zend_View_Helper_CommandButton extends Zend_View_Helper_Abstracts { + + /** + * Available command buttons. + */ + const CMD_DISABLE_ACTIVE_CHECKS = 1; + const CMD_ENABLE_ACTIVE_CHECKS = 2; + const CMD_RESCHEDULE_NEXT_CHECK = 3; + const CMD_SUBMIT_PASSIVE_CHECK_RESULT = 4; + const CMD_STOP_OBSESSING = 5; + const CMD_START_OBSESSING = 6; + const CMD_STOP_ACCEPTING_PASSIVE_CHECKS = 7; + const CMD_START_ACCEPTING_PASSIVE_CHECKS = 8; + const CMD_DISABLE_NOTIFICATIONS = 9; + const CMD_ENABLE_NOTIFICATIONS = 10; + const CMD_SEND_CUSTOM_NOTIFICATION = 11; + const CMD_SCHEDULE_DOWNTIME = 12; + const CMD_SCHEDULE_DOWNTIMES_TO_ALL = 13; + const CMD_REMOVE_DOWNTIMES_FROM_ALL = 14; + const CMD_DISABLE_NOTIFICATIONS_FOR_ALL = 15; + const CMD_ENABLE_NOTIFICATIONS_FOR_ALL = 16; + const CMD_RESCHEDULE_NEXT_CHECK_TO_ALL = 17; + const CMD_DISABLE_ACTIVE_CHECKS_FOR_ALL = 18; + const CMD_ENABLE_ACTIVE_CHECKS_FOR_ALL = 19; + const CMD_DISABLE_EVENT_HANDLER = 20; + const CMD_ENABLE_EVENT_HANDLER = 21; + const CMD_DISABLE_FLAP_DETECTION = 22; + const CMD_ENABLE_FLAP_DETECTION = 23; + const CMD_ADD_COMMENT = 24; + const CMD_RESET_ATTRIBUTES = 25; + const CMD_ACKNOWLEDGE_PROBLEM = 26; + const CMD_REMOVE_ACKNOWLEDGEMENT = 27; + const CMD_DELAY_NOTIFICATION = 28; + const CMD_REMOVE_DOWNTIME = 29; + + /** + * Information about interface commands + * + * With following structure + *
+     * array(
+     *  self::CMD_CONSTANT_* => array(
+     *   '',
+     *   '',
+     *   '[ICON CSS CLASS]',
+     *   '[BUTTON CSS CLASS]',
+     *
+     *    // Maybe any other options later on
+     *  )
+     * )
+     * 
+ * + * @var array + */ + private static $commandInformation = array( + self::CMD_DISABLE_ACTIVE_CHECKS => array( + 'Disable Active Checks For This %s', // Long description (mandatory) + 'Disable Active Checks', // Short description (mandatory) + '', // Icon anything (optional) + '' // Button css cls (optional) + ), + self::CMD_ENABLE_ACTIVE_CHECKS => array( + 'Enable Active Checks For This %s', + 'Enable Active Checks', + '' + ), + self::CMD_RESCHEDULE_NEXT_CHECK => array( + 'Reschedule Next Service Check', + 'Recheck', + '', + 'btn-success' + ), + self::CMD_SUBMIT_PASSIVE_CHECK_RESULT => array( + 'Submit Passive Check Result', + 'Submit Check Result', + '' + ), + self::CMD_STOP_OBSESSING => array( + 'Stop Obsessing Over This %s', + 'Stop Obsessing', + '' + ), + self::CMD_START_OBSESSING => array( + 'Start Obsessing Over This %s', + 'Start Obsessing', + '' + ), + self::CMD_STOP_ACCEPTING_PASSIVE_CHECKS => array( + 'Stop Accepting Passive Checks For This %s', + 'Stop Passive Checks', + '' + ), + self::CMD_START_ACCEPTING_PASSIVE_CHECKS => array( + 'Start Accepting Passive Checks For This %s', + 'Start Passive Checks', + '' + ), + self::CMD_DISABLE_NOTIFICATIONS => array( + 'Disable Notifications For This %s', + 'Disable Notifications', + '' + ), + self::CMD_ENABLE_NOTIFICATIONS => array( + 'Enable Notifications For This %s', + 'Enable Notifications', + '' + ), + self::CMD_SEND_CUSTOM_NOTIFICATION => array( + 'Send Custom %s Notification', + 'Send Notification', + '' + ), + self::CMD_SCHEDULE_DOWNTIME => array( + 'Schedule Downtime For This %s', + 'Schedule Downtime', + '' + ), + self::CMD_SCHEDULE_DOWNTIMES_TO_ALL => array( + 'Schedule Downtime For This %s And All Services', + 'Schedule Services Downtime', + '' + ), + self::CMD_REMOVE_DOWNTIMES_FROM_ALL => array( + 'Remove Downtime(s) For This %s And All Services', + 'Remove Downtime(s)', + '' + ), + self::CMD_DISABLE_NOTIFICATIONS_FOR_ALL => array( + 'Disable Notification For All Service On This %s', + 'Disable Service Notifications', + '' + ), + self::CMD_ENABLE_NOTIFICATIONS_FOR_ALL => array( + 'Enable Notification For All Service On This %s', + 'Enable Service Notifications', + '' + ), + self::CMD_RESCHEDULE_NEXT_CHECK_TO_ALL => array( + 'Schedule a Check Of All Service On This %s', + 'Recheck All Services', + '', + 'btn-success' + ), + self::CMD_DISABLE_ACTIVE_CHECKS_FOR_ALL => array( + 'Disable Checks For All Services On This %s', + 'Disable Service Checks', + '' + ), + self::CMD_ENABLE_ACTIVE_CHECKS_FOR_ALL => array( + 'Enable Checks For All Services On This %s', + 'Enable Service Checks', + '' + ), + self::CMD_DISABLE_EVENT_HANDLER => array( + 'Disable Event Handler For This %s', + 'Disable Event Handler', + '' + ), + self::CMD_ENABLE_EVENT_HANDLER => array( + 'Enable Event Handler For This %s', + 'Enable Event Handler', + '' + ), + self::CMD_DISABLE_FLAP_DETECTION => array( + 'Disable Flap Detection For This %s', + 'Disable Flap Detection', + '' + ), + self::CMD_ENABLE_FLAP_DETECTION => array( + 'Enable Flap Detection For This %s', + 'Enable Flap Detection', + '' + ), + self::CMD_ADD_COMMENT => array( + 'Add New %s Comment', + 'Add Comment', + '' + ), + self::CMD_RESET_ATTRIBUTES => array( + 'Reset Modified Attributes', + 'Reset Attributes', + '', + 'btn-danger' + ), + self::CMD_ACKNOWLEDGE_PROBLEM => array( + 'Acknowledge %s Problem', + 'Acknowledge', + '', + 'btn-warning' + ), + self::CMD_REMOVE_ACKNOWLEDGEMENT => array( + 'Remove %s Acknowledgement', + 'Remove Acknowledgement', + '', + 'btn-warning' + ), + self::CMD_DELAY_NOTIFICATION => array( + 'Delay Next %s Notification', + 'Delay Notification', + '' + ), + ); +} \ No newline at end of file diff --git a/modules/monitoring/application/views/helpers/MonitoringCommands.php b/modules/monitoring/application/views/helpers/MonitoringCommands.php index abd9588ef..0889dc670 100644 --- a/modules/monitoring/application/views/helpers/MonitoringCommands.php +++ b/modules/monitoring/application/views/helpers/MonitoringCommands.php @@ -34,11 +34,19 @@ use \Icinga\Module\Monitoring\Command\Meta; class Zend_View_Helper_MonitoringCommands extends Zend_View_Helper_Abstract { /** - * @param stdClass $object host or service object or something other - * @param string $type small or full - * @return string html output + * Fetch all monitoring commands that are currently available for *all* + * given objects and render a html string that contains buttons to execute + * these commands. + * + * NOTE: This means that if you give multiple commands, the commands that + * are not available on every single host, will be left out. + * + * @param array|stdClass $object host or service object or something other + * @param string $type small or full + * + * @return string The rendered html */ - public function monitoringCommands(\stdClass $object, $type) + public function monitoringCommands($object, $type) { $commands = new Meta(); $definitions = $commands->getCommandForObject($object, $type); diff --git a/modules/monitoring/application/views/scripts/list/notifications.phtml b/modules/monitoring/application/views/scripts/list/notifications.phtml index 0604cda8e..8507d4d9c 100644 --- a/modules/monitoring/application/views/scripts/list/notifications.phtml +++ b/modules/monitoring/application/views/scripts/list/notifications.phtml @@ -27,7 +27,8 @@ } else { $detailLink = $this->href('monitoring/show/host', array( 'host' => $notification->host_name, - 'service' => $notification->service_description + 'service' => $notification->service_description, + 'notification_id' => $notification->notification_internal_id ) ); } diff --git a/modules/monitoring/application/views/scripts/multi/components/comments.phtml b/modules/monitoring/application/views/scripts/multi/components/comments.phtml new file mode 100644 index 000000000..b3d9bbc7f --- /dev/null +++ b/modules/monitoring/application/views/scripts/multi/components/comments.phtml @@ -0,0 +1 @@ +
- Summary for object(s) + Execute commands for all object(s)
+ monitoringCommands($objects, \Icinga\Module\Monitoring\Command\Meta::TYPE_FULL); ?>
- \ No newline at end of file + diff --git a/modules/monitoring/application/views/scripts/multi/downtimes.phtml b/modules/monitoring/application/views/scripts/multi/downtimes.phtml new file mode 100644 index 000000000..514102444 --- /dev/null +++ b/modules/monitoring/application/views/scripts/multi/downtimes.phtml @@ -0,0 +1,12 @@ +
+
+ {{HOST_ICON}}

Selected hosts

+
+
+ + + +
+
+ +render('multi/components/summary.phtml') ?> \ No newline at end of file diff --git a/modules/monitoring/application/views/scripts/multi/host.phtml b/modules/monitoring/application/views/scripts/multi/host.phtml index e9fce5bf9..5886d3693 100644 --- a/modules/monitoring/application/views/scripts/multi/host.phtml +++ b/modules/monitoring/application/views/scripts/multi/host.phtml @@ -1 +1,21 @@ -render('multi/components/summary.phtml'); ?> \ No newline at end of file +
+
+ {{HOST_ICON}}

Selected hosts

+
+
+ +
+
+ +render('multi/components/summary.phtml') ?> diff --git a/modules/monitoring/application/views/scripts/multi/service.phtml b/modules/monitoring/application/views/scripts/multi/service.phtml new file mode 100644 index 000000000..78c16c47e --- /dev/null +++ b/modules/monitoring/application/views/scripts/multi/service.phtml @@ -0,0 +1,22 @@ +
+
+ {{SERVICE_ICON}}

Selected services

+
+
+ services as $service) { ?> +
  • + + host_name ?> service_description ?> + +
  • + +
    +
    + +render('multi/components/summary.phtml') ?> diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/NotificationQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/NotificationQuery.php index dd11e1dc3..a0d803e10 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/NotificationQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/NotificationQuery.php @@ -40,7 +40,8 @@ class NotificationQuery extends IdoQuery 'notification_type' => 'n.notification_type', 'notification_reason' => 'n.notification_reason', 'notification_start_time' => 'n.start_time', - 'notification_information' => 'n.output' + 'notification_information' => 'n.output', + 'notification_internal_id' => 'n.notification_id' ), 'objects' => array( 'host_name' => 'o.name1', diff --git a/modules/monitoring/library/Monitoring/Command/Meta.php b/modules/monitoring/library/Monitoring/Command/Meta.php index f26ebf383..fc818a25e 100644 --- a/modules/monitoring/library/Monitoring/Command/Meta.php +++ b/modules/monitoring/library/Monitoring/Command/Meta.php @@ -84,6 +84,20 @@ class Meta const CMD_DELAY_NOTIFICATION = 28; const CMD_REMOVE_DOWNTIME = 29; + + /** + * The context defines which commands are related to which icinga object. This + * is useful for narrowing down the commands to the relevant ones. + */ + + const CONTEXT_SERVICE = 'service'; + const CONTEXT_HOST = 'host'; + const CONTEXT_DOWNTIME = 'downtime'; + const CONTEXT_NOTIFICATION = 'notification'; + const CONTEXT_COMMENT = 'comment'; + const CONTEXT_CONTACT = 'contact'; + + /** * Filter array for array displayed in small interfaces * @var int[] @@ -628,38 +642,21 @@ class Meta /** * Returns the type of object * - * This is made by the first key of property - * e.g. - * $object->host_state - * Type is 'host' - * - * @param \stdClass $object - * @return mixed + * @param $object The object + * + * @return string Either 'host' or 'service' */ - private function getObjectType(\stdClass $object) + private function getObjectType($object) { - $objectKeys = array_keys(get_object_vars($object)); - $firstKeys = explode('_', array_shift($objectKeys), 2); - return array_shift($firstKeys); + if ($object instanceof \Icinga\Module\Monitoring\Object\Host) { + return 'host'; + } else if ($object instanceof \Icinga\Module\Monitoring\Object\Service) { + return 'service'; + } + + throw new ProgrammingError('Object must be either "host" or "service"'); } - /** - * Returns method name based on object type - * @param string $type - * @return string - * @throws \Icinga\Exception\ProgrammingError - */ - private function getCommandProcessorMethod($type) - { - if (array_key_exists($type, self::$commandProcessorMethods)) { - $method = self::$commandProcessorMethods[$type]; - if (is_callable(array(&$this, $method))) { - return $method; - } - } - - throw new ProgrammingError('Type has no command processor: '. $type); - } /** * Return interface commands by object type @@ -675,43 +672,19 @@ class Meta throw new ProgrammingError('Type has no commands defined: '. $type); } - - /** - * Modifies data objects to drop their object type - * - * - host_state will be state - * - service_state will be also state - * - And so on - * - * @param \stdClass $object - * @param $type - * @return object - */ - private function dropTypeAttributes(\stdClass $object, $type) - { - $objectData = get_object_vars($object); - foreach ($objectData as $propertyName => $propertyValue) { - $newProperty = str_replace($type. '_', '', $propertyName); - $objectData[$newProperty] = $propertyValue; - unset($objectData[$propertyName]); - } - return (object)$objectData; - } - + /** * Default processor for host and service objects * * Drop commands from list based on states and object properties * - * @param \stdClass $object + * @param $object * @param array $commands * @param string $type * @return array */ - private function defaultCommandProcessor(\stdClass $object, array $commands, $type) + private function processCommand($object, array $commands, $type) { - $object = $this->dropTypeAttributes($object, $type); - $commands = array_flip($commands); if ($object->active_checks_enabled === '1') { @@ -736,8 +709,8 @@ class Meta unset($commands[self::CMD_STOP_OBSESSING]); } - if ($object->state !== '0') { - if ($object->acknowledged === '1') { + if ($object->{$type . '_state'} !== '0') { + if ($object->{ $type . '_acknowledged'} === '1') { unset($commands[self::CMD_ACKNOWLEDGE_PROBLEM]); } else { unset($commands[self::CMD_REMOVE_ACKNOWLEDGEMENT]); @@ -767,6 +740,7 @@ class Meta return array_flip($commands); } + /** * Creates structure to work with in interfaces @@ -825,22 +799,88 @@ class Meta } /** - * Get commands for an object + * Narrow down several sets of commands to one set that only contains + * commands that are possible in all sets + * + * @param array $sets The sets of commands to narrow down. + * + * @returns array The merged set of commands + */ + private function mergeCommands(array $sets) + { + /* + * Collect all occurring commands + */ + $merged = array(); + for ($i = 0; $i < count($sets); $i++) { + foreach ($sets[$i] as $j => $value) { + $merged[$sets[$i][$j]] = $j; + } + $sets[$i] = array_flip($sets[$i]); + } + + /* + * Remove all commands that do not exist in every set + * + foreach ($merged as $command => $index) { + foreach ($sets as $i => $set) { + if (!array_key_exists($command, $set)) { + unset($merged[$command]); + } + } + } + */ + return array_flip($merged); + } + + /** + * Remove all commands that do not apply to the given context. + * + * @param array $commands The commands that will be reduced + * @param string $context The context, either + */ + private function applyContext($commands, $context) + { + switch ($context) { + case 'comment': + + break; + } + } + + /** + * Get commands that are available for a set of objects. If more than one object is given, + * the set of commands will be narrowed down to a CommandSet that is available to all * * Based on objects and interface type * - * @param \stdClass $object - * @param $interfaceType - * @param User $user + * @param mixed $object Retrieve the commands for + * @param $interfaceType The interface type (Meta::TYPE_FULL or Meta::TYPE_SMALL) to determine + * the amount of showed commands. + * @param string $context The context that will be used to narrow down the commands. + * @param User $user CURRENTLY NOT IMPLEMENTED! + * * @return array */ - public function getCommandForObject(\stdClass $object, $interfaceType, User $user = null) + public function getCommandForObject( + $objects, + $interfaceType, + $context = null, + User $user = null + ) { - $objectType = $this->getObjectType($object); - $commands = $this->getCommandsByType($objectType); - $method = $this->getCommandProcessorMethod($objectType); - $commands = $this->$method($object, $commands, $objectType); - $commands = $this->filterInterfaceType($commands, $interfaceType); + if (!is_array($objects)) { + $objects = array($objects); + } + $commands = array(); + foreach ($objects as $object) { + $objectType = $this->getObjectType($object); + $command = $this->getCommandsByType($objectType); + $command = $this->processCommand($object, $command, $objectType); + $command = $this->filterInterfaceType($command, $interfaceType); + $commands[] = $command; + } + $commands = $this->mergeCommands($commands); $commands = $this->buildInterfaceConfiguration($commands, $objectType); return $commands; } diff --git a/modules/monitoring/library/Monitoring/DataView/Notification.php b/modules/monitoring/library/Monitoring/DataView/Notification.php index 6a9803c87..817a93609 100644 --- a/modules/monitoring/library/Monitoring/DataView/Notification.php +++ b/modules/monitoring/library/Monitoring/DataView/Notification.php @@ -24,6 +24,7 @@ class Notification extends DataView 'notification_command', 'host', 'service' + 'notification_internal_id' ); } diff --git a/public/js/icinga/selection/multiSelection.js b/public/js/icinga/selection/multiSelection.js index f4b1fd48d..47796a6fa 100644 --- a/public/js/icinga/selection/multiSelection.js +++ b/public/js/icinga/selection/multiSelection.js @@ -133,7 +133,7 @@ function($, URI, Selectable) { if (!selections[i]) { selections[i] = []; } - selections[i] = [ encodeURIComponent(key) + '=' + encodeURIComponent(value) ]; + selections[i].push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); } }); return selections;