From 576747f792cc09701b24777795194a34d60fb8ac Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 12 Nov 2015 17:44:29 +0100 Subject: [PATCH 01/22] Application\Hook is the new Hook loader --- library/Icinga/{Web => Application}/Hook.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename library/Icinga/{Web => Application}/Hook.php (99%) diff --git a/library/Icinga/Web/Hook.php b/library/Icinga/Application/Hook.php similarity index 99% rename from library/Icinga/Web/Hook.php rename to library/Icinga/Application/Hook.php index 3b9700f27..643cb9041 100644 --- a/library/Icinga/Web/Hook.php +++ b/library/Icinga/Application/Hook.php @@ -1,7 +1,7 @@ Date: Thu, 12 Nov 2015 17:56:32 +0100 Subject: [PATCH 02/22] Application\Hook: move existing ones, keep compat --- .../Icinga/Application/Hook/GrapherHook.php | 111 ++++++++++++++++ .../Icinga/Application/Hook/TicketHook.php | 124 ++++++++++++++++++ .../{Web => Application}/Hook/WebBaseHook.php | 2 +- library/Icinga/Web/Hook.php | 14 ++ library/Icinga/Web/Hook/GrapherHook.php | 106 +-------------- library/Icinga/Web/Hook/TicketHook.php | 119 +---------------- 6 files changed, 258 insertions(+), 218 deletions(-) create mode 100644 library/Icinga/Application/Hook/GrapherHook.php create mode 100644 library/Icinga/Application/Hook/TicketHook.php rename library/Icinga/{Web => Application}/Hook/WebBaseHook.php (96%) create mode 100644 library/Icinga/Web/Hook.php diff --git a/library/Icinga/Application/Hook/GrapherHook.php b/library/Icinga/Application/Hook/GrapherHook.php new file mode 100644 index 000000000..b923d2978 --- /dev/null +++ b/library/Icinga/Application/Hook/GrapherHook.php @@ -0,0 +1,111 @@ +init(); + } + + /** + * Overwrite this function if you want to do some initialization stuff + * + * @return void + */ + protected function init() + { + } + + /** + * Whether this grapher provides previews + * + * @return bool + */ + public function hasPreviews() + { + return $this->hasPreviews; + } + + /** + * Whether this grapher provides tiny previews + * + * @return bool + */ + public function hasTinyPreviews() + { + return $this->hasTinyPreviews; + } + + /** + * Whether a graph for the monitoring object exist + * + * @param MonitoredObject $object + * + * @return bool + */ + abstract public function has(MonitoredObject $object); + + /** + * Get a preview for the given object + * + * This function must return an empty string if no graph exists. + * + * @param MonitoredObject $object + * + * @return string + * @throws ProgrammingError + * + */ + public function getPreviewHtml(MonitoredObject $object) + { + throw new ProgrammingError('This hook provide previews but it is not implemented'); + } + + + /** + * Get a tiny preview for the given object + * + * This function must return an empty string if no graph exists. + * + * @param MonitoredObject $object + * + * @return string + * @throws ProgrammingError + */ + public function getTinyPreviewHtml(MonitoredObject $object) + { + throw new ProgrammingError('This hook provide tiny previews but it is not implemented'); + } +} diff --git a/library/Icinga/Application/Hook/TicketHook.php b/library/Icinga/Application/Hook/TicketHook.php new file mode 100644 index 000000000..8e0aa4cc2 --- /dev/null +++ b/library/Icinga/Application/Hook/TicketHook.php @@ -0,0 +1,124 @@ +init(); + } + + /** + * Overwrite this function for hook initialization, e.g. loading the hook's config + */ + protected function init() + { + } + + /** + * Set the hook as failed w/ the given message + * + * @param string $message Error message or error format string + * @param mixed ...$arg Format string argument + */ + private function fail($message) + { + $args = array_slice(func_get_args(), 1); + $lastError = vsprintf($message, $args); + Logger::debug($lastError); + $this->lastError = $lastError; + } + + /** + * Get the last error, if any + * + * @return string|null + */ + public function getLastError() + { + return $this->lastError; + } + + /** + * Get the pattern + * + * @return string + */ + abstract public function getPattern(); + + /** + * Create a link for each matched element in the subject text + * + * @param array $match Array of matched elements according to {@link getPattern()} + * + * @return string Replacement string + */ + abstract public function createLink($match); + + /** + * Create links w/ {@link createLink()} in the given text that matches to the subject from {@link getPattern()} + * + * In case of errors a debug message is recorded to the log and any subsequent call to {@link createLinks()} will + * be a no-op. + * + * @param string $text + * + * @return string + */ + final public function createLinks($text) + { + if ($this->lastError !== null) { + return $text; + } + + try { + $pattern = $this->getPattern(); + } catch (Exception $e) { + $this->fail('Can\'t create ticket links: Retrieving the pattern failed: %s', IcingaException::describe($e)); + return $text; + } + if (empty($pattern)) { + $this->fail('Can\'t create ticket links: Pattern is empty'); + return $text; + } + try { + $text = preg_replace_callback( + $pattern, + array($this, 'createLink'), + $text + ); + } catch (ErrorException $e) { + $this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e)); + return $text; + } catch (Exception $e) { + $this->fail('Can\'t create ticket links: %s', IcingaException::describe($e)); + return $text; + } + + return $text; + } +} diff --git a/library/Icinga/Web/Hook/WebBaseHook.php b/library/Icinga/Application/Hook/WebBaseHook.php similarity index 96% rename from library/Icinga/Web/Hook/WebBaseHook.php rename to library/Icinga/Application/Hook/WebBaseHook.php index 544d2afa3..826b52a33 100644 --- a/library/Icinga/Web/Hook/WebBaseHook.php +++ b/library/Icinga/Application/Hook/WebBaseHook.php @@ -1,7 +1,7 @@ init(); - } - - /** - * Overwrite this function if you want to do some initialization stuff - * - * @return void - */ - protected function init() - { - } - - /** - * Whether this grapher provides previews - * - * @return bool - */ - public function hasPreviews() - { - return $this->hasPreviews; - } - - /** - * Whether this grapher provides tiny previews - * - * @return bool - */ - public function hasTinyPreviews() - { - return $this->hasTinyPreviews; - } - - /** - * Whether a graph for the monitoring object exist - * - * @param MonitoredObject $object - * - * @return bool - */ - abstract public function has(MonitoredObject $object); - - /** - * Get a preview for the given object - * - * This function must return an empty string if no graph exists. - * - * @param MonitoredObject $object - * - * @return string - * @throws ProgrammingError - * - */ - public function getPreviewHtml(MonitoredObject $object) - { - throw new ProgrammingError('This hook provide previews but it is not implemented'); - } - - - /** - * Get a tiny preview for the given object - * - * This function must return an empty string if no graph exists. - * - * @param MonitoredObject $object - * - * @return string - * @throws ProgrammingError - */ - public function getTinyPreviewHtml(MonitoredObject $object) - { - throw new ProgrammingError('This hook provide tiny previews but it is not implemented'); - } -} +abstract class GrapherHook extends BaseHook {} diff --git a/library/Icinga/Web/Hook/TicketHook.php b/library/Icinga/Web/Hook/TicketHook.php index 74af1a91f..63a4aa75c 100644 --- a/library/Icinga/Web/Hook/TicketHook.php +++ b/library/Icinga/Web/Hook/TicketHook.php @@ -3,122 +3,11 @@ namespace Icinga\Web\Hook; -use ErrorException; -use Exception; -use Icinga\Application\Logger; -use Icinga\Exception\IcingaException; +use Icinga\Application\Hook\TicketHook as BaseHook; /** - * Base class for ticket hooks + * Deprecated, compat only. * - * Extend this class if you want to integrate your ticketing solution Icinga Web 2 + * Please implement hooks in Icinga\Application\Hook */ -abstract class TicketHook -{ - /** - * Last error, if any - * - * @var string|null - */ - protected $lastError; - - /** - * Create a new ticket hook - * - * @see init() For hook initialization. - */ - final public function __construct() - { - $this->init(); - } - - /** - * Overwrite this function for hook initialization, e.g. loading the hook's config - */ - protected function init() - { - } - - /** - * Set the hook as failed w/ the given message - * - * @param string $message Error message or error format string - * @param mixed ...$arg Format string argument - */ - private function fail($message) - { - $args = array_slice(func_get_args(), 1); - $lastError = vsprintf($message, $args); - Logger::debug($lastError); - $this->lastError = $lastError; - } - - /** - * Get the last error, if any - * - * @return string|null - */ - public function getLastError() - { - return $this->lastError; - } - - /** - * Get the pattern - * - * @return string - */ - abstract public function getPattern(); - - /** - * Create a link for each matched element in the subject text - * - * @param array $match Array of matched elements according to {@link getPattern()} - * - * @return string Replacement string - */ - abstract public function createLink($match); - - /** - * Create links w/ {@link createLink()} in the given text that matches to the subject from {@link getPattern()} - * - * In case of errors a debug message is recorded to the log and any subsequent call to {@link createLinks()} will - * be a no-op. - * - * @param string $text - * - * @return string - */ - final public function createLinks($text) - { - if ($this->lastError !== null) { - return $text; - } - - try { - $pattern = $this->getPattern(); - } catch (Exception $e) { - $this->fail('Can\'t create ticket links: Retrieving the pattern failed: %s', IcingaException::describe($e)); - return $text; - } - if (empty($pattern)) { - $this->fail('Can\'t create ticket links: Pattern is empty'); - return $text; - } - try { - $text = preg_replace_callback( - $pattern, - array($this, 'createLink'), - $text - ); - } catch (ErrorException $e) { - $this->fail('Can\'t create ticket links: Pattern is invalid: %s', IcingaException::describe($e)); - return $text; - } catch (Exception $e) { - $this->fail('Can\'t create ticket links: %s', IcingaException::describe($e)); - return $text; - } - - return $text; - } -} +abstract class TicketHook extends BaseHook {} From 52159c2627362b500ab43028cc0ec1e63c68fb0a Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 12 Nov 2015 17:58:19 +0100 Subject: [PATCH 03/22] Hook: switch base namespace checks --- library/Icinga/Application/Hook.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/Icinga/Application/Hook.php b/library/Icinga/Application/Hook.php index 643cb9041..e3ef616a8 100644 --- a/library/Icinga/Application/Hook.php +++ b/library/Icinga/Application/Hook.php @@ -8,7 +8,7 @@ use Icinga\Application\Logger; use Icinga\Exception\ProgrammingError; /** - * Icinga Web Hook registry + * Icinga Hook registry * * Modules making use of predefined hooks have to use this registry * @@ -38,7 +38,7 @@ class Hook * * @var string */ - public static $BASE_NS = 'Icinga\\Web\\Hook\\'; + public static $BASE_NS = 'Icinga\\Application\\Hook\\'; /** * Append this string to base class @@ -56,7 +56,7 @@ class Hook { self::$hooks = array(); self::$instances = array(); - self::$BASE_NS = 'Icinga\\Web\\Hook\\'; + self::$BASE_NS = 'Icinga\\Application\\Hook\\'; } /** @@ -149,7 +149,7 @@ class Hook } else { $base_class = 'Icinga\\Module\\' . ucfirst($module) - . '\\Web\\Hook\\' + . '\\Hook\\' . ucfirst($name) . $suffix; } @@ -205,7 +205,7 @@ class Hook * @param string $name One of the predefined hook names * @param string $key The identifier of a specific subtype * @param string $class Your class name, must inherit one of the - * classes in the Icinga/Web/Hook folder + * classes in the Icinga/Application/Hook folder */ public static function register($name, $key, $class) { From e6903b3834d5826c558192b44cae2416742e3c20 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 12 Nov 2015 18:06:59 +0100 Subject: [PATCH 04/22] Monitoring\Hook: moved from Monitoring\Web\Hook refs #10613 --- .../Monitoring/Hook/HostActionsHook.php | 46 +++++++++++++++++++ .../Monitoring/Hook/ServiceActionsHook.php | 46 +++++++++++++++++++ .../Monitoring/Hook/TimelineProviderHook.php | 37 +++++++++++++++ .../Monitoring/Web/Hook/HostActionsHook.php | 43 ++--------------- .../Web/Hook/ServiceActionsHook.php | 43 ++--------------- .../Web/Hook/TimelineProviderHook.php | 34 ++------------ 6 files changed, 144 insertions(+), 105 deletions(-) create mode 100644 modules/monitoring/library/Monitoring/Hook/HostActionsHook.php create mode 100644 modules/monitoring/library/Monitoring/Hook/ServiceActionsHook.php create mode 100644 modules/monitoring/library/Monitoring/Hook/TimelineProviderHook.php diff --git a/modules/monitoring/library/Monitoring/Hook/HostActionsHook.php b/modules/monitoring/library/Monitoring/Hook/HostActionsHook.php new file mode 100644 index 000000000..b7923bcc8 --- /dev/null +++ b/modules/monitoring/library/Monitoring/Hook/HostActionsHook.php @@ -0,0 +1,46 @@ + url, where title will + * be used as link caption. Url should be an Icinga\Web\Url object when + * the link should point to an Icinga Web url - otherwise a string would + * be fine. + * + * Mixed example: + * + * return array( + * 'Wiki' => 'http://my.wiki/host=' . rawurlencode($host->host_name), + * 'Logstash' => Url::fromPath( + * 'logstash/search/syslog', + * array('host' => $host->host_name) + * ) + * ); + * + * + * One might also provide ssh:// or rdp:// urls if equipped with fitting + * (safe) URL handlers for his browser(s). + * + * TODO: I'd love to see some kind of a Link/LinkSet object implemented + * for this and similar hooks. + * + * @param Host $host Monitoring host object + * + * @return array An array containing a list of host action links + */ + abstract public function getActionsForHost(Host $host); +} diff --git a/modules/monitoring/library/Monitoring/Hook/ServiceActionsHook.php b/modules/monitoring/library/Monitoring/Hook/ServiceActionsHook.php new file mode 100644 index 000000000..6c1ef25ce --- /dev/null +++ b/modules/monitoring/library/Monitoring/Hook/ServiceActionsHook.php @@ -0,0 +1,46 @@ + url, where title will + * be used as link caption. Url should be an Icinga\Web\Url object when + * the link should point to an Icinga Web url - otherwise a string would + * be fine. + * + * Mixed example: + * + * return array( + * 'Wiki' => 'http://my.wiki/host=' . rawurlencode($service->service_name), + * 'Logstash' => Url::fromPath( + * 'logstash/search/syslog', + * array('service' => $service->host_name) + * ) + * ); + * + * + * One might also provide ssh:// or rdp:// urls if equipped with fitting + * (safe) URL handlers for his browser(s). + * + * TODO: I'd love to see some kind of a Link/LinkSet object implemented + * for this and similar hooks. + * + * @param Service $service Monitoring service object + * + * @return array An array containing a list of service action links + */ + abstract public function getActionsForService(Service $service); +} diff --git a/modules/monitoring/library/Monitoring/Hook/TimelineProviderHook.php b/modules/monitoring/library/Monitoring/Hook/TimelineProviderHook.php new file mode 100644 index 000000000..2b9524828 --- /dev/null +++ b/modules/monitoring/library/Monitoring/Hook/TimelineProviderHook.php @@ -0,0 +1,37 @@ + url, where title will - * be used as link caption. Url should be an Icinga\Web\Url object when - * the link should point to an Icinga Web url - otherwise a string would - * be fine. - * - * Mixed example: - * - * return array( - * 'Wiki' => 'http://my.wiki/host=' . rawurlencode($host->host_name), - * 'Logstash' => Url::fromPath( - * 'logstash/search/syslog', - * array('host' => $host->host_name) - * ) - * ); - * - * - * One might also provide ssh:// or rdp:// urls if equipped with fitting - * (safe) URL handlers for his browser(s). - * - * TODO: I'd love to see some kind of a Link/LinkSet object implemented - * for this and similar hooks. - * - * @param Host $host Monitoring host object - * - * @return array An array containing a list of host action links - */ - abstract public function getActionsForHost(Host $host); -} +abstract class HostActionsHook extends BaseHook {} diff --git a/modules/monitoring/library/Monitoring/Web/Hook/ServiceActionsHook.php b/modules/monitoring/library/Monitoring/Web/Hook/ServiceActionsHook.php index 2df3c4f55..25ec269f0 100644 --- a/modules/monitoring/library/Monitoring/Web/Hook/ServiceActionsHook.php +++ b/modules/monitoring/library/Monitoring/Web/Hook/ServiceActionsHook.php @@ -3,44 +3,11 @@ namespace Icinga\Module\Monitoring\Web\Hook; -use Icinga\Module\Monitoring\Object\Service; +use Icinga\Module\Monitoring\Hook\HostActionsHook as BaseHook; /** - * Base class for host action hooks + * Compat only + * + * Please implement hooks in our Hook direcory */ -abstract class ServiceActionsHook -{ - /** - * Implementors of this method should return an array containing - * additional action links for a specific host. You get a full Service - * object, which allows you to return specific links only for nodes - * with specific properties. - * - * The result array should be in the form title => url, where title will - * be used as link caption. Url should be an Icinga\Web\Url object when - * the link should point to an Icinga Web url - otherwise a string would - * be fine. - * - * Mixed example: - * - * return array( - * 'Wiki' => 'http://my.wiki/host=' . rawurlencode($service->service_name), - * 'Logstash' => Url::fromPath( - * 'logstash/search/syslog', - * array('service' => $service->host_name) - * ) - * ); - * - * - * One might also provide ssh:// or rdp:// urls if equipped with fitting - * (safe) URL handlers for his browser(s). - * - * TODO: I'd love to see some kind of a Link/LinkSet object implemented - * for this and similar hooks. - * - * @param Service $service Monitoring service object - * - * @return array An array containing a list of service action links - */ - abstract public function getActionsForService(Service $service); -} +abstract class ServiceActionsHook extends BaseHook {} diff --git a/modules/monitoring/library/Monitoring/Web/Hook/TimelineProviderHook.php b/modules/monitoring/library/Monitoring/Web/Hook/TimelineProviderHook.php index 0af65d303..265e6894d 100644 --- a/modules/monitoring/library/Monitoring/Web/Hook/TimelineProviderHook.php +++ b/modules/monitoring/library/Monitoring/Web/Hook/TimelineProviderHook.php @@ -3,35 +3,11 @@ namespace Icinga\Module\Monitoring\Web\Hook; -use Icinga\Module\Monitoring\Timeline\TimeRange; +use Icinga\Module\Monitoring\Hook\HostActionsHook as BaseHook; /** - * Base class for TimeLine providers + * Compat only + * + * Please implement hooks in our Hook direcory */ -abstract class TimelineProviderHook -{ - /** - * Return the names by which to group entries - * - * @return array An array with the names as keys and their attribute-lists as values - */ - abstract public function getIdentifiers(); - - /** - * Return the visible entries supposed to be shown on the timeline - * - * @param TimeRange $range The range of time for which to fetch entries - * - * @return array The entries to display on the timeline - */ - abstract public function fetchEntries(TimeRange $range); - - /** - * Return the entries supposed to be used to calculate forecasts - * - * @param TimeRange $range The range of time for which to fetch forecasts - * - * @return array The entries to calculate forecasts with - */ - abstract public function fetchForecasts(TimeRange $range); -} +abstract class TimelineProviderHook extends BaseHook {} From dc3c7874462f1b70ac19f1aff72f28b55579314a Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 12 Nov 2015 18:17:33 +0100 Subject: [PATCH 05/22] Compat Hooks: fix c&p error --- .../library/Monitoring/Web/Hook/ServiceActionsHook.php | 2 +- .../library/Monitoring/Web/Hook/TimelineProviderHook.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/monitoring/library/Monitoring/Web/Hook/ServiceActionsHook.php b/modules/monitoring/library/Monitoring/Web/Hook/ServiceActionsHook.php index 25ec269f0..b118f8d58 100644 --- a/modules/monitoring/library/Monitoring/Web/Hook/ServiceActionsHook.php +++ b/modules/monitoring/library/Monitoring/Web/Hook/ServiceActionsHook.php @@ -3,7 +3,7 @@ namespace Icinga\Module\Monitoring\Web\Hook; -use Icinga\Module\Monitoring\Hook\HostActionsHook as BaseHook; +use Icinga\Module\Monitoring\Hook\ServiceActionsHook as BaseHook; /** * Compat only diff --git a/modules/monitoring/library/Monitoring/Web/Hook/TimelineProviderHook.php b/modules/monitoring/library/Monitoring/Web/Hook/TimelineProviderHook.php index 265e6894d..ba01d1e03 100644 --- a/modules/monitoring/library/Monitoring/Web/Hook/TimelineProviderHook.php +++ b/modules/monitoring/library/Monitoring/Web/Hook/TimelineProviderHook.php @@ -3,7 +3,7 @@ namespace Icinga\Module\Monitoring\Web\Hook; -use Icinga\Module\Monitoring\Hook\HostActionsHook as BaseHook; +use Icinga\Module\Monitoring\Hook\TimelineProviderHook as BaseHook; /** * Compat only From a24bf32c5b1217ddad76defea692ad18eab5fae4 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 12 Nov 2015 18:30:18 +0100 Subject: [PATCH 06/22] Hook: allow hooks for old modules Web\Hooks refs #10613 --- library/Icinga/Application/Hook.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/Icinga/Application/Hook.php b/library/Icinga/Application/Hook.php index e3ef616a8..ed38a7fe8 100644 --- a/library/Icinga/Application/Hook.php +++ b/library/Icinga/Application/Hook.php @@ -155,6 +155,20 @@ class Hook } if (!$instance instanceof $base_class) { + + // This is a compatibility check. Should be removed one far day: + if ($module !== null) { + $compat_class = 'Icinga\\Module\\' + . ucfirst($module) + . '\\Web\\Hook\\' + . ucfirst($name) + . $suffix; + + if ($instance instanceof $compat_class) { + return; + } + } + throw new ProgrammingError( '%s is not an instance of %s', get_class($instance), From 54db2c9afa17b4bdf7b07396e8fcd7fad1afb38e Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 12 Nov 2015 18:33:51 +0100 Subject: [PATCH 07/22] Module::registerHook: use class as default key refs #9685 --- library/Icinga/Application/Modules/Module.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index 737e5265e..1d1331524 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -1239,7 +1239,7 @@ class Module protected function registerHook($name, $class, $key = null) { if ($key === null) { - $key = $this->name; + $key = $class; } Hook::register($name, $key, $class); From b66e4dfdf278be3b9fc29d6a2a0fc0c2a97fa5fc Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 12 Nov 2015 18:34:25 +0100 Subject: [PATCH 08/22] Module: use Application\Hook instead of Web\Hook --- library/Icinga/Application/Modules/Module.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index 1d1331524..e8c99ad56 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -19,7 +19,7 @@ use Icinga\Module\Setup\SetupWizard; use Icinga\Util\File; use Icinga\Util\Translator; use Icinga\Web\Controller\Dispatcher; -use Icinga\Web\Hook; +use Icinga\Application\Hook; use Icinga\Web\Navigation\Navigation; use Icinga\Web\Widget; From 997c5a0a135b1f0d7bbc08d32c76933789841bdc Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 12 Nov 2015 19:52:20 +0100 Subject: [PATCH 09/22] Hook: normalize names --- library/Icinga/Application/Hook.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/library/Icinga/Application/Hook.php b/library/Icinga/Application/Hook.php index ed38a7fe8..3c3cb0cc8 100644 --- a/library/Icinga/Application/Hook.php +++ b/library/Icinga/Application/Hook.php @@ -68,9 +68,24 @@ class Hook */ public static function has($name) { + $name = self::normalizeHookName($name); return array_key_exists($name, self::$hooks); } + protected static function normalizeHookName($name) + { + if (strpos($name, '\\') === false) { + $parts = explode('/', $name); + foreach ($parts as & $part) { + $part = ucfirst($part); + } + + return implode('\\', $parts); + } + + return $name; + } + /** * Create or return an instance of a given hook * @@ -83,6 +98,8 @@ class Hook */ public static function createInstance($name, $key) { + $name = self::normalizeHookName($name); + if (!self::has($name, $key)) { return null; } @@ -134,6 +151,8 @@ class Hook */ private static function assertValidHook($instance, $name) { + $name = self::normalizeHookName($name); + $suffix = self::$classSuffix; // 'Hook' $base = self::$BASE_NS; // 'Icinga\\Web\\Hook\\' @@ -208,6 +227,8 @@ class Hook */ public static function first($name) { + $name = self::normalizeHookName($name); + if (self::has($name)) { return self::createInstance($name, key(self::$hooks[$name])); } @@ -223,6 +244,8 @@ class Hook */ public static function register($name, $key, $class) { + $name = self::normalizeHookName($name); + if (!isset(self::$hooks[$name])) { self::$hooks[$name] = array(); } From b7189382fb8055140deac3a831b913c5a38db2f6 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 12 Nov 2015 19:52:51 +0100 Subject: [PATCH 10/22] Module: add getNamespace() method --- library/Icinga/Application/Modules/Module.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index e8c99ad56..2090ab51f 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -590,6 +590,16 @@ class Module return $this->name; } + /** + * Get the module namespace + * + * @return string + */ + public function getNamespace() + { + return 'Icinga\\Module\\' . ucfirst($this->getName()); + } + /** * Get the module version * From 380f11d9c2750a0657c0239a4583a3ed6b11e92e Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Thu, 12 Nov 2015 19:53:23 +0100 Subject: [PATCH 11/22] Module: add new provideHook method --- library/Icinga/Application/Modules/Module.php | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index 2090ab51f..5f91b0891 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -1248,12 +1248,35 @@ class Module */ protected function registerHook($name, $class, $key = null) { - if ($key === null) { - $key = $class; + return $this->provideHook($name, $class, $key); + } + + protected function slashesToNamespace($class) + { + $list = explode('/', $class); + foreach ($list as &$part) { + $part = ucfirst($part); } - Hook::register($name, $key, $class); + return implode('\\', $list); + } + // deprecate $key + protected function provideHook($name, $implementation = null, $key = null) + { + if ($implementation === null) { + $implementation = $name; + } + + if (strpos($implementation, '\\') === false) { + $class = $this->getNamespace() + . '\\Hook\\' + . $this->slashesToNamespace($implementation); + } else { + $class = $implementation; + } + + Hook::register($name, $implementation, $class); return $this; } From 8fa33cebc7e1e587ba4e188a6a186f40914d4180 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 13 Nov 2015 14:27:46 +0100 Subject: [PATCH 12/22] Hook: normalize names also for all() --- library/Icinga/Application/Hook.php | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Icinga/Application/Hook.php b/library/Icinga/Application/Hook.php index 3c3cb0cc8..ed11cf458 100644 --- a/library/Icinga/Application/Hook.php +++ b/library/Icinga/Application/Hook.php @@ -205,6 +205,7 @@ class Hook */ public static function all($name) { + $name = self::normalizeHookName($name); if (!self::has($name)) { return array(); } From 4b9607ad352d39536f3adc85c6c40ceb729ee6c6 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 13 Nov 2015 14:28:09 +0100 Subject: [PATCH 13/22] Module: we want to load from ProvidedHook refs #10613 --- library/Icinga/Application/Modules/Module.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Icinga/Application/Modules/Module.php b/library/Icinga/Application/Modules/Module.php index 5f91b0891..02c718eb3 100644 --- a/library/Icinga/Application/Modules/Module.php +++ b/library/Icinga/Application/Modules/Module.php @@ -1270,7 +1270,7 @@ class Module if (strpos($implementation, '\\') === false) { $class = $this->getNamespace() - . '\\Hook\\' + . '\\ProvidedHook\\' . $this->slashesToNamespace($implementation); } else { $class = $implementation; From f3cb1f915d5abd43f5c70b622e22ebfa8218a53a Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 13 Nov 2015 14:33:32 +0100 Subject: [PATCH 14/22] Monitoring/DataView: allow to hook in columns --- .../library/Monitoring/DataView/DataView.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/monitoring/library/Monitoring/DataView/DataView.php b/modules/monitoring/library/Monitoring/DataView/DataView.php index 50cd436fd..2afb046d5 100644 --- a/modules/monitoring/library/Monitoring/DataView/DataView.php +++ b/modules/monitoring/library/Monitoring/DataView/DataView.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Monitoring\DataView; use IteratorAggregate; +use Icinga\Application\Hook; use Icinga\Data\ConnectionInterface; use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\FilterMatch; @@ -122,6 +123,18 @@ abstract class DataView implements QueryInterface, SortRules, FilterColumns, Ite return $view; } + protected function getHookedColumns() + { + $columns = array(); + foreach (Hook::all('monitoring/dataviewExtension') as $hook) { + foreach ($hook->getAdditionalQueryColumns($this->getQueryName()) as $col) { + $columns[] = $col; + } + } + + return $columns; + } + // TODO: This is not the right place for this, move it away protected function applyUrlFilter($request = null) { From 35d3342b0557f8b2cf8dfe45df6491da5e76c828 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 13 Nov 2015 15:03:08 +0100 Subject: [PATCH 15/22] DataviewExtensionHook: just a new hook --- .../library/Monitoring/Hook/DataviewExtensionHook.php | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php diff --git a/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php b/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php new file mode 100644 index 000000000..61b46a81b --- /dev/null +++ b/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php @@ -0,0 +1,9 @@ + Date: Fri, 13 Nov 2015 15:09:15 +0100 Subject: [PATCH 16/22] DataviewExtensionHook: we always want an array This way implementors do not need to care --- .../library/Monitoring/Hook/DataviewExtensionHook.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php b/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php index 61b46a81b..cb0269219 100644 --- a/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php +++ b/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php @@ -5,5 +5,12 @@ namespace Icinga\Module\Monitoring\Hook; abstract class DataviewExtensionHook { - abstract public function getAdditionalQueryColumns($queryName); + public function getAdditionalQueryColumns($queryName) + { + $cols = $this->provideAdditionalQueryColumns($queryName); + + return $cols; + } + + abstract public function provideAdditionalQueryColumns($queryName); } From 0e709d5469574f779dc3065cf158aad7ddf7d9a6 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 13 Nov 2015 15:09:54 +0100 Subject: [PATCH 17/22] DataViewHost/Servicestatus: use hooked columns --- modules/monitoring/library/Monitoring/DataView/Hoststatus.php | 4 ++-- .../monitoring/library/Monitoring/DataView/Servicestatus.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/monitoring/library/Monitoring/DataView/Hoststatus.php b/modules/monitoring/library/Monitoring/DataView/Hoststatus.php index 0ab9dd92e..220ce2226 100644 --- a/modules/monitoring/library/Monitoring/DataView/Hoststatus.php +++ b/modules/monitoring/library/Monitoring/DataView/Hoststatus.php @@ -10,7 +10,7 @@ class HostStatus extends DataView */ public function getColumns() { - return array( + return array_merge($this->getHookedColumns(), array( 'instance_name', 'host_name', 'host_display_name', @@ -63,7 +63,7 @@ class HostStatus extends DataView 'host_problem', 'host_ipv4', 'host_acknowledgement_type' - ); + )); } /** diff --git a/modules/monitoring/library/Monitoring/DataView/Servicestatus.php b/modules/monitoring/library/Monitoring/DataView/Servicestatus.php index db44f62c6..389bc9ae0 100644 --- a/modules/monitoring/library/Monitoring/DataView/Servicestatus.php +++ b/modules/monitoring/library/Monitoring/DataView/Servicestatus.php @@ -10,7 +10,7 @@ class ServiceStatus extends DataView */ public function getColumns() { - return array( + return array_merge($this->getHookedColumns(), array( 'instance_name', 'host_name', 'host_display_name', @@ -98,7 +98,7 @@ class ServiceStatus extends DataView 'service_modified_service_attributes', 'service_host_name', 'service_acknowledgement_type', - ); + )); } /** From 6394cec9337d55013958ca9b62dfcd0458edb7a5 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 13 Nov 2015 15:12:30 +0100 Subject: [PATCH 18/22] DataviewExtensionHook: return fetched columns --- .../library/Monitoring/Hook/DataviewExtensionHook.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php b/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php index cb0269219..c50d1d747 100644 --- a/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php +++ b/modules/monitoring/library/Monitoring/Hook/DataviewExtensionHook.php @@ -9,6 +9,10 @@ abstract class DataviewExtensionHook { $cols = $this->provideAdditionalQueryColumns($queryName); + if (! is_array($cols)) { + return array(); + } + return $cols; } From b7352105d287f5799d42899e8923b59047de080f Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 13 Nov 2015 16:48:06 +0100 Subject: [PATCH 19/22] IdoQueryExtensionHook: "just a new hook" --- .../Monitoring/Backend/Ido/Query/IdoQuery.php | 58 ++++++++++++++++++- .../Monitoring/Hook/IdoQueryExtensionHook.php | 15 +++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 modules/monitoring/library/Monitoring/Hook/IdoQueryExtensionHook.php diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php index 5edc8f6f1..bbaae6fb1 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Monitoring\Backend\Ido\Query; use Zend_Db_Expr; use Icinga\Application\Icinga; +use Icinga\Application\Hook; use Icinga\Application\Logger; use Icinga\Data\Db\DbQuery; use Icinga\Data\Filter\Filter; @@ -119,6 +120,15 @@ abstract class IdoQuery extends DbQuery */ protected $joinedVirtualTables = array(); + /** + * A map of virtual table names and corresponding hook instances + * + * Joins for those tables will be delegated to them + * + * @var array + */ + protected $hookedVirtualTables = array(); + /** * List of column aliases used for sorting the result * @@ -593,6 +603,18 @@ abstract class IdoQuery extends DbQuery return isset($this->caseInsensitiveColumns[$table][$alias]); } + /** + * Return our column map + * + * Might be useful for hooks + * + * @return array + */ + public function getColumnMap() + { + return $this->columnMap; + } + /** * Apply oracle specific query initialization */ @@ -651,6 +673,23 @@ abstract class IdoQuery extends DbQuery { parent::init(); $this->prefix = $this->ds->getTablePrefix(); + + foreach (Hook::all('monitoring/idoQueryExtension') as $hook) { + $extensions = $hook->extendColumnMap($this); + if (! is_array($extensions)) continue; + + foreach ($extensions as $vTable => $cols) { + if (! array_key_exists($vTable, $this->columnMap)) { + $this->hookedVirtualTables[$vTable] = $hook; + $this->columMap[$vTable] = array(); + } + + foreach ($cols as $k => $v) { + $this->columnMap[$vTable][$k] = $v; + } + } + } + $dbType = $this->ds->getDbType(); if ($dbType === 'oracle') { $this->initializeForOracle(); @@ -787,7 +826,24 @@ abstract class IdoQuery extends DbQuery if ($this->hasJoinedVirtualTable($name)) { return $this; } - return $this->joinVirtualTable($name); + + if ($this->virtualTableIsHooked($name)) { + return $this->joinHookedVirtualTable($name); + } else { + return $this->joinVirtualTable($name); + } + } + + /** + * Whether a given virtual table name has been provided by a hook + * + * @param string $name Virtual table name + * + * @return boolean + */ + protected function virtualTableIsHooked($name) + { + return array_key_exists($name, $this->hookedVirtualTables); } protected function conflictsWithVirtualTable($name) diff --git a/modules/monitoring/library/Monitoring/Hook/IdoQueryExtensionHook.php b/modules/monitoring/library/Monitoring/Hook/IdoQueryExtensionHook.php new file mode 100644 index 000000000..ea7f663f1 --- /dev/null +++ b/modules/monitoring/library/Monitoring/Hook/IdoQueryExtensionHook.php @@ -0,0 +1,15 @@ + Date: Fri, 13 Nov 2015 17:04:56 +0100 Subject: [PATCH 20/22] IdoQuery::joinHookedVirtualTable: missing method --- .../Monitoring/Backend/Ido/Query/IdoQuery.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php index bbaae6fb1..d39effc0f 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php @@ -882,6 +882,19 @@ abstract class IdoQuery extends DbQuery return $this; } + /** + * Tell a hook to join a virtual table + * + * @param String $table + * @return $this + */ + protected function joinHookedVirtualTable($table) + { + $this->hookedVirtualTable[$table]->joinVirtualTable($table); + $this->joinedVirtualTables[$table] = true; + return $this; + } + /** * Get the table for a specific alias * From cd16206c7e6b3d7dc81deb83091cc9933606322b Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 13 Nov 2015 17:24:14 +0100 Subject: [PATCH 21/22] IdoQuery: fix typo --- .../library/Monitoring/Backend/Ido/Query/IdoQuery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php index d39effc0f..a38371c19 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php @@ -890,7 +890,7 @@ abstract class IdoQuery extends DbQuery */ protected function joinHookedVirtualTable($table) { - $this->hookedVirtualTable[$table]->joinVirtualTable($table); + $this->hookedVirtualTables[$table]->joinVirtualTable($table); $this->joinedVirtualTables[$table] = true; return $this; } From fd7165329a3129102b717995378728fffe6f8e43 Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 13 Nov 2015 17:25:04 +0100 Subject: [PATCH 22/22] IdoQuery: provide ourselves to the hook --- .../library/Monitoring/Backend/Ido/Query/IdoQuery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php index a38371c19..f615ece11 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/IdoQuery.php @@ -828,7 +828,7 @@ abstract class IdoQuery extends DbQuery } if ($this->virtualTableIsHooked($name)) { - return $this->joinHookedVirtualTable($name); + return $this->joinHookedVirtualTable($this, $name); } else { return $this->joinVirtualTable($name); }