mirror of
https://github.com/Icinga/icingadb-web.git
synced 2026-05-28 04:36:06 -04:00
This was easy because only README.md and doc/01-About.md were redacted manually, everything else via: git ls-files -z |xargs -0 perl -pi -e 's/Icinga GmbH \| GPLv2/Icinga GmbH | GPLv2+/' This is legal because we have only merged PRs with label:cla/signed or made by Icinga staff: https://github.com/Icinga/icingadb-web/pulls?page=1&q=is%3Apr+is%3Aclosed+-label%3Acla%2Fsigned+-author%3Anilmerg This has no risk for us in people distributing their own version under GPLv3 only. After all, we won't take their patches anyway, unless they sign our CLA. This is the cleanest solution for having e.g. these in one address space: * Icinga Web, GPLv2+ * K8s Web, AGPLv3 * Thirdparty, some LGPLv3 and Apache-2.0 Apropos, K8s Web is even v3-licensed on purpose, to have a stronger protection against cloud ops.
719 lines
26 KiB
PHP
719 lines
26 KiB
PHP
<?php
|
|
|
|
/* Icinga DB Web | (c) 2020 Icinga GmbH | GPLv2+ */
|
|
|
|
namespace Icinga\Module\Icingadb\Forms;
|
|
|
|
use Closure;
|
|
use Exception;
|
|
use Icinga\Application\Config;
|
|
use Icinga\Application\Icinga;
|
|
use Icinga\Application\Logger;
|
|
use Icinga\Exception\AlreadyExistsException;
|
|
use Icinga\Exception\IcingaException;
|
|
use Icinga\Exception\NotWritableError;
|
|
use Icinga\File\Storage\LocalFileStorage;
|
|
use Icinga\File\Storage\TemporaryLocalFileStorage;
|
|
use Icinga\Forms\ConfigForm;
|
|
use Icinga\Module\Icingadb\Common\IcingaRedis;
|
|
use Icinga\Web\Form;
|
|
use ipl\Validator\PrivateKeyValidator;
|
|
use ipl\Validator\X509CertValidator;
|
|
use Throwable;
|
|
use Zend_Config_Exception;
|
|
use Zend_Form_Decorator_Abstract;
|
|
use Zend_Validate_Callback;
|
|
|
|
class RedisConfigForm extends ConfigForm
|
|
{
|
|
public function init()
|
|
{
|
|
$this->setSubmitLabel(t('Save Changes'));
|
|
$this->setValidatePartial(true);
|
|
}
|
|
|
|
public function createElements(array $formData)
|
|
{
|
|
$this->addElement('checkbox', 'redis_tls', [
|
|
'label' => t('Use TLS'),
|
|
'description' => t('Encrypt connections to Redis via TLS'),
|
|
'autosubmit' => true
|
|
]);
|
|
|
|
$this->addElement('hidden', 'redis_ca');
|
|
$this->addElement('hidden', 'redis_cert');
|
|
$this->addElement('hidden', 'redis_key');
|
|
$this->addElement('hidden', 'clear_redis_ca', ['ignore' => true]);
|
|
$this->addElement('hidden', 'clear_redis_cert', ['ignore' => true]);
|
|
$this->addElement('hidden', 'clear_redis_key', ['ignore' => true]);
|
|
|
|
$useTls = isset($formData['redis_tls']) && $formData['redis_tls'];
|
|
if ($useTls) {
|
|
$this->addElement('textarea', 'redis_ca_pem', [
|
|
'label' => t('Redis CA Certificate'),
|
|
'description' => sprintf(
|
|
t('Verify the peer using this PEM-encoded CA certificate ("%s...")'),
|
|
'-----BEGIN CERTIFICATE-----'
|
|
),
|
|
'required' => true,
|
|
'ignore' => true,
|
|
'validators' => [$this->wrapIplValidator(X509CertValidator::class, 'redis_ca_pem')]
|
|
]);
|
|
|
|
$this->addElement('textarea', 'redis_cert_pem', [
|
|
'label' => t('Client Certificate'),
|
|
'description' => sprintf(
|
|
t('Authenticate using this PEM-encoded client certificate ("%s...")'),
|
|
'-----BEGIN CERTIFICATE-----'
|
|
),
|
|
'ignore' => true,
|
|
'allowEmpty' => false,
|
|
'validators' => [
|
|
$this->wrapIplValidator(X509CertValidator::class, 'redis_cert_pem', function ($value) {
|
|
if (! $value && $this->getElement('redis_key_pem')->getValue()) {
|
|
$this->getElement('redis_cert_pem')->addError(t(
|
|
'Either both a client certificate and its private key or none of them must be specified'
|
|
));
|
|
}
|
|
|
|
return true;
|
|
})
|
|
]
|
|
]);
|
|
|
|
$this->addElement('textarea', 'redis_key_pem', [
|
|
'label' => t('Client Key'),
|
|
'description' => sprintf(
|
|
t('Authenticate using this PEM-encoded private key ("%s...")'),
|
|
'-----BEGIN PRIVATE KEY-----'
|
|
),
|
|
'ignore' => true,
|
|
'allowEmpty' => false,
|
|
'validators' => [
|
|
$this->wrapIplValidator(PrivateKeyValidator::class, 'redis_key_pem', function ($value) {
|
|
if (! $value && $this->getElement('redis_cert_pem')->getValue()) {
|
|
$this->getElement('redis_key_pem')->addError(t(
|
|
'Either both a client certificate and its private key or none of them must be specified'
|
|
));
|
|
}
|
|
|
|
return true;
|
|
})
|
|
]
|
|
]);
|
|
}
|
|
|
|
$this->addDisplayGroup(
|
|
['redis_tls', 'redis_insecure', 'redis_ca_pem', 'redis_cert_pem', 'redis_key_pem'],
|
|
'redis',
|
|
[
|
|
'decorators' => [
|
|
'FormElements',
|
|
['HtmlTag', ['tag' => 'div']],
|
|
[
|
|
'Description',
|
|
['tag' => 'span', 'class' => 'description', 'placement' => 'prepend']
|
|
],
|
|
'Fieldset'
|
|
],
|
|
'description' => t(
|
|
'Secure connections. If you are running a high availability zone'
|
|
. ' with two masters, the following applies to both of them.'
|
|
),
|
|
'legend' => t('General')
|
|
]
|
|
);
|
|
|
|
if (isset($formData['skip_validation']) && $formData['skip_validation']) {
|
|
// In case another error occured and the checkbox was displayed before
|
|
static::addSkipValidationCheckbox($this);
|
|
}
|
|
|
|
if ($useTls && isset($formData['redis_insecure']) && $formData['redis_insecure']) {
|
|
// In case another error occured and the checkbox was displayed before
|
|
static::addInsecureCheckboxIfTls($this);
|
|
}
|
|
|
|
$redisPortDescription = t(sprintf(
|
|
"Defaults to %d as the Redis® open source server provided by"
|
|
. ' the "icingadb-redis" package listens on that port.',
|
|
IcingaRedis::DEFAULT_PORT
|
|
));
|
|
$redisDatabaseDescription = t(sprintf(
|
|
"Numerical database identifier, defaults to %d. This only needs to be changed"
|
|
. ' if Icinga 2 is configured to write to another database index.',
|
|
IcingaRedis::DEFAULT_DATABASE
|
|
));
|
|
$redisUsernameDescription = t(
|
|
'Authentication username, requires a password being set as well. This field is necessary when'
|
|
. ' connecting to a redis instance that requires authentication beyond the default user.'
|
|
);
|
|
$redisPasswordDescription = t(
|
|
'Authentication password. May be used alone when logging in as the'
|
|
. ' default user or together with a username.'
|
|
);
|
|
|
|
$this->addElement('text', 'redis1_host', [
|
|
'description' => t('Redis Host'),
|
|
'label' => t('Redis Host'),
|
|
'required' => true
|
|
]);
|
|
|
|
$this->addElement('number', 'redis1_port', [
|
|
'description' => $redisPortDescription,
|
|
'label' => t('Redis Port'),
|
|
'placeholder' => IcingaRedis::DEFAULT_PORT
|
|
]);
|
|
|
|
$this->addElement('number', 'redis1_database', [
|
|
'description' => $redisDatabaseDescription,
|
|
'label' => t('Redis Database'),
|
|
'placeholder' => IcingaRedis::DEFAULT_DATABASE
|
|
]);
|
|
|
|
$this->addElement('text', 'redis1_username', [
|
|
'description' => $redisUsernameDescription,
|
|
'label' => t('Redis Username')
|
|
]);
|
|
|
|
$this->addElement('password', 'redis1_password', [
|
|
'description' => $redisPasswordDescription,
|
|
'label' => t('Redis Password'),
|
|
'renderPassword' => true,
|
|
'autocomplete' => 'new-password'
|
|
]);
|
|
|
|
$this->addDisplayGroup(
|
|
['redis1_host', 'redis1_port', 'redis1_database', 'redis1_username', 'redis1_password'],
|
|
'redis1',
|
|
[
|
|
'decorators' => [
|
|
'FormElements',
|
|
['HtmlTag', ['tag' => 'div']],
|
|
[
|
|
'Description',
|
|
['tag' => 'span', 'class' => 'description', 'placement' => 'prepend']
|
|
],
|
|
'Fieldset'
|
|
],
|
|
'description' => t(
|
|
'Redis connection details of your Icinga host. If you are running a high'
|
|
. ' availability zone with two masters, this is your configuration master.'
|
|
),
|
|
'legend' => t('Primary Icinga Master')
|
|
]
|
|
);
|
|
|
|
$this->addElement('text', 'redis2_host', [
|
|
'description' => t('Redis Host'),
|
|
'label' => t('Redis Host'),
|
|
]);
|
|
|
|
$this->addElement('number', 'redis2_port', [
|
|
'description' => $redisPortDescription,
|
|
'label' => t('Redis Port'),
|
|
'placeholder' => IcingaRedis::DEFAULT_PORT
|
|
]);
|
|
|
|
$this->addElement('number', 'redis2_database', [
|
|
'description' => $redisDatabaseDescription,
|
|
'label' => t('Redis Database'),
|
|
'placeholder' => IcingaRedis::DEFAULT_DATABASE
|
|
]);
|
|
|
|
$this->addElement('text', 'redis2_username', [
|
|
'description' => $redisUsernameDescription,
|
|
'label' => t('Redis Username')
|
|
]);
|
|
|
|
$this->addElement('password', 'redis2_password', [
|
|
'description' => $redisPasswordDescription,
|
|
'label' => t('Redis Password'),
|
|
'renderPassword' => true,
|
|
'autocomplete' => 'new-password'
|
|
]);
|
|
|
|
$this->addDisplayGroup(
|
|
['redis2_host', 'redis2_port', 'redis2_database', 'redis2_username', 'redis2_password'],
|
|
'redis2',
|
|
[
|
|
'decorators' => [
|
|
'FormElements',
|
|
['HtmlTag', ['tag' => 'div']],
|
|
[
|
|
'Description',
|
|
['tag' => 'span', 'class' => 'description', 'placement' => 'prepend']
|
|
],
|
|
'Fieldset'
|
|
],
|
|
'description' => t(
|
|
'If you are running a high availability zone with two masters,'
|
|
. ' please provide the Redis connection details of the secondary master.'
|
|
),
|
|
'legend' => t('Secondary Icinga Master')
|
|
]
|
|
);
|
|
}
|
|
|
|
public static function addSkipValidationCheckbox(Form $form)
|
|
{
|
|
$form->addElement(
|
|
'checkbox',
|
|
'skip_validation',
|
|
[
|
|
'order' => 0,
|
|
'ignore' => true,
|
|
'label' => t('Skip Validation'),
|
|
'description' => t(
|
|
'Check this box to enforce changes without validating that Redis is available.'
|
|
)
|
|
]
|
|
);
|
|
}
|
|
|
|
public static function addInsecureCheckboxIfTls(Form $form)
|
|
{
|
|
if ($form->getElement('redis_insecure') !== null) {
|
|
return;
|
|
}
|
|
|
|
$form->addElement(
|
|
'checkbox',
|
|
'redis_insecure',
|
|
[
|
|
'order' => 1,
|
|
'label' => t('Insecure'),
|
|
'description' => t('Don\'t verify the peer')
|
|
]
|
|
);
|
|
|
|
$displayGroup = $form->getDisplayGroup('redis');
|
|
$elements = $displayGroup->getElements();
|
|
$elements['redis_insecure'] = $form->getElement('redis_insecure');
|
|
$displayGroup->setElements($elements);
|
|
}
|
|
|
|
public function isValid($formData)
|
|
{
|
|
if (! parent::isValid($formData)) {
|
|
return false;
|
|
}
|
|
|
|
if (($el = $this->getElement('skip_validation')) === null || ! $el->isChecked()) {
|
|
if (! static::checkRedis($this)) {
|
|
if ($el === null) {
|
|
static::addSkipValidationCheckbox($this);
|
|
|
|
if ($this->getElement('redis_tls')->isChecked()) {
|
|
static::addInsecureCheckboxIfTls($this);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function isValidPartial(array $formData)
|
|
{
|
|
if (! parent::isValidPartial($formData)) {
|
|
return false;
|
|
}
|
|
|
|
$useTls = $this->getElement('redis_tls')->isChecked();
|
|
foreach (['ca', 'cert', 'key'] as $name) {
|
|
$textareaName = 'redis_' . $name . '_pem';
|
|
$clearName = 'clear_redis_' . $name;
|
|
|
|
if ($useTls) {
|
|
$this->getElement($clearName)->setValue(null);
|
|
|
|
$pemPath = $this->getValue('redis_' . $name);
|
|
if ($pemPath && ! isset($formData[$textareaName]) && ! $formData[$clearName]) {
|
|
$this->getElement($textareaName)->setValue(@file_get_contents($pemPath));
|
|
}
|
|
}
|
|
|
|
if (isset($formData[$textareaName]) && ! $formData[$textareaName]) {
|
|
$this->getElement($clearName)->setValue(true);
|
|
}
|
|
}
|
|
|
|
if ($this->getElement('backend_validation')->isChecked()) {
|
|
if (! static::checkRedis($this)) {
|
|
if ($this->getElement('redis_tls')->isChecked()) {
|
|
static::addInsecureCheckboxIfTls($this);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function onRequest()
|
|
{
|
|
$errors = [];
|
|
|
|
$redisConfig = $this->config->getSection('redis');
|
|
if ($redisConfig->get('tls', false)) {
|
|
foreach (['ca', 'cert', 'key'] as $name) {
|
|
$path = $redisConfig->get($name, '');
|
|
if (file_exists($path)) {
|
|
try {
|
|
$redisConfig[$name . '_pem'] = file_get_contents($path);
|
|
} catch (Exception $e) {
|
|
$errors['redis_' . $name . '_pem'] = sprintf(
|
|
t('Failed to read file "%s": %s'),
|
|
$path,
|
|
$e->getMessage()
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$connectionConfig = Config::fromIni(
|
|
join(DIRECTORY_SEPARATOR, [dirname($this->config->getConfigFile()), 'redis.ini'])
|
|
);
|
|
$this->config->setSection('redis1', [
|
|
'host' => $connectionConfig->get('redis1', 'host'),
|
|
'port' => $connectionConfig->get('redis1', 'port'),
|
|
'database' => $connectionConfig->get('redis1', 'database'),
|
|
'username' => $connectionConfig->get('redis1', 'username'),
|
|
'password' => $connectionConfig->get('redis1', 'password')
|
|
]);
|
|
$this->config->setSection('redis2', [
|
|
'host' => $connectionConfig->get('redis2', 'host'),
|
|
'port' => $connectionConfig->get('redis2', 'port'),
|
|
'database' => $connectionConfig->get('redis2', 'database'),
|
|
'username' => $connectionConfig->get('redis2', 'username'),
|
|
'password' => $connectionConfig->get('redis2', 'password')
|
|
]);
|
|
|
|
parent::onRequest();
|
|
|
|
foreach ($errors as $elementName => $message) {
|
|
$this->getElement($elementName)->addError($message);
|
|
}
|
|
}
|
|
|
|
public function onSuccess()
|
|
{
|
|
$storage = new LocalFileStorage(Icinga::app()->getStorageDir(
|
|
join(DIRECTORY_SEPARATOR, ['modules', 'icingadb', 'redis'])
|
|
));
|
|
|
|
$useTls = $this->getElement('redis_tls')->isChecked();
|
|
$pem = null;
|
|
foreach (['ca', 'cert', 'key'] as $name) {
|
|
$textarea = $this->getElement('redis_' . $name . '_pem');
|
|
if ($useTls && $textarea !== null && ($pem = $textarea->getValue())) {
|
|
$pemFile = md5($pem) . '-' . $name . '.pem';
|
|
if (! $storage->has($pemFile)) {
|
|
try {
|
|
$storage->create($pemFile, $pem);
|
|
} catch (NotWritableError $e) {
|
|
$textarea->addError($e->getMessage());
|
|
|
|
return false;
|
|
} catch (AlreadyExistsException $e) {
|
|
$textarea->addError($e->getMessage());
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$this->getElement('redis_' . $name)->setValue($storage->resolvePath($pemFile));
|
|
}
|
|
|
|
if ((! $useTls && $this->getElement('clear_redis_' . $name)->getValue()) || ($useTls && ! $pem)) {
|
|
$pemPath = $this->getValue('redis_' . $name);
|
|
if ($pemPath && $storage->has(($pemFile = basename($pemPath)))) {
|
|
try {
|
|
$storage->delete($pemFile);
|
|
$this->getElement('redis_' . $name)->setValue(null);
|
|
} catch (NotWritableError $e) {
|
|
$this->addError($e->getMessage());
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$connectionConfig = Config::fromIni(
|
|
join(DIRECTORY_SEPARATOR, [dirname($this->config->getConfigFile()), 'redis.ini'])
|
|
);
|
|
|
|
$redis1Host = $this->getValue('redis1_host');
|
|
$redis1Port = $this->getValue('redis1_port');
|
|
$redis1Database = $this->getValue('redis1_database');
|
|
$redis1Username = $this->getValue('redis1_username');
|
|
$redis1Password = $this->getValue('redis1_password');
|
|
$redis1Section = $connectionConfig->getSection('redis1');
|
|
$redis1Section['host'] = $redis1Host;
|
|
$this->getElement('redis1_host')->setValue(null);
|
|
$connectionConfig->setSection('redis1', $redis1Section);
|
|
if (! empty($redis1Port)) {
|
|
$redis1Section['port'] = $redis1Port;
|
|
$this->getElement('redis1_port')->setValue(null);
|
|
} else {
|
|
$redis1Section['port'] = null;
|
|
}
|
|
|
|
if (! empty($redis1Database)) {
|
|
$redis1Section['database'] = $redis1Database;
|
|
$this->getElement('redis1_database')->setValue(null);
|
|
} else {
|
|
$redis1Section['database'] = null;
|
|
}
|
|
|
|
if (! empty($redis1Username)) {
|
|
$redis1Section['username'] = $redis1Username;
|
|
$this->getElement('redis1_username')->setValue(null);
|
|
} else {
|
|
$redis1Section['username'] = null;
|
|
}
|
|
|
|
if (! empty($redis1Password)) {
|
|
$redis1Section['password'] = $redis1Password;
|
|
$this->getElement('redis1_password')->setValue(null);
|
|
} else {
|
|
$redis1Section['password'] = null;
|
|
}
|
|
|
|
if (! array_filter($redis1Section->toArray())) {
|
|
$connectionConfig->removeSection('redis1');
|
|
}
|
|
|
|
$redis2Host = $this->getValue('redis2_host');
|
|
$redis2Port = $this->getValue('redis2_port');
|
|
$redis2Database = $this->getValue('redis2_database');
|
|
$redis2Username = $this->getValue('redis2_username');
|
|
$redis2Password = $this->getValue('redis2_password');
|
|
$redis2Section = $connectionConfig->getSection('redis2');
|
|
if (! empty($redis2Host)) {
|
|
$redis2Section['host'] = $redis2Host;
|
|
$this->getElement('redis2_host')->setValue(null);
|
|
$connectionConfig->setSection('redis2', $redis2Section);
|
|
} else {
|
|
$redis2Section['host'] = null;
|
|
}
|
|
|
|
if (! empty($redis2Port)) {
|
|
$redis2Section['port'] = $redis2Port;
|
|
$this->getElement('redis2_port')->setValue(null);
|
|
$connectionConfig->setSection('redis2', $redis2Section);
|
|
} else {
|
|
$redis2Section['port'] = null;
|
|
}
|
|
|
|
if (! empty($redis2Database)) {
|
|
$redis2Section['database'] = $redis2Database;
|
|
$this->getElement('redis2_database')->setValue(null);
|
|
} else {
|
|
$redis2Section['database'] = null;
|
|
}
|
|
|
|
if (! empty($redis2Username)) {
|
|
$redis2Section['username'] = $redis2Username;
|
|
$this->getElement('redis2_username')->setValue(null);
|
|
} else {
|
|
$redis2Section['username'] = null;
|
|
}
|
|
|
|
if (! empty($redis2Password)) {
|
|
$redis2Section['password'] = $redis2Password;
|
|
$this->getElement('redis2_password')->setValue(null);
|
|
} else {
|
|
$redis2Section['password'] = null;
|
|
}
|
|
|
|
if (! array_filter($redis2Section->toArray())) {
|
|
$connectionConfig->removeSection('redis2');
|
|
}
|
|
|
|
try {
|
|
$connectionConfig->saveIni();
|
|
} catch (NotWritableError | Zend_Config_Exception $e) {
|
|
$this->addDecorator('ViewScript', array(
|
|
'viewModule' => 'default',
|
|
'viewScript' => 'showConfiguration.phtml',
|
|
'errorMessage' => $e->getMessage(),
|
|
'configString' => $connectionConfig,
|
|
'filePath' => $connectionConfig->getConfigFile(),
|
|
'placement' => Zend_Form_Decorator_Abstract::PREPEND
|
|
));
|
|
|
|
return false;
|
|
} catch (Throwable $e) {
|
|
$this->addError($e->getMessage());
|
|
Logger::error($e->getMessage());
|
|
Logger::debug(IcingaException::getConfidentialTraceAsString($e));
|
|
|
|
return false;
|
|
}
|
|
|
|
return parent::onSuccess();
|
|
}
|
|
|
|
public function addSubmitButton()
|
|
{
|
|
parent::addSubmitButton()
|
|
->getElement('btn_submit')
|
|
->setDecorators(['ViewHelper']);
|
|
|
|
$this->addElement(
|
|
'submit',
|
|
'backend_validation',
|
|
[
|
|
'ignore' => true,
|
|
'label' => t('Validate Configuration'),
|
|
'data-progress-label' => t('Validation In Progress'),
|
|
'decorators' => ['ViewHelper']
|
|
]
|
|
);
|
|
$this->addDisplayGroup(
|
|
['btn_submit', 'backend_validation'],
|
|
'submit_validation',
|
|
[
|
|
'decorators' => [
|
|
'FormElements',
|
|
['HtmlTag', ['tag' => 'div', 'class' => 'control-group form-controls']]
|
|
]
|
|
]
|
|
);
|
|
|
|
return $this;
|
|
}
|
|
|
|
public static function checkRedis(Form $form): bool
|
|
{
|
|
$sections = [];
|
|
|
|
$storage = new TemporaryLocalFileStorage();
|
|
foreach (ConfigForm::transformEmptyValuesToNull($form->getValues()) as $sectionAndPropertyName => $value) {
|
|
if ($value !== null) {
|
|
list($section, $property) = explode('_', $sectionAndPropertyName, 2);
|
|
if (in_array($property, ['ca', 'cert', 'key'])) {
|
|
$storage->create("$property.pem", $value);
|
|
$value = $storage->resolvePath("$property.pem");
|
|
}
|
|
|
|
$sections[$section][$property] = $value;
|
|
}
|
|
}
|
|
|
|
$ignoredTextAreas = [
|
|
'ca' => 'redis_ca_pem',
|
|
'cert' => 'redis_cert_pem',
|
|
'key' => 'redis_key_pem'
|
|
];
|
|
foreach ($ignoredTextAreas as $name => $textareaName) {
|
|
if (($textarea = $form->getElement($textareaName)) !== null) {
|
|
if (($pem = $textarea->getValue())) {
|
|
if ($storage->has("$name.pem")) {
|
|
$storage->update("$name.pem", $pem);
|
|
} else {
|
|
$storage->create("$name.pem", $pem);
|
|
$sections['redis'][$name] = $storage->resolvePath("$name.pem");
|
|
}
|
|
} elseif ($storage->has("$name.pem")) {
|
|
$storage->delete("$name.pem");
|
|
unset($sections['redis'][$name]);
|
|
}
|
|
}
|
|
}
|
|
|
|
$moduleConfig = new Config();
|
|
$moduleConfig->setSection('redis', $sections['redis']);
|
|
$redisConfig = new Config();
|
|
$redisConfig->setSection('redis1', $sections['redis1'] ?? []);
|
|
$redisConfig->setSection('redis2', $sections['redis2'] ?? []);
|
|
|
|
try {
|
|
$redis1 = IcingaRedis::getPrimaryRedis($moduleConfig, $redisConfig);
|
|
} catch (Exception $e) {
|
|
$form->warning(sprintf(
|
|
t('Failed to connect to primary Redis: %s'),
|
|
$e->getMessage()
|
|
));
|
|
|
|
return false;
|
|
}
|
|
|
|
if (IcingaRedis::getLastIcingaHeartbeat($redis1) === null) {
|
|
$form->warning(t('Primary connection established but failed to verify Icinga is connected as well.'));
|
|
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$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 && IcingaRedis::getLastIcingaHeartbeat($redis2) === null) {
|
|
$form->warning(t('Secondary connection established but failed to verify Icinga is connected as well.'));
|
|
|
|
return false;
|
|
}
|
|
|
|
$form->info(t('The configuration has been successfully validated.'));
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Wraps the given IPL validator class into a callback validator
|
|
* for usage as the only validator of the element given by name.
|
|
*
|
|
* @param string $cls IPL validator class FQN
|
|
* @param string $element Form element name
|
|
* @param Closure $additionalValidator
|
|
*
|
|
* @return array Callback validator
|
|
*/
|
|
private function wrapIplValidator(string $cls, string $element, Closure $additionalValidator = null): array
|
|
{
|
|
return [
|
|
'Callback',
|
|
false,
|
|
[
|
|
'callback' => function ($v) use ($cls, $element, $additionalValidator) {
|
|
if ($additionalValidator !== null) {
|
|
if (! $additionalValidator($v)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (! $v) {
|
|
return true;
|
|
}
|
|
|
|
$validator = new $cls();
|
|
$valid = $validator->isValid($v);
|
|
|
|
if (! $valid) {
|
|
/** @var Zend_Validate_Callback $callbackValidator */
|
|
$callbackValidator = $this->getElement($element)->getValidator('Callback');
|
|
|
|
$callbackValidator->setMessage(
|
|
$validator->getMessages()[0],
|
|
Zend_Validate_Callback::INVALID_VALUE
|
|
);
|
|
}
|
|
|
|
return $valid;
|
|
}
|
|
]
|
|
];
|
|
}
|
|
}
|