diff --git a/application/forms/RedisConfigForm.php b/application/forms/RedisConfigForm.php index 88b2f48f..1786c03d 100644 --- a/application/forms/RedisConfigForm.php +++ b/application/forms/RedisConfigForm.php @@ -20,8 +20,6 @@ use Zend_Validate_Callback; class RedisConfigForm extends ConfigForm { - use IcingaRedis; - public function init() { $this->setSubmitLabel(t('Save Changes')); @@ -482,7 +480,7 @@ class RedisConfigForm extends ConfigForm $redisConfig->setSection('redis2', $sections['redis2'] ?? []); try { - $redis1 = $form->getPrimaryRedis($moduleConfig, $redisConfig); + $redis1 = IcingaRedis::getPrimaryRedis($moduleConfig, $redisConfig); } catch (Exception $e) { $form->warning(sprintf( t('Failed to connect to primary Redis: %s'), @@ -491,19 +489,19 @@ class RedisConfigForm extends ConfigForm return false; } - if ($form->getLastIcingaHeartbeat($redis1) === null) { + if (IcingaRedis::getLastIcingaHeartbeat($redis1) === null) { $form->warning(t('Primary connection established but failed to verify Icinga is connected as well.')); return false; } try { - $redis2 = $form->getSecondaryRedis($moduleConfig, $redisConfig); + $redis2 = IcingaRedis::getSecondaryRedis($moduleConfig, $redisConfig); } catch (Exception $e) { $form->warning(sprintf(t('Failed to connect to secondary Redis: %s'), $e->getMessage())); return false; } - if ($redis2 !== null && $form->getLastIcingaHeartbeat($redis2) === null) { + if ($redis2 !== null && IcingaRedis::getLastIcingaHeartbeat($redis2) === null) { $form->warning(t('Secondary connection established but failed to verify Icinga is connected as well.')); return false; } diff --git a/library/Icingadb/Common/IcingaRedis.php b/library/Icingadb/Common/IcingaRedis.php index 85d3b484..8ff58fa8 100644 --- a/library/Icingadb/Common/IcingaRedis.php +++ b/library/Icingadb/Common/IcingaRedis.php @@ -8,11 +8,28 @@ use Exception; use Icinga\Application\Config; use Predis\Client as Redis; -trait IcingaRedis +class IcingaRedis { + /** @var static The singleton */ + protected static $instance; + /** @var Redis Connection to the Icinga Redis */ private $redis; + /** + * Get the singleton + * + * @return static + */ + public static function instance(): self + { + if (self::$instance === null) { + self::$instance = new static(); + } + + return self::$instance; + } + /** * Get the connection to the Icinga Redis * @@ -20,7 +37,7 @@ trait IcingaRedis * * @throws Exception */ - public function getIcingaRedis() + public function getConnection() { if ($this->redis === null) { try { @@ -63,8 +80,12 @@ trait IcingaRedis return $this->redis; } - public function getLastIcingaHeartbeat(Redis $redis) + public static function getLastIcingaHeartbeat(Redis $redis = null) { + if ($redis === null) { + $redis = self::instance()->getConnection(); + } + // Predis doesn't support streams (yet). // https://github.com/predis/predis/issues/607#event-3640855190 $rs = $redis->executeRaw(['XREAD', 'COUNT', '1', 'STREAMS', 'icinga:stats', '0']); @@ -90,7 +111,7 @@ trait IcingaRedis return null; } - public function getPrimaryRedis(Config $moduleConfig = null, Config $redisConfig = null) + public static function getPrimaryRedis(Config $moduleConfig = null, Config $redisConfig = null) { if ($moduleConfig === null) { $moduleConfig = Config::module('icingadb'); @@ -106,14 +127,14 @@ trait IcingaRedis 'host' => $section->get('host', 'localhost'), 'port' => $section->get('port', 6380), 'timeout' => 0.5 - ] + $this->getTlsParams($moduleConfig)); + ] + static::getTlsParams($moduleConfig)); $redis->ping(); return $redis; } - public function getSecondaryRedis(Config $moduleConfig = null, Config $redisConfig = null) + public static function getSecondaryRedis(Config $moduleConfig = null, Config $redisConfig = null) { if ($moduleConfig === null) { $moduleConfig = Config::module('redis'); @@ -134,14 +155,14 @@ trait IcingaRedis 'host' => $host, 'port' => $section->get('port', 6380), 'timeout' => 0.5 - ] + $this->getTlsParams($moduleConfig)); + ] + static::getTlsParams($moduleConfig)); $redis->ping(); return $redis; } - private function getTlsParams(Config $config) + private static function getTlsParams(Config $config) { $config = $config->getSection('redis'); diff --git a/library/Icingadb/Common/ObjectInspectionDetail.php b/library/Icingadb/Common/ObjectInspectionDetail.php index a4935e9f..b3925472 100644 --- a/library/Icingadb/Common/ObjectInspectionDetail.php +++ b/library/Icingadb/Common/ObjectInspectionDetail.php @@ -22,8 +22,6 @@ use ipl\Orm\Model; abstract class ObjectInspectionDetail extends BaseHtmlElement { - use IcingaRedis; - protected $tag = 'div'; protected $defaultAttributes = ['class' => ['object-detail', 'inspection-detail']]; @@ -101,7 +99,7 @@ abstract class ObjectInspectionDetail extends BaseHtmlElement $title = new HtmlElement('h2', null, Text::create(t('Volatile State Details'))); try { - $json = $this->getIcingaRedis() + $json = IcingaRedis::instance()->getConnection() ->hGet("icinga:{$this->object->getTableName()}:state", bin2hex($this->object->id)); } catch (Exception $e) { return [$title, sprintf('Failed to load redis data: %s', $e->getMessage())]; diff --git a/library/Icingadb/Model/Behavior/VolatileState.php b/library/Icingadb/Model/Behavior/VolatileState.php index 27eeef84..0a40bf44 100644 --- a/library/Icingadb/Model/Behavior/VolatileState.php +++ b/library/Icingadb/Model/Behavior/VolatileState.php @@ -12,14 +12,12 @@ use ipl\Orm\Model; class VolatileState implements RetrieveBehavior { - use IcingaRedis; - protected $state; protected function getVolatileState() { if ($this->state === null) { - $this->state = new RedisState($this->getIcingaRedis()); + $this->state = new RedisState(IcingaRedis::instance()->getConnection()); } return $this->state; diff --git a/library/Icingadb/ProvidedHook/ApplicationState.php b/library/Icingadb/ProvidedHook/ApplicationState.php index c3f10e6c..f05fa632 100644 --- a/library/Icingadb/ProvidedHook/ApplicationState.php +++ b/library/Icingadb/ProvidedHook/ApplicationState.php @@ -15,7 +15,6 @@ use ipl\Stdlib\Filter; class ApplicationState extends ApplicationStateHook { use Database; - use IcingaRedis; public function collectMessages() { @@ -52,11 +51,7 @@ class ApplicationState extends ApplicationStateHook $outdatedDbHeartbeat = $instance->heartbeat < time() - 60; try { - $redis = $this->getIcingaRedis(); - - Session::getSession()->getNamespace('icingadb')->delete('redis.down-since'); - - $lastIcingaHeartbeat = $this->getLastIcingaHeartbeat($redis); + $lastIcingaHeartbeat = IcingaRedis::getLastIcingaHeartbeat(); if ($lastIcingaHeartbeat === null) { $missingSince = Session::getSession() ->getNamespace('icingadb')->get('redis.heartbeat-missing-since'); @@ -93,6 +88,8 @@ class ApplicationState extends ApplicationStateHook break; } + + Session::getSession()->getNamespace('icingadb')->delete('redis.down-since'); } catch (Exception $e) { $downSince = Session::getSession()->getNamespace('icingadb')->get('redis.down-since'); diff --git a/library/Icingadb/ProvidedHook/RedisHealth.php b/library/Icingadb/ProvidedHook/RedisHealth.php index defb50c9..ad8f8f59 100644 --- a/library/Icingadb/ProvidedHook/RedisHealth.php +++ b/library/Icingadb/ProvidedHook/RedisHealth.php @@ -13,7 +13,6 @@ use Icinga\Module\Icingadb\Model\Instance; class RedisHealth extends HealthHook { use Database; - use IcingaRedis; public function getName() { @@ -23,9 +22,7 @@ class RedisHealth extends HealthHook public function checkHealth() { try { - $redis = $this->getIcingaRedis(); - - $lastIcingaHeartbeat = $this->getLastIcingaHeartbeat($redis); + $lastIcingaHeartbeat = IcingaRedis::getLastIcingaHeartbeat(); if ($lastIcingaHeartbeat === null) { $lastIcingaHeartbeat = time(); } diff --git a/library/Icingadb/Setup/RedisPage.php b/library/Icingadb/Setup/RedisPage.php index 66c1b1ac..3c0a7413 100644 --- a/library/Icingadb/Setup/RedisPage.php +++ b/library/Icingadb/Setup/RedisPage.php @@ -4,14 +4,11 @@ namespace Icinga\Module\Icingadb\Setup; -use Icinga\Module\Icingadb\Common\IcingaRedis; use Icinga\Module\Icingadb\Forms\RedisConfigForm; use Icinga\Web\Form; class RedisPage extends Form { - use IcingaRedis; - public function init() { $this->setName('setup_icingadb_redis');