mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-04-08 17:15:08 +02:00
Merge branch 'master' into feature/deduplicate-puppet-code-6842
Conflicts: packages/rpm/etc/icingaweb2/resources.ini
This commit is contained in:
commit
570b31fe05
application
controllers
forms
Authentication
Config
Authentication
AuthenticationBackendConfigForm.phpAuthenticationBackendReorderForm.phpConfirmRemovalForm.phpGeneral
GeneralConfigForm.phpGeneralForm.phpLoggingForm.phpResource
ResourceConfigForm.phpResourceForm.phpDashboard
Install
Preference
PreferenceForm.phplocale/de_DE/LC_MESSAGES
views
helpers
scripts
config
icingaweb2.speclibrary/Icinga
Application
Authentication
Cli
Data
Exception
Logger
Protocol
Test
User.phpUser
Util
@ -14,7 +14,6 @@ use Icinga\Exception\AuthenticationException;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\User;
|
||||
use Icinga\Web\Session;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
@ -36,7 +35,6 @@ class AuthenticationController extends ActionController
|
||||
{
|
||||
$auth = $this->Auth();
|
||||
$this->view->form = $form = new LoginForm();
|
||||
$form->setRequest($this->_request);
|
||||
$this->view->title = $this->translate('Icingaweb Login');
|
||||
|
||||
try {
|
||||
@ -55,27 +53,17 @@ class AuthenticationController extends ActionController
|
||||
$config = Config::app('authentication');
|
||||
} catch (NotReadableError $e) {
|
||||
throw new ConfigurationError(
|
||||
$this->translate(
|
||||
'Could not read your authentiction.ini, no authentication methods are available.'
|
||||
)
|
||||
$this->translate('Could not read your authentiction.ini, no authentication methods are available.'),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
|
||||
$chain = new AuthChain($config);
|
||||
if ($this->getRequest()->isGet()) {
|
||||
$user = new User('');
|
||||
foreach ($chain as $backend) {
|
||||
if ($backend instanceof AutoLoginBackend) {
|
||||
$authenticated = $backend->authenticate($user);
|
||||
if ($authenticated === true) {
|
||||
$auth->setAuthenticated($user);
|
||||
$this->rerenderLayout()->redirectNow($redirectUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($form->isSubmittedAndValid()) {
|
||||
$user = new User($form->getValue('username'));
|
||||
$password = $form->getValue('password');
|
||||
$request = $this->getRequest();
|
||||
if ($request->isPost() && $this->view->form->isValid($request->getPost())) {
|
||||
$user = new User($this->view->form->getValue('username'));
|
||||
$password = $this->view->form->getValue('password');
|
||||
$backendsTried = 0;
|
||||
$backendsWithError = 0;
|
||||
|
||||
@ -121,14 +109,27 @@ class AuthenticationController extends ActionController
|
||||
);
|
||||
}
|
||||
if ($backendsWithError) {
|
||||
$form->addNote(
|
||||
$this->view->form->getElement('username')->addError(
|
||||
$this->translate(
|
||||
'Please note that not all authentication methods where available.'
|
||||
'Please note that not all authentication methods were available.'
|
||||
. ' Check the system log or Icinga Web 2 log for more information.'
|
||||
)
|
||||
);
|
||||
}
|
||||
$form->getElement('password')->addError($this->translate('Incorrect username or password'));
|
||||
$this->view->form->getElement('password')->addError($this->translate('Incorrect username or password'));
|
||||
} elseif ($request->isGet()) {
|
||||
$user = new User('');
|
||||
foreach ($chain as $backend) {
|
||||
if ($backend instanceof AutoLoginBackend) {
|
||||
$authenticated = $backend->authenticate($user);
|
||||
if ($authenticated === true) {
|
||||
$auth->setAuthenticated($user);
|
||||
$this->rerenderLayout()->redirectNow(
|
||||
Url::fromPath(Url::fromRequest()->getParam('redirect', 'dashboard'))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->view->errorInfo = $e->getMessage();
|
||||
@ -141,14 +142,16 @@ class AuthenticationController extends ActionController
|
||||
public function logoutAction()
|
||||
{
|
||||
$auth = $this->Auth();
|
||||
if (! $auth->isAuthenticated()) {
|
||||
$this->redirectToLogin();
|
||||
}
|
||||
$isRemoteUser = $auth->getUser()->isRemoteUser();
|
||||
$auth->removeAuthorization();
|
||||
|
||||
if ($isRemoteUser === true) {
|
||||
$this->_helper->layout->setLayout('login');
|
||||
$this->_response->setHttpResponseCode(401);
|
||||
} else {
|
||||
$this->rerenderLayout()->redirectToLogin();
|
||||
$this->redirectToLogin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,38 +2,25 @@
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
use Icinga\Web\Controller\BaseConfigController;
|
||||
use Icinga\Web\Widget\Tab;
|
||||
use Icinga\Web\Widget\AlertMessageBox;
|
||||
use Icinga\Web\Controller\ActionController;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Web\Widget;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Application\Config as IcingaConfig;
|
||||
use Icinga\Form\Config\GeneralConfigForm;
|
||||
use Icinga\Form\Config\AuthenticationBackendReorderForm;
|
||||
use Icinga\Form\Config\AuthenticationBackendConfigForm;
|
||||
use Icinga\Form\Config\ResourceConfigForm;
|
||||
use Icinga\Form\ConfirmRemovalForm;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Form\Config\GeneralForm;
|
||||
use Icinga\Form\Config\Authentication\ReorderForm;
|
||||
use Icinga\Form\Config\Authentication\LdapBackendForm;
|
||||
use Icinga\Form\Config\Authentication\DbBackendForm;
|
||||
use Icinga\Form\Config\ResourceForm;
|
||||
use Icinga\Form\Config\LoggingForm;
|
||||
use Icinga\Form\Config\ConfirmRemovalForm;
|
||||
use Icinga\Config\PreservingIniWriter;
|
||||
|
||||
|
||||
/**
|
||||
* Application wide controller for application preferences
|
||||
*/
|
||||
class ConfigController extends BaseConfigController
|
||||
class ConfigController extends ActionController
|
||||
{
|
||||
/**
|
||||
* The resource types that are available.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $resourceTypes = array('livestatus', 'ido', 'statusdat', 'ldap');
|
||||
|
||||
public function init()
|
||||
{
|
||||
$this->view->tabs = Widget::create('tabs')->add('index', array(
|
||||
@ -45,9 +32,6 @@ class ConfigController extends BaseConfigController
|
||||
))->add('resources', array(
|
||||
'title' => 'Resources',
|
||||
'url' => 'config/resource'
|
||||
))->add('logging', array(
|
||||
'title' => 'Logging',
|
||||
'url' => 'config/logging'
|
||||
));
|
||||
}
|
||||
|
||||
@ -61,42 +45,12 @@ class ConfigController extends BaseConfigController
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$form = new GeneralConfigForm();
|
||||
$form->setIniConfig(IcingaConfig::app());
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->tabs->activate('index');
|
||||
$form = new GeneralForm();
|
||||
$form->setConfiguration(IcingaConfig::app());
|
||||
$form->setRequest($this->_request);
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
if (!$this->writeConfigFile($form->getConfig(), 'config')) {
|
||||
return;
|
||||
}
|
||||
Notification::success('New configuration has successfully been stored');
|
||||
$form->setConfiguration(IcingaConfig::app(), true);
|
||||
$this->redirectNow('config/index');
|
||||
}
|
||||
$this->view->form = $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form for modifying the logging configuration
|
||||
*/
|
||||
public function loggingAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$this->view->tabs->activate('logging');
|
||||
|
||||
$form = new LoggingForm();
|
||||
$form->setConfiguration(IcingaConfig::app());
|
||||
$form->setRequest($this->_request);
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
if (!$this->writeConfigFile($form->getConfig(), 'config')) {
|
||||
return;
|
||||
}
|
||||
Notification::success('New configuration has sucessfully been stored');
|
||||
$form->setConfiguration(IcingaConfig::app(), true);
|
||||
$this->redirectNow('config/logging');
|
||||
}
|
||||
$this->view->form = $form;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,7 +96,7 @@ class ConfigController extends BaseConfigController
|
||||
try {
|
||||
$manager->enableModule($module);
|
||||
$manager->loadModule($module);
|
||||
Notification::success('Module "' . $module . '" enabled');
|
||||
Notification::success(sprintf($this->translate('Module "%s" enabled'), $module));
|
||||
$this->rerenderLayout()->reloadCss()->redirectNow('config/modules');
|
||||
} catch (Exception $e) {
|
||||
$this->view->exceptionMesssage = $e->getMessage();
|
||||
@ -161,7 +115,7 @@ class ConfigController extends BaseConfigController
|
||||
$manager = Icinga::app()->getModuleManager();
|
||||
try {
|
||||
$manager->disableModule($module);
|
||||
Notification::success('Module "' . $module . '" disabled');
|
||||
Notification::success(sprintf($this->translate('Module "%s" disabled'), $module));
|
||||
$this->rerenderLayout()->reloadCss()->redirectNow('config/modules');
|
||||
} catch (Exception $e) {
|
||||
$this->view->exceptionMessage = $e->getMessage();
|
||||
@ -172,40 +126,17 @@ class ConfigController extends BaseConfigController
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for creating a new authentication backend
|
||||
* Action for listing and reordering authentication backends
|
||||
*/
|
||||
public function authenticationAction()
|
||||
{
|
||||
$config = IcingaConfig::app('authentication', true);
|
||||
$form = new AuthenticationBackendReorderForm();
|
||||
$form->setIniConfig(IcingaConfig::app('authentication'));
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->tabs->activate('authentication');
|
||||
|
||||
$order = array_keys($config->toArray());
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
|
||||
$backends = array();
|
||||
foreach ($order as $backend) {
|
||||
$form = new ReorderForm();
|
||||
$form->setName('form_reorder_backend_' . $backend);
|
||||
$form->setBackendName($backend);
|
||||
$form->setCurrentOrder($order);
|
||||
$form->setRequest($this->_request);
|
||||
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
if ($this->writeAuthenticationFile($form->getReorderedConfig($config))) {
|
||||
Notification::success('Authentication Order Updated');
|
||||
$this->redirectNow('config/authentication');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$backends[] = (object) array(
|
||||
'name' => $backend,
|
||||
'reorderForm' => $form
|
||||
);
|
||||
}
|
||||
|
||||
$this->view->backends = $backends;
|
||||
$this->render('authentication/reorder');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -213,316 +144,151 @@ class ConfigController extends BaseConfigController
|
||||
*/
|
||||
public function createauthenticationbackendAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$form = new AuthenticationBackendConfigForm();
|
||||
$form->setIniConfig(IcingaConfig::app('authentication'));
|
||||
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||
$form->setRedirectUrl('config/authentication');
|
||||
$form->handleRequest();
|
||||
|
||||
if ($this->getRequest()->getParam('type') === 'ldap') {
|
||||
$form = new LdapBackendForm();
|
||||
} else {
|
||||
$form = new DbBackendForm();
|
||||
}
|
||||
if ($this->getParam('auth_backend')) {
|
||||
$form->setBackendName($this->getParam('auth_backend'));
|
||||
}
|
||||
$form->setRequest($this->getRequest());
|
||||
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
$backendCfg = IcingaConfig::app('authentication')->toArray();
|
||||
foreach ($backendCfg as $backendName => $settings) {
|
||||
unset($backendCfg[$backendName]['name']);
|
||||
}
|
||||
foreach ($form->getConfig() as $backendName => $settings) {
|
||||
unset($settings->{'name'});
|
||||
if (isset($backendCfg[$backendName])) {
|
||||
$this->addErrorMessage('Backend name already exists');
|
||||
$this->view->form = $form;
|
||||
$this->render('authentication/create');
|
||||
return;
|
||||
}
|
||||
$backendCfg[$backendName] = $settings;
|
||||
}
|
||||
if ($this->writeAuthenticationFile($backendCfg)) {
|
||||
// redirect to overview with success message
|
||||
Notification::success('Backend Modification Written.');
|
||||
$this->redirectNow("config/authentication");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->view->messageBox->addForm($form);
|
||||
$this->view->form = $form;
|
||||
$this->view->tabs->activate('authentication');
|
||||
$this->render('authentication/create');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Form for editing backends
|
||||
*
|
||||
* Mostly the same like the createAuthenticationBackendAction, but with additional checks for backend existence
|
||||
* and form population
|
||||
* Action for editing authentication backends
|
||||
*/
|
||||
public function editauthenticationbackendAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$form = new AuthenticationBackendConfigForm();
|
||||
$form->setIniConfig(IcingaConfig::app('authentication'));
|
||||
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||
$form->setRedirectUrl('config/authentication');
|
||||
$form->handleRequest();
|
||||
|
||||
$configArray = IcingaConfig::app('authentication', true)->toArray();
|
||||
$authBackend = $this->getParam('auth_backend');
|
||||
if (!isset($configArray[$authBackend])) {
|
||||
$this->addErrorMessage('Can\'t edit: Unknown Authentication Backend Provided');
|
||||
$this->configurationerrorAction();
|
||||
return;
|
||||
}
|
||||
if (!array_key_exists('resource', $configArray[$authBackend])) {
|
||||
$this->addErrorMessage('Configuration error: Backend "' . $authBackend . '" has no Resource');
|
||||
$this->configurationerrorAction();
|
||||
return;
|
||||
}
|
||||
|
||||
$type = ResourceFactory::getResourceConfig($configArray[$authBackend]['resource'])->type;
|
||||
switch ($type) {
|
||||
case 'ldap':
|
||||
$form = new LdapBackendForm();
|
||||
break;
|
||||
case 'db':
|
||||
$form = new DbBackendForm();
|
||||
break;
|
||||
default:
|
||||
$this->addErrorMessage('Can\'t edit: backend type "' . $type . '" of given resource not supported.');
|
||||
$this->configurationerrorAction();
|
||||
return;
|
||||
}
|
||||
|
||||
$form->setBackendName($this->getParam('auth_backend'));
|
||||
$form->setBackend(IcingaConfig::app('authentication', true)->$authBackend);
|
||||
$form->setRequest($this->getRequest());
|
||||
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
$backendCfg = IcingaConfig::app('authentication')->toArray();
|
||||
foreach ($form->getConfig() as $backendName => $settings) {
|
||||
$backendCfg[$backendName] = $settings;
|
||||
// Remove the old section if the backend is renamed
|
||||
if ($backendName != $authBackend) {
|
||||
unset($backendCfg[$authBackend]);
|
||||
}
|
||||
unset($settings['name']);
|
||||
}
|
||||
if ($this->writeAuthenticationFile($backendCfg)) {
|
||||
// redirect to overview with success message
|
||||
Notification::success('Backend "' . $authBackend . '" created');
|
||||
$this->redirectNow("config/authentication");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->view->messageBox->addForm($form);
|
||||
$this->view->name = $authBackend;
|
||||
$this->view->form = $form;
|
||||
$this->view->tabs->activate('authentication');
|
||||
$this->render('authentication/modify');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action for removing a backend from the authentication list.
|
||||
*
|
||||
* Redirects to the overview after removal is finished
|
||||
* Action for removing a backend from the authentication list
|
||||
*/
|
||||
public function removeauthenticationbackendAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$form = new ConfirmRemovalForm(array(
|
||||
'onSuccess' => function ($request) {
|
||||
$configForm = new AuthenticationBackendConfigForm();
|
||||
$configForm->setIniConfig(IcingaConfig::app('authentication'));
|
||||
$authBackend = $request->getQuery('auth_backend');
|
||||
|
||||
$configArray = IcingaConfig::app('authentication', true)->toArray();
|
||||
$authBackend = $this->getParam('auth_backend');
|
||||
if (!isset($configArray[$authBackend])) {
|
||||
Notification::error('Can\'t perform removal: Unknown Authentication Backend Provided');
|
||||
$this->render('authentication/remove');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$configForm->remove($authBackend);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
$form = new ConfirmRemovalForm();
|
||||
$form->setRequest($this->getRequest());
|
||||
$form->setRemoveTarget('auth_backend', $authBackend);
|
||||
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
unset($configArray[$authBackend]);
|
||||
if ($this->writeAuthenticationFile($configArray)) {
|
||||
Notification::success('Authentication Backend "' . $authBackend . '" Removed');
|
||||
$this->redirectNow("config/authentication");
|
||||
if ($configForm->save()) {
|
||||
Notification::success(sprintf(
|
||||
t('Authentication backend "%s" has been successfully removed'),
|
||||
$authBackend
|
||||
));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
));
|
||||
$form->setRedirectUrl('config/authentication');
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->name = $authBackend;
|
||||
$this->view->tabs->activate('authentication');
|
||||
$this->render('authentication/remove');
|
||||
}
|
||||
|
||||
public function resourceAction($showOnly = false)
|
||||
/**
|
||||
* Display all available resources and a link to create a new one and to remove existing ones
|
||||
*/
|
||||
public function resourceAction()
|
||||
{
|
||||
$this->view->tabs->activate('resources');
|
||||
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$this->view->resources = IcingaConfig::app('resources', true)->toArray();
|
||||
$this->render('resource');
|
||||
$this->view->tabs->activate('resources');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a form to create a new resource
|
||||
*/
|
||||
public function createresourceAction()
|
||||
{
|
||||
$this->view->resourceTypes = $this->resourceTypes;
|
||||
$resources = IcingaConfig::app('resources', true);
|
||||
$form = new ResourceForm();
|
||||
$form->setRequest($this->_request);
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
$name = $form->getName();
|
||||
if (isset($resources->{$name})) {
|
||||
$this->addErrorMessage('Resource name "' . $name .'" already in use.');
|
||||
} else {
|
||||
$resources->{$name} = $form->getConfig();
|
||||
if ($this->writeConfigFile($resources, 'resources')) {
|
||||
$this->addSuccessMessage('Resource "' . $name . '" created.');
|
||||
$this->redirectNow("config/resource");
|
||||
}
|
||||
}
|
||||
}
|
||||
$form = new ResourceConfigForm();
|
||||
$form->setIniConfig(IcingaConfig::app('resources'));
|
||||
$form->setRedirectUrl('config/resource');
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$this->view->messageBox->addForm($form);
|
||||
$this->view->form = $form;
|
||||
$this->render('resource/create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a form to edit a existing resource
|
||||
*/
|
||||
public function editresourceAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$form = new ResourceConfigForm();
|
||||
$form->setIniConfig(IcingaConfig::app('resources'));
|
||||
$form->setRedirectUrl('config/resource');
|
||||
$form->handleRequest();
|
||||
|
||||
$resources = ResourceFactory::getResourceConfigs();
|
||||
$name = $this->getParam('resource');
|
||||
if ($resources->get($name) === null) {
|
||||
$this->addErrorMessage('Can\'t edit: Unknown Resource Provided');
|
||||
$this->render('resource/modify');
|
||||
return;
|
||||
}
|
||||
$form = new ResourceForm();
|
||||
if ($this->_request->isPost() === false) {
|
||||
$form->setOldName($name);
|
||||
$form->setName($name);
|
||||
}
|
||||
$form->setRequest($this->_request);
|
||||
$form->setResource($resources->get($name));
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
$oldName = $form->getOldName();
|
||||
$name = $form->getName();
|
||||
if ($oldName !== $name) {
|
||||
unset($resources->{$oldName});
|
||||
}
|
||||
$resources->{$name} = $form->getConfig();
|
||||
if ($this->writeConfigFile($resources, 'resources')) {
|
||||
$this->addSuccessMessage('Resource "' . $name . '" edited.');
|
||||
$this->redirectNow("config/resource");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->view->messageBox->addForm($form);
|
||||
$this->view->form = $form;
|
||||
$this->view->name = $name;
|
||||
$this->render('resource/modify');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a confirmation form to remove a resource
|
||||
*/
|
||||
public function removeresourceAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$form = new ConfirmRemovalForm(array(
|
||||
'onSuccess' => function ($request) {
|
||||
$configForm = new ResourceConfigForm();
|
||||
$configForm->setIniConfig(IcingaConfig::app('resources'));
|
||||
$resource = $request->getQuery('resource');
|
||||
|
||||
$resources = ResourceFactory::getResourceConfigs()->toArray();
|
||||
$name = $this->getParam('resource');
|
||||
if (!isset($resources[$name])) {
|
||||
$this->addSuccessMessage('Can\'t remove: Unknown resource provided');
|
||||
$this->render('resource/remove');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$configForm->remove($resource);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
$form = new ConfirmRemovalForm();
|
||||
$form->setRequest($this->getRequest());
|
||||
$form->setRemoveTarget('resource', $name);
|
||||
if ($configForm->save()) {
|
||||
Notification::success(sprintf(t('Resource "%s" has been successfully removed'), $resource));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
));
|
||||
$form->setRedirectUrl('config/resource');
|
||||
$form->handleRequest();
|
||||
|
||||
// Check if selected resource is currently used for authentication
|
||||
$authConfig = IcingaConfig::app('authentication', true)->toArray();
|
||||
$resource = $this->getRequest()->getQuery('resource');
|
||||
$authConfig = IcingaConfig::app('authentication')->toArray();
|
||||
foreach ($authConfig as $backendName => $config) {
|
||||
if (array_key_exists('resource', $config) && $config['resource'] === $name) {
|
||||
$this->addErrorMessage(
|
||||
'Warning: The resource "' . $name . '" is currently used for user authentication by "' . $backendName . '". ' .
|
||||
' Deleting it could eventally make login impossible.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
unset($resources[$name]);
|
||||
if ($this->writeConfigFile($resources, 'resources')) {
|
||||
$this->addSuccessMessage('Resource "' . $name . '" removed.');
|
||||
$this->redirectNow('config/resource');
|
||||
if (array_key_exists('resource', $config) && $config['resource'] === $resource) {
|
||||
$form->addError(sprintf(
|
||||
$this->translate(
|
||||
'The resource "%s" is currently in use by the authentication backend "%s". ' .
|
||||
'Removing the resource can result in noone being able to log in any longer.'
|
||||
),
|
||||
$resource,
|
||||
$backendName
|
||||
));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->view->name = $name;
|
||||
$this->view->form = $form;
|
||||
$this->render('resource/remove');
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect target only for error-states
|
||||
*
|
||||
* When an error is opened in the side-pane, redirecting this request to the index or the overview will look
|
||||
* weird. This action returns a clear page containing only an AlertMessageBox.
|
||||
*/
|
||||
public function configurationerrorAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$this->render('error/error', null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write changes to an authentication file
|
||||
*
|
||||
* @param array $config The configuration changes
|
||||
*
|
||||
* @return bool True when persisting succeeded, otherwise false
|
||||
*
|
||||
* @see writeConfigFile()
|
||||
*/
|
||||
private function writeAuthenticationFile($config) {
|
||||
return $this->writeConfigFile($config, 'authentication');
|
||||
}
|
||||
|
||||
/**
|
||||
* Write changes to a configuration file $file, using the supplied writer or PreservingIniWriter if none is set
|
||||
*
|
||||
* @param array|Zend_Config $config The configuration to write
|
||||
* @param string $file The filename to write to (without .ini)
|
||||
* @param Zend_Config_Writer $writer An optional writer to use for persisting changes
|
||||
*
|
||||
* @return bool True when persisting succeeded, otherwise false
|
||||
*/
|
||||
private function writeConfigFile($config, $file, $writer = null)
|
||||
{
|
||||
if (is_array($config)) {
|
||||
$config = new Zend_Config($config);
|
||||
}
|
||||
if ($writer === null) {
|
||||
$writer = new PreservingIniWriter(
|
||||
array(
|
||||
'config' => $config,
|
||||
'filename' => IcingaConfig::app($file)->getConfigFile()
|
||||
)
|
||||
);
|
||||
}
|
||||
try {
|
||||
$writer->write();
|
||||
return true;
|
||||
} catch (Exception $exc) {
|
||||
$this->view->exceptionMessage = $exc->getMessage();
|
||||
$this->view->iniConfigurationString = $writer->render();
|
||||
$this->view->file = $file;
|
||||
$this->render('show-configuration');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,25 +82,29 @@ class DashboardController extends ActionController
|
||||
)->activate('addurl');
|
||||
|
||||
$form = new AddUrlForm();
|
||||
$form->setRequest($this->getRequest());
|
||||
$form->setAction(Url::fromRequest()->setParams(array())->getAbsoluteUrl());
|
||||
$this->view->form = $form;
|
||||
$request = $this->getRequest();
|
||||
if ($request->isPost()) {
|
||||
if ($form->isValid($request->getPost()) && $form->isSubmitted()) {
|
||||
$dashboard = $this->getDashboard();
|
||||
$dashboard->setComponentUrl(
|
||||
$form->getValue('pane'),
|
||||
$form->getValue('component'),
|
||||
ltrim($form->getValue('url'), '/')
|
||||
);
|
||||
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
$dashboard = $this->getDashboard();
|
||||
$dashboard->setComponentUrl(
|
||||
$form->getValue('pane'),
|
||||
$form->getValue('component'),
|
||||
ltrim($form->getValue('url'), '/')
|
||||
);
|
||||
|
||||
$configFile = IcingaConfig::app('dashboard/dashboard')->getConfigFile();
|
||||
if ($this->writeConfiguration(new Zend_Config($dashboard->toArray()), $configFile)) {
|
||||
$this->redirectNow(Url::fromPath('dashboard', array('pane' => $form->getValue('pane'))));
|
||||
} else {
|
||||
$this->render('show-configuration');
|
||||
$configFile = IcingaConfig::app('dashboard/dashboard')->getConfigFile();
|
||||
if ($this->writeConfiguration(new Zend_Config($dashboard->toArray()), $configFile)) {
|
||||
$this->redirectNow(Url::fromPath('dashboard', array('pane' => $form->getValue('pane'))));
|
||||
} else {
|
||||
$this->render('showConfiguration');
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$form->create()->setDefault('url', htmlspecialchars_decode($request->getParam('url', '')));
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,9 +164,9 @@ class DashboardController extends ActionController
|
||||
$writer->write();
|
||||
} catch (Exception $e) {
|
||||
Logger::error(new ConfiguationError("Cannot write dashboard to $target", 0, $e));
|
||||
$this->view->iniConfigurationString = $writer->render();
|
||||
$this->view->exceptionMessage = $e->getMessage();
|
||||
$this->view->file = $target;
|
||||
$this->view->configString = $writer->render();
|
||||
$this->view->errorMessage = $e->getMessage();
|
||||
$this->view->filePath = $target;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3,11 +3,12 @@
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
use Icinga\Web\Controller\BasePreferenceController;
|
||||
use Icinga\Web\Widget\Tab;
|
||||
use Icinga\Application\Config as IcingaConfig;
|
||||
use Icinga\Web\Url;
|
||||
use Icinga\Form\Preference\GeneralForm;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Widget\Tab;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Form\PreferenceForm;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\User\Preferences\PreferencesStore;
|
||||
|
||||
/**
|
||||
* Application wide preference controller for user preferences
|
||||
@ -34,27 +35,22 @@ class PreferenceController extends BasePreferenceController
|
||||
}
|
||||
|
||||
/**
|
||||
* General settings for date and time
|
||||
* Show form to adjust user preferences
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$form = new GeneralForm();
|
||||
$this->getTabs()->activate('general');
|
||||
$form->setConfiguration(IcingaConfig::app())
|
||||
->setRequest($this->getRequest());
|
||||
if ($form->isSubmittedAndValid()) {
|
||||
try {
|
||||
$this->savePreferences($form->getPreferences());
|
||||
Notification::success(t('Preferences updated successfully'));
|
||||
// Recreate form to show new values
|
||||
// TODO(el): It must sufficient to call $form->populate(...)
|
||||
$form = new GeneralForm();
|
||||
$form->setConfiguration(IcingaConfig::app());
|
||||
$form->setRequest($this->getRequest());
|
||||
} catch (Exception $e) {
|
||||
Notification::error(sprintf(t('Failed to persist preferences. (%s)'), $e->getMessage()));
|
||||
}
|
||||
$storeConfig = Config::app()->preferences;
|
||||
if ($storeConfig === null) {
|
||||
throw new ConfigurationError(t('You need to configure how to store preferences first.'));
|
||||
}
|
||||
|
||||
$user = $this->getRequest()->getUser();
|
||||
$form = new PreferenceForm();
|
||||
$form->setPreferences($user->getPreferences());
|
||||
$form->setStore(PreferencesStore::create($storeConfig, $user));
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->getTabs()->activate('general');
|
||||
}
|
||||
}
|
||||
|
@ -13,36 +13,45 @@ use Icinga\Web\Url;
|
||||
class LoginForm extends Form
|
||||
{
|
||||
/**
|
||||
* Interface how the form should be created
|
||||
* Initialize this login form
|
||||
*/
|
||||
protected function create()
|
||||
public function init()
|
||||
{
|
||||
$url = Url::fromRequest()->without('renderLayout');
|
||||
|
||||
$this->setName('form_login');
|
||||
$this->addElement('text', 'username', array(
|
||||
'label' => t('Username'),
|
||||
'placeholder' => t('Please enter your username...'),
|
||||
'required' => true,
|
||||
));
|
||||
$redir = $this->addElement('hidden', 'redirect');
|
||||
$redirectUrl = $url->shift('redirect');
|
||||
if ($redirectUrl) {
|
||||
$this->setDefault('redirect', $redirectUrl);
|
||||
}
|
||||
$this->setSubmitLabel(t('Login'));
|
||||
}
|
||||
|
||||
$this->addElement('password', 'password', array(
|
||||
'label' => t('Password'),
|
||||
'placeholder' => t('...and your password'),
|
||||
'required' => true
|
||||
));
|
||||
// TODO: We need a place to intercept filled forms before rendering
|
||||
if ($this->getRequest()->getPost('username') !== null) {
|
||||
$this->getElement('password')->setAttrib('class', 'autofocus');
|
||||
} else {
|
||||
$this->getElement('username')->setAttrib('class', 'autofocus');
|
||||
}
|
||||
$this->setAction((string) $url);
|
||||
$this->setSubmitLabel('Login');
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'username',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Username'),
|
||||
'placeholder' => t('Please enter your username...'),
|
||||
'class' => false === isset($formData['username']) ? 'autofocus' : ''
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'password',
|
||||
'password',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Password'),
|
||||
'placeholder' => t('...and your password'),
|
||||
'class' => isset($formData['username']) ? 'autofocus' : ''
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'redirect',
|
||||
array(
|
||||
'value' => Url::fromRequest()->getParam('redirect')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\Authentication;
|
||||
|
||||
use Zend_Validate_Callback;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying autologin authentication backends
|
||||
*/
|
||||
class AutologinBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend_autologin');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Backend Name'),
|
||||
'description' => t('The name of this authentication backend'),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\\[\\]:]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => 'The backend name cannot contain \'[\', \']\' or \':\'.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'strip_username_regexp',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Backend Domain Pattern'),
|
||||
'description' => t('The domain pattern of this authentication backend'),
|
||||
'value' => '/\@[^$]+$/',
|
||||
'validators' => array(
|
||||
new Zend_Validate_Callback(function ($value) {
|
||||
return @preg_match($value, '') !== false;
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'required' => true,
|
||||
'value' => 'autologin'
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* Returns always true as autologin backends are just "passive" backends. (The webserver authenticates users.)
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public function isValidAuthenticationBackend(Form $form)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\Authentication;
|
||||
|
||||
use Zend_Config;
|
||||
use Zend_Form_Element_Checkbox;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Web\Form\Decorator\HelpText;
|
||||
|
||||
/**
|
||||
* Base form for authentication backend forms
|
||||
*/
|
||||
abstract class BaseBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* The name of the backend currently displayed in this form
|
||||
*
|
||||
* Will be the section in the authentication.ini file
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $backendName = '';
|
||||
|
||||
/**
|
||||
* The backend configuration as a Zend_Config object
|
||||
*
|
||||
* @var Zend_Config
|
||||
*/
|
||||
protected $backend;
|
||||
|
||||
/**
|
||||
* The resources to use instead of the factory provided ones (use for testing)
|
||||
*
|
||||
* @var Zend_Config
|
||||
*/
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* Set the name of the currently displayed backend
|
||||
*
|
||||
* @param string $name The name to be stored as the section when persisting
|
||||
*/
|
||||
public function setBackendName($name)
|
||||
{
|
||||
$this->backendName = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the backend name of this form
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBackendName()
|
||||
{
|
||||
return $this->backendName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the backend configuration or a empty Zend_Config object if none is given
|
||||
*
|
||||
* @return Zend_Config
|
||||
*/
|
||||
public function getBackend()
|
||||
{
|
||||
return ($this->backend !== null) ? $this->backend : new Zend_Config(array());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the backend configuration for initial population
|
||||
*
|
||||
* @param Zend_Config $backend The backend to display in this form
|
||||
*/
|
||||
public function setBackend(Zend_Config $backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an alternative array of resources that should be used instead of the DBFactory resource set
|
||||
*
|
||||
* @param array $resources The resources to use for populating the db selection field
|
||||
*/
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
$this->resources = $resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return content of the resources.ini or previously set resources
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getResources()
|
||||
{
|
||||
if ($this->resources === null) {
|
||||
return ResourceFactory::getResourceConfigs()->toArray();
|
||||
} else {
|
||||
return $this->resources;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add checkbox at the beginning of the form which allows to skip logic connection validation
|
||||
*/
|
||||
protected function addForceCreationCheckbox()
|
||||
{
|
||||
$checkbox = new Zend_Form_Element_Checkbox(
|
||||
array(
|
||||
'name' => 'backend_force_creation',
|
||||
'label' => t('Force Changes'),
|
||||
'helptext' => t('Check this box to enforce changes without connectivity validation'),
|
||||
'order' => 0
|
||||
)
|
||||
);
|
||||
$checkbox->addDecorator(new HelpText());
|
||||
$this->addElement($checkbox);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate this form with the Zend validation mechanism and perform a logic validation of the connection.
|
||||
*
|
||||
* If logic validation fails, the 'backend_force_creation' checkbox is prepended to the form to allow users to
|
||||
* skip the logic connection validation.
|
||||
*
|
||||
* @param array $data The form input to validate
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public function isValid($data)
|
||||
{
|
||||
if (!parent::isValid($data)) {
|
||||
return false;
|
||||
}
|
||||
if (isset($data['backend_force_creation']) && $data['backend_force_creation']) {
|
||||
return true;
|
||||
}
|
||||
if (!$this->isValidAuthenticationBackend()) {
|
||||
$this->addForceCreationCheckbox();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array containing all sections defined by this form as the key and all settings
|
||||
* as an key-value sub-array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getConfig();
|
||||
|
||||
/**
|
||||
* Validate the configuration state of this backend with the concrete authentication backend.
|
||||
*
|
||||
* An implementation should not throw any exception, but use the add/setErrorMessages method of
|
||||
* Zend_Form. If the 'backend_force_creation' checkbox is set, this method won't be called.
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
abstract public function isValidAuthenticationBackend();
|
||||
}
|
@ -5,123 +5,116 @@
|
||||
namespace Icinga\Form\Config\Authentication;
|
||||
|
||||
use Exception;
|
||||
use Zend_Config;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Authentication\DbConnection;
|
||||
use Icinga\Authentication\Backend\DbUserBackend;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying database authentication backends
|
||||
*/
|
||||
class DbBackendForm extends BaseBackendForm
|
||||
class DbBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* Return content of the resources.ini or previously set resources
|
||||
* The database resource names the user can choose from
|
||||
*
|
||||
* @return array
|
||||
* @var array
|
||||
*/
|
||||
public function getResources()
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if ($this->resources === null) {
|
||||
$res = ResourceFactory::getResourceConfigs('db')->toArray();
|
||||
$this->setName('form_config_authbackend_db');
|
||||
}
|
||||
|
||||
foreach (array_keys($res) as $key) {
|
||||
$res[$key] = $key;
|
||||
}
|
||||
/**
|
||||
* Set the resource names the user can choose from
|
||||
*
|
||||
* @param array $resources The resources to choose from
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
$this->resources = $resources;
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $res;
|
||||
} else {
|
||||
return $this->resources;
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Backend Name'),
|
||||
'description' => t('The name of this authentication provider'),
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Connection'),
|
||||
'description' => t('The database connection to use for authenticating with this provider'),
|
||||
'multiOptions' => false === empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'required' => true,
|
||||
'value' => 'db'
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the selected resource is a valid database authentication backend
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
if (false === $this->isValidAuthenticationBackend($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create this form and add all required elements
|
||||
* Validate the configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* @see Form::create()
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public function create()
|
||||
public function isValidAuthenticationBackend(Form $form)
|
||||
{
|
||||
$this->setName('form_modify_backend');
|
||||
$name = $this->filterName($this->getBackendName());
|
||||
$this->addElement(
|
||||
'text',
|
||||
'backend_' . $name . '_name',
|
||||
array(
|
||||
'required' => true,
|
||||
'allowEmpty' => false,
|
||||
'label' => t('Backend Name'),
|
||||
'helptext' => t('The name of this authentication provider'),
|
||||
'value' => $this->getBackendName()
|
||||
)
|
||||
);
|
||||
$element = $form->getElement('resource');
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'backend_' . $name . '_resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'allowEmpty' => false,
|
||||
'label' => t('Database Connection'),
|
||||
'helptext' => t('The database connection to use for authenticating with this provider'),
|
||||
'value' => $this->getBackend()->get('resource'),
|
||||
'multiOptions' => $this->getResources()
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'button',
|
||||
'btn_submit',
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'value' => '1',
|
||||
'escape' => false,
|
||||
'class' => 'btn btn-cta btn-wide',
|
||||
'label' => '<i class="icinga-icon-save"></i> Save Backend'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the datatbase authentication backend configuration for this form
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @see BaseBackendForm::getConfig()
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
$prefix = 'backend_' . $this->filterName($this->getBackendName()) . '_';
|
||||
$section = $this->getValue($prefix . 'name');
|
||||
$cfg = array(
|
||||
'backend' => 'db',
|
||||
'resource' => $this->getValue($prefix . 'resource'),
|
||||
);
|
||||
|
||||
return array($section => $cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the current configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*
|
||||
* @see BaseBackendForm::isValidAuthenticationBackend
|
||||
*/
|
||||
public function isValidAuthenticationBackend()
|
||||
{
|
||||
try {
|
||||
$dbUserBackend = new DbUserBackend(ResourceFactory::create(
|
||||
$this->getValue('backend_' . $this->filterName($this->getBackendName()) . '_resource')
|
||||
));
|
||||
$dbUserBackend = new DbUserBackend(ResourceFactory::create($element->getValue()));
|
||||
if ($dbUserBackend->count() < 1) {
|
||||
$this->addErrorMessage(t("No users found under the specified database backend"));
|
||||
$element->addError(t('No users found under the specified database backend'));
|
||||
return false;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->addErrorMessage(sprintf(t('Using the specified backend failed: %s'), $e->getMessage()));
|
||||
$element->addError(sprintf(t('Using the specified backend failed: %s'), $e->getMessage()));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -5,166 +5,134 @@
|
||||
namespace Icinga\Form\Config\Authentication;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Application\Platform;
|
||||
use Zend_Config;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Authentication\Backend\LdapUserBackend;
|
||||
|
||||
/**
|
||||
* Form for adding or modifying LDAP authentication backends
|
||||
* Form class for adding/modifying LDAP authentication backends
|
||||
*/
|
||||
class LdapBackendForm extends BaseBackendForm
|
||||
class LdapBackendForm extends Form
|
||||
{
|
||||
/**
|
||||
* Return content of the resources.ini or previously set resources
|
||||
* The ldap resource names the user can choose from
|
||||
*
|
||||
* @return array
|
||||
* @var array
|
||||
*/
|
||||
public function getResources()
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if ($this->resources === null) {
|
||||
$res = ResourceFactory::getResourceConfigs('ldap')->toArray();
|
||||
|
||||
foreach (array_keys($res) as $key) {
|
||||
$res[$key] = $key;
|
||||
}
|
||||
|
||||
return $res;
|
||||
} else {
|
||||
return $this->resources;
|
||||
}
|
||||
$this->setName('form_config_authbackend_ldap');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create this form and add all required elements
|
||||
* Set the resource names the user can choose from
|
||||
*
|
||||
* @see Form::create()
|
||||
* @param array $resources The resources to choose from
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function create()
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
$this->setName('form_modify_backend');
|
||||
$name = $this->filterName($this->getBackendName());
|
||||
$backend = $this->getBackend();
|
||||
$this->resources = $resources;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'backend_' . $name . '_name',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'allowEmpty' => false,
|
||||
'label' => t('Backend Name'),
|
||||
'helptext' => t('The name of this authentication backend'),
|
||||
'value' => $this->getBackendName()
|
||||
'description' => t('The name of this authentication backend')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'backend_' . $name . '_resource',
|
||||
'resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'allowEmpty' => false,
|
||||
'label' => t('LDAP Resource'),
|
||||
'helptext' => t('The resource to use for authenticating with this provider'),
|
||||
'value' => $this->getBackend()->get('resource'),
|
||||
'multiOptions' => $this->getResources()
|
||||
'description' => t('The resource to use for authenticating with this provider'),
|
||||
'multiOptions' => false === empty($this->resources)
|
||||
? array_combine($this->resources, $this->resources)
|
||||
: array()
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'backend_' . $name . '_user_class',
|
||||
'user_class',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('LDAP User Object Class'),
|
||||
'helptext' => t('The object class used for storing users on the ldap server'),
|
||||
'value' => $backend->get('user_class', 'inetOrgPerson')
|
||||
'required' => true,
|
||||
'label' => t('LDAP User Object Class'),
|
||||
'description' => t('The object class used for storing users on the ldap server'),
|
||||
'value' => 'inetOrgPerson'
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'backend_' . $name . '_user_name_attribute',
|
||||
'user_name_attribute',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('LDAP User Name Attribute'),
|
||||
'description' => t('The attribute name used for storing the user name on the ldap server'),
|
||||
'value' => 'uid'
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'backend',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('LDAP User Name Attribute'),
|
||||
'helptext' => t('The attribute name used for storing the user name on the ldap server'),
|
||||
'value' => $backend->get('user_name_attribute', 'uid')
|
||||
'value' => 'ldap'
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'button',
|
||||
'btn_submit',
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'value' => '1',
|
||||
'escape' => false,
|
||||
'class' => 'btn btn-cta btn-wide',
|
||||
'label' => '<i class="icinga-icon-save"></i> Save Backend'
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ldap authentication backend configuration for this form
|
||||
* Validate that the selected resource is a valid ldap authentication backend
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @see BaseBackendForm::getConfig()
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function getConfig()
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
$prefix = 'backend_' . $this->filterName($this->getBackendName()) . '_';
|
||||
$section = $this->getValue($prefix . 'name');
|
||||
$cfg = array(
|
||||
'backend' => 'ldap',
|
||||
'resource' => $this->getValue($prefix . 'resource'),
|
||||
'user_class' => $this->getValue($prefix . 'user_class'),
|
||||
'user_name_attribute' => $this->getValue($prefix . 'user_name_attribute')
|
||||
);
|
||||
return array($section => $cfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the current configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*
|
||||
* @see BaseBackendForm::isValidAuthenticationBacken
|
||||
*/
|
||||
public function isValidAuthenticationBackend()
|
||||
{
|
||||
if (! Platform::extensionLoaded('ldap')) {
|
||||
/*
|
||||
* It should be possible to run icingaweb without the php ldap extension, when
|
||||
* no ldap backends are needed. When the user tries to create an ldap backend
|
||||
* without ldap installed we need to show him an error.
|
||||
*/
|
||||
$this->addErrorMessage(t('Using ldap is not possible, the php extension "ldap" is not installed.'));
|
||||
if (false === $this->isValidAuthenticationBackend($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the configuration by creating a backend and requesting the user count
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public function isValidAuthenticationBackend(Form $form)
|
||||
{
|
||||
$element = $form->getElement('resource');
|
||||
|
||||
try {
|
||||
$cfg = $this->getConfig();
|
||||
$backendName = 'backend_' . $this->filterName($this->getBackendName()) . '_name';
|
||||
$backendConfig = new Zend_Config($cfg[$this->getValue($backendName)]);
|
||||
$backend = ResourceFactory::create($backendConfig->resource);
|
||||
$testConn = new LdapUserBackend(
|
||||
$backend,
|
||||
$backendConfig->user_class,
|
||||
$backendConfig->user_name_attribute
|
||||
);
|
||||
$testConn->assertAuthenticationPossible();
|
||||
/*
|
||||
if ($testConn->count() === 0) {
|
||||
throw new IcingaException('No Users Found On Directory Server');
|
||||
}
|
||||
*/
|
||||
} catch (Exception $exc) {
|
||||
$this->addErrorMessage(
|
||||
t('Connection Validation Failed: ' . $exc->getMessage())
|
||||
$ldapUserBackend = new LdapUserBackend(
|
||||
ResourceFactory::create($element->getValue()),
|
||||
$form->getElement('user_class')->getValue(),
|
||||
$form->getElement('user_name_attribute')->getValue()
|
||||
);
|
||||
$ldapUserBackend->assertAuthenticationPossible();
|
||||
} catch (Exception $e) {
|
||||
$element->addError(sprintf(t('Connection validation failed: %s'), $e->getMessage()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,233 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\Authentication;
|
||||
|
||||
use Zend_Config;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form for modifying the authentication provider order
|
||||
*/
|
||||
class ReorderForm extends Form
|
||||
{
|
||||
/**
|
||||
* The name of the current backend which will get action buttons for up and down movement
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $backend;
|
||||
|
||||
/**
|
||||
* The current ordering of all backends, required to determine possible changes
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $currentOrder = array();
|
||||
|
||||
/**
|
||||
* Set an array with the current order of all backends
|
||||
*
|
||||
* @param array $order An array containing backend names in the order
|
||||
* they are defined in the authentication.ini
|
||||
*/
|
||||
public function setCurrentOrder(array $order)
|
||||
{
|
||||
$this->currentOrder = $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the authentication backend for which to create the form
|
||||
*
|
||||
* @param string $backend The name of the authentication backend
|
||||
*/
|
||||
public function setBackendName($backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the currently set backend as it will appear in the form
|
||||
*
|
||||
* @return string The name of the backend
|
||||
*/
|
||||
public function getBackendName()
|
||||
{
|
||||
return $this->filterName($this->backend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create this form
|
||||
*
|
||||
* @see Form::create
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
if ($this->moveElementUp($this->backend, $this->currentOrder) !== $this->currentOrder) {
|
||||
$upForm = new Form();
|
||||
|
||||
$upForm->addElement(
|
||||
'hidden',
|
||||
'form_backend_order',
|
||||
array(
|
||||
'required' => true,
|
||||
'value' => join(',', $this->moveElementUp($this->backend, $this->currentOrder))
|
||||
)
|
||||
);
|
||||
$upForm->addElement(
|
||||
'button',
|
||||
'btn_' . $this->getBackendName() . '_reorder_up',
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'escape' => false,
|
||||
'value' => 'btn_' . $this->getBackendName() . '_reorder_up',
|
||||
'name' => 'btn_' . $this->getBackendName() . '_reorder_up',
|
||||
'label' => $this->getView()->icon('up.png', t('Move up in authentication order'))
|
||||
)
|
||||
);
|
||||
|
||||
$this->addSubForm($upForm, 'btn_reorder_up');
|
||||
}
|
||||
|
||||
if ($this->moveElementDown($this->backend, $this->currentOrder) !== $this->currentOrder) {
|
||||
$downForm = new Form();
|
||||
|
||||
$downForm->addElement(
|
||||
'hidden',
|
||||
'form_backend_order',
|
||||
array(
|
||||
'required' => true,
|
||||
'value' => join(',', $this->moveElementDown($this->backend, $this->currentOrder))
|
||||
)
|
||||
);
|
||||
$downForm->addElement(
|
||||
'button',
|
||||
'btn_' . $this->getBackendName() . '_reorder_down',
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'escape' => false,
|
||||
'value' => 'btn_' . $this->getBackendName() . '_reorder_down',
|
||||
'name' => 'btn_' . $this->getBackendName() . '_reorder_down',
|
||||
'label' => $this->getView()->icon('down.png', t('Move down in authentication order'))
|
||||
)
|
||||
);
|
||||
|
||||
$this->addSubForm($downForm, 'btn_reorder_down');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the flattened result of $this->getValues
|
||||
*
|
||||
* @return array The currently set values
|
||||
*
|
||||
* @see Form::getValues()
|
||||
*/
|
||||
protected function getFlattenedValues()
|
||||
{
|
||||
$result = array();
|
||||
foreach (parent::getValues() as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$result += $value;
|
||||
} else {
|
||||
$result[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this form is submitted by testing the submit buttons of both subforms
|
||||
*
|
||||
* @return bool Whether the form has been submitted or not
|
||||
*/
|
||||
public function isSubmitted()
|
||||
{
|
||||
$checkData = $this->getRequest()->getParams();
|
||||
return isset($checkData['btn_' . $this->getBackendName() . '_reorder_up']) ||
|
||||
isset($checkData['btn_' . $this->getBackendName() . '_reorder_down']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the reordered configuration after a reorder button has been submitted
|
||||
*
|
||||
* @param Zend_Config $config The configuration to reorder
|
||||
*
|
||||
* @return array An array containing the reordered configuration
|
||||
*/
|
||||
public function getReorderedConfig(Zend_Config $config)
|
||||
{
|
||||
$originalConfig = $config->toArray();
|
||||
$newOrder = $this->getFlattenedValues();
|
||||
$order = explode(',', $newOrder['form_backend_order']);
|
||||
|
||||
$reordered = array();
|
||||
foreach ($order as $key) {
|
||||
if (isset($originalConfig[$key])) {
|
||||
$reordered[$key] = $originalConfig[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $reordered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static helper for moving an element in an array one slot up, if possible
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* <pre>
|
||||
* $array = array('first', 'second', 'third');
|
||||
* moveElementUp('third', $array); // returns ['first', 'third', 'second']
|
||||
* </pre>
|
||||
*
|
||||
* @param string $key The key to bubble up one slot
|
||||
* @param array $array The array to work with
|
||||
*
|
||||
* @return array The modified array
|
||||
*/
|
||||
protected static function moveElementUp($key, array $array)
|
||||
{
|
||||
for ($i = 0; $i < count($array) - 1; $i++) {
|
||||
if ($array[$i + 1] === $key) {
|
||||
$swap = $array[$i];
|
||||
$array[$i] = $array[$i + 1];
|
||||
$array[$i + 1] = $swap;
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static helper for moving an element in an array one slot down, if possible
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* <pre>
|
||||
* $array = array('first', 'second', 'third');
|
||||
* moveElementDown('first', $array); // returns ['second', 'first', 'third']
|
||||
* </pre>
|
||||
*
|
||||
* @param string $key The key to bubble up one slot
|
||||
* @param array $array The array to work with
|
||||
*
|
||||
* @return array The modified array
|
||||
*/
|
||||
protected static function moveElementDown($key, array $array)
|
||||
{
|
||||
for ($i = 0; $i < count($array) - 1; $i++) {
|
||||
if ($array[$i] === $key) {
|
||||
$swap = $array[$i + 1];
|
||||
$array[$i + 1] = $array[$i];
|
||||
$array[$i] = $swap;
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
322
application/forms/Config/AuthenticationBackendConfigForm.php
Normal file
322
application/forms/Config/AuthenticationBackendConfigForm.php
Normal file
@ -0,0 +1,322 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Form\ConfigForm;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Form\Config\Authentication\DbBackendForm;
|
||||
use Icinga\Form\Config\Authentication\LdapBackendForm;
|
||||
use Icinga\Form\Config\Authentication\AutologinBackendForm;
|
||||
|
||||
class AuthenticationBackendConfigForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* The available resources split by type
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $resources;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_authbackend');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource configuration to use
|
||||
*
|
||||
* @param Config $resources The resource configuration
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @throws ConfigurationError In case no resources are available for authentication
|
||||
*/
|
||||
public function setResourceConfig(Config $resourceConfig)
|
||||
{
|
||||
$resources = array();
|
||||
foreach ($resourceConfig as $name => $resource) {
|
||||
$resources[strtolower($resource->type)][] = $name;
|
||||
}
|
||||
|
||||
if (empty($resources)) {
|
||||
throw new ConfigurationError(t('Could not find any resources for authentication'));
|
||||
}
|
||||
|
||||
$this->resources = $resources;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a form object for the given backend type
|
||||
*
|
||||
* @param string $type The backend type for which to return a form
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
public function getBackendForm($type)
|
||||
{
|
||||
if ($type === 'db') {
|
||||
$form = new DbBackendForm();
|
||||
$form->setResources(isset($this->resources['db']) ? $this->resources['db'] : array());
|
||||
} elseif ($type === 'ldap') {
|
||||
$form = new LdapBackendForm();
|
||||
$form->setResources(isset($this->resources['ldap']) ? $this->resources['ldap'] : array());
|
||||
} elseif ($type === 'autologin') {
|
||||
$form = new AutologinBackendForm();
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf(t('Invalid backend type "%s" provided'), $type));
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a particular authentication backend
|
||||
*
|
||||
* The backend to add is identified by the array-key `name'.
|
||||
*
|
||||
* @param array $values The values to extend the configuration with
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does already exist
|
||||
*/
|
||||
public function add(array $values)
|
||||
{
|
||||
$name = isset($values['name']) ? $values['name'] : '';
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Authentication backend name missing'));
|
||||
} elseif ($this->config->get($name) !== null) {
|
||||
throw new InvalidArgumentException(t('Authentication backend already exists'));
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
$this->config->{$name} = $values;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a particular authentication backend
|
||||
*
|
||||
* @param string $name The name of the backend to edit
|
||||
* @param array $values The values to edit the configuration with
|
||||
*
|
||||
* @return array The edited backend configuration
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does not exist
|
||||
*/
|
||||
public function edit($name, array $values)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Old authentication backend name missing'));
|
||||
} elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) {
|
||||
throw new InvalidArgumentException(t('New authentication backend name missing'));
|
||||
} elseif (($backendConfig = $this->config->get($name)) === null) {
|
||||
throw new InvalidArgumentException(t('Unknown authentication backend provided'));
|
||||
}
|
||||
|
||||
if ($newName !== $name) {
|
||||
// Only remove the old entry if it has changed as the order gets screwed when editing backend names
|
||||
unset($this->config->{$name});
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
$this->config->{$newName} = array_merge($backendConfig->toArray(), $values);
|
||||
return $this->config->{$newName};
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given authentication backend
|
||||
*
|
||||
* @param string $name The name of the backend to remove
|
||||
*
|
||||
* @return array The removed backend configuration
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does not exist
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Authentication backend name missing'));
|
||||
} elseif (($backendConfig = $this->config->get($name)) === null) {
|
||||
throw new InvalidArgumentException(t('Unknown authentication backend provided'));
|
||||
}
|
||||
|
||||
unset($this->config->{$name});
|
||||
return $backendConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the given authentication backend up or down in order
|
||||
*
|
||||
* @param string $name The name of the backend to be moved
|
||||
* @param int $position The new (absolute) position of the backend
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @throws InvalidArgumentException In case the backend does not exist
|
||||
*/
|
||||
public function move($name, $position)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Authentication backend name missing'));
|
||||
} elseif ($this->config->get($name) === null) {
|
||||
throw new InvalidArgumentException(t('Unknown authentication backend provided'));
|
||||
}
|
||||
|
||||
$backendOrder = $this->config->keys();
|
||||
array_splice($backendOrder, array_search($name, $backendOrder), 1);
|
||||
array_splice($backendOrder, $position, 0, $name);
|
||||
|
||||
$newConfig = array();
|
||||
foreach ($backendOrder as $backendName) {
|
||||
$newConfig[$backendName] = $this->config->get($backendName);
|
||||
}
|
||||
|
||||
$config = new Config($newConfig);
|
||||
$this->config = $config->setConfigFile($this->config->getConfigFile());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or edit an authentication backend and save the configuration
|
||||
*
|
||||
* Performs a connectivity validation using the submitted values. A checkbox is
|
||||
* added to the form to skip the check if it fails and redirection is aborted.
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) {
|
||||
$backendForm = $this->getBackendForm($this->getElement('type')->getValue());
|
||||
if (false === $backendForm->isValidAuthenticationBackend($this)) {
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$authBackend = $request->getQuery('auth_backend');
|
||||
try {
|
||||
if ($authBackend === null) { // create new backend
|
||||
$this->add($this->getValues());
|
||||
$message = t('Authentication backend "%s" has been successfully created');
|
||||
} else { // edit existing backend
|
||||
$this->edit($authBackend, $this->getValues());
|
||||
$message = t('Authentication backend "%s" has been successfully changed');
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->save()) {
|
||||
Notification::success(sprintf($message, $this->getElement('name')->getValue()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the form in case an authentication backend is being edited
|
||||
*
|
||||
* @see Form::onRequest()
|
||||
*
|
||||
* @throws ConfigurationError In case the backend name is missing in the request or is invalid
|
||||
*/
|
||||
public function onRequest(Request $request)
|
||||
{
|
||||
$authBackend = $request->getQuery('auth_backend');
|
||||
if ($authBackend !== null) {
|
||||
if ($authBackend === '') {
|
||||
throw new ConfigurationError(t('Authentication backend name missing'));
|
||||
} elseif (false === isset($this->config->{$authBackend})) {
|
||||
throw new ConfigurationError(t('Unknown authentication backend provided'));
|
||||
} elseif (false === isset($this->config->{$authBackend}->backend)) {
|
||||
throw new ConfigurationError(sprintf(t('Backend "%s" has no `backend\' setting'), $authBackend));
|
||||
}
|
||||
|
||||
$configValues = $this->config->{$authBackend}->toArray();
|
||||
$configValues['type'] = $configValues['backend'];
|
||||
$configValues['name'] = $authBackend;
|
||||
$this->populate($configValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a checkbox to be displayed at the beginning of the form
|
||||
* which allows the user to skip the connection validation
|
||||
*
|
||||
* @return Zend_Form_Element
|
||||
*/
|
||||
protected function getForceCreationCheckbox()
|
||||
{
|
||||
return $this->createElement(
|
||||
'checkbox',
|
||||
'force_creation',
|
||||
array(
|
||||
'order' => 0,
|
||||
'ignore' => true,
|
||||
'label' => t('Force Changes'),
|
||||
'description' => t('Check this box to enforce changes without connectivity validation')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$backendTypes = array();
|
||||
$backendType = isset($formData['type']) ? $formData['type'] : 'db';
|
||||
|
||||
if (isset($this->resources['db'])) {
|
||||
$backendTypes['db'] = t('Database');
|
||||
}
|
||||
if (isset($this->resources['ldap']) && ($backendType === 'ldap' || Platform::extensionLoaded('ldap'))) {
|
||||
$backendTypes['ldap'] = 'LDAP';
|
||||
}
|
||||
|
||||
$autologinBackends = array_filter(
|
||||
$this->config->toArray(),
|
||||
function ($authBackendCfg) {
|
||||
return isset($authBackendCfg['backend']) && $authBackendCfg['backend'] === 'autologin';
|
||||
}
|
||||
);
|
||||
if ($backendType === 'autologin' || empty($autologinBackends)) {
|
||||
$backendTypes['autologin'] = t('Autologin');
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'type',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('Backend Type'),
|
||||
'description' => t('The type of the resource to use for this authenticaton backend'),
|
||||
'multiOptions' => $backendTypes
|
||||
)
|
||||
);
|
||||
|
||||
if (isset($formData['force_creation']) && $formData['force_creation']) {
|
||||
// In case another error occured and the checkbox was displayed before
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
}
|
||||
|
||||
$this->addElements($this->getBackendForm($backendType)->createElements($formData)->getElements());
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Form\ConfigForm;
|
||||
|
||||
class AuthenticationBackendReorderForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_reorder_authbackend');
|
||||
$this->setViewScript('form/reorder-authbackend.phtml');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ordered backend names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getBackendOrder()
|
||||
{
|
||||
return $this->config->keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the authentication backend order and save the configuration
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
$formData = $this->getRequestData($request);
|
||||
if (isset($formData['backend_newpos'])) {
|
||||
$configForm = $this->getConfigForm();
|
||||
list($backendName, $position) = explode('|', $formData['backend_newpos'], 2);
|
||||
|
||||
try {
|
||||
if ($configForm->move($backendName, $position)->save()) {
|
||||
Notification::success(t('Authentication order updated!'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the config form for authentication backends
|
||||
*
|
||||
* @return ConfigForm
|
||||
*/
|
||||
protected function getConfigForm()
|
||||
{
|
||||
$form = new AuthenticationBackendConfigForm();
|
||||
$form->setIniConfig($this->config);
|
||||
return $form;
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config;
|
||||
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form for confirming removal of an object
|
||||
*/
|
||||
class ConfirmRemovalForm extends Form
|
||||
{
|
||||
/**
|
||||
* The value of the target to remove
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $removeTarget;
|
||||
|
||||
/**
|
||||
* The name of the target parameter to remove
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $targetName;
|
||||
|
||||
/**
|
||||
* Set the remove target in this field to be a hidden field with $name and value $target
|
||||
*
|
||||
* @param string $name The name to be set in the hidden field
|
||||
* @param string $target The value to be set in the hidden field
|
||||
*/
|
||||
public function setRemoveTarget($name, $target)
|
||||
{
|
||||
$this->targetName = $name;
|
||||
$this->removeTarget = $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the confirmation form
|
||||
*
|
||||
* @see Form::create()
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->setName('form_confirm_removal');
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
$this->targetName,
|
||||
array(
|
||||
'value' => $this->removeTarget,
|
||||
'required' => true
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'button',
|
||||
'btn_submit',
|
||||
array(
|
||||
'type' => 'submit',
|
||||
'escape' => false,
|
||||
'value' => '1',
|
||||
'class' => 'btn btn-cta btn-common',
|
||||
'label' => '<i class="icinga-icon-remove"></i> Confirm Removal'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
118
application/forms/Config/General/ApplicationConfigForm.php
Normal file
118
application/forms/Config/General/ApplicationConfigForm.php
Normal file
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\General;
|
||||
|
||||
use DateTimeZone;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
|
||||
/**
|
||||
* Form class to modify the general application configuration
|
||||
*/
|
||||
class ApplicationConfigForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_general_application');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$languages = array();
|
||||
foreach (Translator::getAvailableLocaleCodes() as $language) {
|
||||
$languages[$language] = $language;
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'global_language',
|
||||
array(
|
||||
'label' => t('Default Language'),
|
||||
'required' => true,
|
||||
'multiOptions' => $languages,
|
||||
'description' => t(
|
||||
'Select the language to use by default. Can be overwritten by a user in his preferences.'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$tzList = array();
|
||||
foreach (DateTimeZone::listIdentifiers() as $tz) {
|
||||
$tzList[$tz] = $tz;
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'global_timezone',
|
||||
array(
|
||||
'label' => t('Default Application Timezone'),
|
||||
'required' => true,
|
||||
'multiOptions' => $tzList,
|
||||
'description' => t(
|
||||
'Select the timezone to be used as the default. User\'s can set their own timezone if'
|
||||
. ' they like to, but this is the timezone to be used as the default setting .'
|
||||
),
|
||||
'value' => date_default_timezone_get()
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'global_modulePath',
|
||||
array(
|
||||
'label' => t('Module Path'),
|
||||
'required' => true,
|
||||
'description' => t(
|
||||
'Contains the directories that will be searched for available modules, separated by '
|
||||
. 'colons. Modules that don\'t exist in these directories can still be symlinked in '
|
||||
. 'the module folder, but won\'t show up in the list of disabled modules.'
|
||||
),
|
||||
'value' => realpath(ICINGAWEB_APPDIR . '/../modules')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'preferences_type',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('User Preference Storage Type'),
|
||||
'multiOptions' => array(
|
||||
'ini' => t('File System (INI Files)'),
|
||||
'db' => t('Database'),
|
||||
'null' => t('Don\'t Store Preferences')
|
||||
)
|
||||
)
|
||||
);
|
||||
if (isset($formData['preferences_type']) && $formData['preferences_type'] === 'db') {
|
||||
$backends = array();
|
||||
foreach (ResourceFactory::getResourceConfigs()->toArray() as $name => $resource) {
|
||||
if ($resource['type'] === 'db') {
|
||||
$backends[$name] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'preferences_resource',
|
||||
array(
|
||||
'required' => true,
|
||||
'multiOptions' => $backends,
|
||||
'label' => t('Database Connection')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
127
application/forms/Config/General/LoggingConfigForm.php
Normal file
127
application/forms/Config/General/LoggingConfigForm.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\General;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Logger\Logger;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Form\Validator\WritablePathValidator;
|
||||
|
||||
class LoggingConfigForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_general_logging');
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see Form::createElements() For the method documentation.
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'select',
|
||||
'logging_log',
|
||||
array(
|
||||
'required' => true,
|
||||
'class' => 'autosubmit',
|
||||
'label' => t('Logging Type'),
|
||||
'description' => t('The type of logging to utilize.'),
|
||||
'multiOptions' => array(
|
||||
'syslog' => 'Syslog',
|
||||
'file' => t('File'),
|
||||
'none' => t('None')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (! isset($formData['logging_log']) || $formData['logging_log'] !== 'none') {
|
||||
$this->addElement(
|
||||
'select',
|
||||
'logging_level',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Logging Level'),
|
||||
'description' => t('The maximum logging level to emit.'),
|
||||
'multiOptions' => array(
|
||||
Logger::$levels[Logger::ERROR] => t('Error'),
|
||||
Logger::$levels[Logger::WARNING] => t('Warning'),
|
||||
Logger::$levels[Logger::INFO] => t('Information'),
|
||||
Logger::$levels[Logger::DEBUG] => t('Debug')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($formData['logging_log']) && $formData['logging_log'] === 'syslog') {
|
||||
$this->addElement(
|
||||
'text',
|
||||
'logging_application',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Application Prefix'),
|
||||
'description' => t('The name of the application by which to prefix syslog messages.'),
|
||||
'value' => 'icingaweb',
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\W]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => 'The application prefix cannot contain any whitespaces.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
/*
|
||||
* Note(el): Since we provide only one possible value for the syslog facility, I opt against exposing
|
||||
* this configuration.
|
||||
*/
|
||||
// $this->addElement(
|
||||
// 'select',
|
||||
// 'logging_facility',
|
||||
// array(
|
||||
// 'required' => true,
|
||||
// 'label' => t('Facility'),
|
||||
// 'description' => t('The syslog facility to utilize.'),
|
||||
// 'multiOptions' => array(
|
||||
// 'user' => 'LOG_USER'
|
||||
// )
|
||||
// )
|
||||
// );
|
||||
} elseif (isset($formData['logging_log']) && $formData['logging_log'] === 'file') {
|
||||
$this->addElement(
|
||||
'text',
|
||||
'logging_file',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('File path'),
|
||||
'description' => t('The full path to the log file to write messages to.'),
|
||||
'value' => $this->getDefaultLogDir(),
|
||||
'validators' => array(new WritablePathValidator())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default logging directory for type 'file'
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultLogDir()
|
||||
{
|
||||
return realpath(Icinga::app()->getApplicationDir('../var/log/icingaweb.log'));
|
||||
}
|
||||
}
|
76
application/forms/Config/GeneralConfigForm.php
Normal file
76
application/forms/Config/GeneralConfigForm.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config;
|
||||
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Form\ConfigForm;
|
||||
use Icinga\Form\Config\General\LoggingConfigForm;
|
||||
use Icinga\Form\Config\General\ApplicationConfigForm;
|
||||
|
||||
/**
|
||||
* Form class for application-wide and logging specific settings
|
||||
*/
|
||||
class GeneralConfigForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* Initialize this configuration form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_general');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$appConfigForm = new ApplicationConfigForm();
|
||||
$loggingConfigForm = new LoggingConfigForm();
|
||||
$this->addElements($appConfigForm->createElements($formData)->getElements());
|
||||
$this->addElements($loggingConfigForm->createElements($formData)->getElements());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
$sections = array();
|
||||
foreach ($this->getValues() as $sectionAndPropertyName => $value) {
|
||||
list($section, $property) = explode('_', $sectionAndPropertyName);
|
||||
if (! isset($sections[$section])) {
|
||||
$sections[$section] = array();
|
||||
}
|
||||
$sections[$section][$property] = $value;
|
||||
}
|
||||
foreach ($sections as $section => $config) {
|
||||
$this->config->{$section} = $config;
|
||||
}
|
||||
|
||||
if ($this->save()) {
|
||||
Notification::success(t('New configuration has successfully been stored'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::onRequest()
|
||||
*/
|
||||
public function onRequest(Request $request)
|
||||
{
|
||||
$values = array();
|
||||
foreach ($this->config as $section => $properties) {
|
||||
foreach ($properties as $name => $value) {
|
||||
$values[$section . '_' . $name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$this->populate($values);
|
||||
}
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config;
|
||||
|
||||
use Icinga\Application\Config as IcingaConfig;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Web\Form\Validator\WritablePathValidator;
|
||||
use Icinga\Web\Form\Decorator\ConditionalHidden;
|
||||
use DateTimeZone;
|
||||
use Zend_Form_Element_Select;
|
||||
use Zend_Config;
|
||||
|
||||
/**
|
||||
* Configuration form for general, application-wide settings
|
||||
*/
|
||||
class GeneralForm extends Form
|
||||
{
|
||||
/**
|
||||
* The base directory of the icingaweb configuration
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $configDir = null;
|
||||
|
||||
/**
|
||||
* The resources to use instead of the factory provided ones (use for testing)
|
||||
*
|
||||
* @var null
|
||||
*/
|
||||
private $resources;
|
||||
|
||||
/**
|
||||
* Set a specific configuration directory to use for configuration specific default paths
|
||||
*
|
||||
* @param string $dir
|
||||
*/
|
||||
public function setConfigDir($dir)
|
||||
{
|
||||
$this->configDir = $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the config path set for this form or the application wide config path if none is set
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @see IcingaConfig::configDir
|
||||
*/
|
||||
public function getConfigDir()
|
||||
{
|
||||
return $this->configDir === null ? IcingaConfig::$configDir : $this->configDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an alternative array of resources that should be used instead of the DBFactory resource set
|
||||
* (used for testing)
|
||||
*
|
||||
* @param array $resources The resources to use for populating the db selection field
|
||||
*/
|
||||
public function setResources(array $resources)
|
||||
{
|
||||
$this->resources = $resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return content of the resources.ini or previously set resources for displaying in the database selection field
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getResources()
|
||||
{
|
||||
if ($this->resources === null) {
|
||||
return ResourceFactory::getResourceConfigs()->toArray();
|
||||
} else {
|
||||
return $this->resources;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a select field for setting the default language
|
||||
*
|
||||
* Possible values are determined by Translator::getAvailableLocaleCodes.
|
||||
*
|
||||
* @param Zend_Config $cfg The "global" section of the config.ini
|
||||
*/
|
||||
private function addLanguageSelection(Zend_Config $cfg)
|
||||
{
|
||||
$languages = array();
|
||||
foreach (Translator::getAvailableLocaleCodes() as $language) {
|
||||
$languages[$language] = $language;
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'language',
|
||||
array(
|
||||
'label' => t('Default Language'),
|
||||
'required' => true,
|
||||
'multiOptions' => $languages,
|
||||
'helptext' => t(
|
||||
'Select the language to use by default. Can be overwritten by a user in his preferences.'
|
||||
),
|
||||
'value' => $cfg->get('language', Translator::DEFAULT_LOCALE)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a select field for setting the default timezone.
|
||||
*
|
||||
* Possible values are determined by DateTimeZone::listIdentifiers
|
||||
*
|
||||
* @param Zend_Config $cfg The "global" section of the config.ini
|
||||
*/
|
||||
private function addTimezoneSelection(Zend_Config $cfg)
|
||||
{
|
||||
$tzList = array();
|
||||
foreach (DateTimeZone::listIdentifiers() as $tz) {
|
||||
$tzList[$tz] = $tz;
|
||||
}
|
||||
$helptext = 'Select the timezone to be used as the default. User\'s can set their own timezone if'
|
||||
. ' they like to, but this is the timezone to be used as the default setting .';
|
||||
|
||||
$this->addElement(
|
||||
'select',
|
||||
'timezone',
|
||||
array(
|
||||
'label' => 'Default Application Timezone',
|
||||
'required' => true,
|
||||
'multiOptions' => $tzList,
|
||||
'helptext' => $helptext,
|
||||
'value' => $cfg->get('timezone', date_default_timezone_get())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add configuration settings for module paths
|
||||
*
|
||||
* @param Zend_Config $cfg The "global" section of the config.ini
|
||||
*/
|
||||
private function addModuleSettings(Zend_Config $cfg)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'module_path',
|
||||
array(
|
||||
'label' => 'Module Path',
|
||||
'required' => true,
|
||||
'helptext' => 'Contains the directories that will be searched for available modules, separated by ' .
|
||||
' colons. Modules that don\'t exist in these directories can still be symlinked in the module ' .
|
||||
' folder, but won\'t show up in the list of disabled modules.',
|
||||
'value' => $cfg->get('modulePath', realpath(ICINGAWEB_APPDIR . '/../modules'))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add form elements for setting the user preference storage backend
|
||||
*
|
||||
* @param Zend_Config $cfg The Zend_config object of preference section
|
||||
*/
|
||||
public function addUserPreferencesDialog(Zend_Config $cfg)
|
||||
{
|
||||
$backend = $cfg->get('type', 'ini');
|
||||
if ($this->getRequest()->get('preferences_type', null) !== null) {
|
||||
$backend = $this->getRequest()->get('preferences_type');
|
||||
}
|
||||
$this->addElement(
|
||||
'select',
|
||||
'preferences_type',
|
||||
array(
|
||||
'label' => 'User Preference Storage Type',
|
||||
'required' => true,
|
||||
'value' => $backend,
|
||||
'multiOptions' => array(
|
||||
'ini' => 'File System (INI Files)',
|
||||
'db' => 'Database',
|
||||
'null' => 'Don\'t Store Preferences'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$backends = array();
|
||||
foreach ($this->getResources() as $name => $resource) {
|
||||
if ($resource['type'] !== 'db') {
|
||||
continue;
|
||||
}
|
||||
$backends[$name] = $name;
|
||||
}
|
||||
|
||||
$txtPreferencesDbResource = new Zend_Form_Element_Select(
|
||||
array(
|
||||
'name' => 'preferences_db_resource',
|
||||
'label' => 'Database Connection',
|
||||
'required' => $backend === 'db',
|
||||
'condition' => $backend === 'db',
|
||||
'value' => $cfg->get('resource'),
|
||||
'multiOptions' => $backends
|
||||
)
|
||||
);
|
||||
$validator = new WritablePathValidator();
|
||||
$validator->setRequireExistence();
|
||||
$this->addElement($txtPreferencesDbResource);
|
||||
|
||||
$txtPreferencesDbResource->addDecorator(new ConditionalHidden());
|
||||
$this->enableAutoSubmit(
|
||||
array(
|
||||
'preferences_type'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the general form, using the provided configuration
|
||||
*
|
||||
* @see Form::create()
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$config = $this->getConfiguration();
|
||||
$global = $config->global;
|
||||
if ($global === null) {
|
||||
$global = new Zend_Config(array());
|
||||
}
|
||||
$preferences = $config->preferences;
|
||||
if ($preferences === null) {
|
||||
$preferences = new Zend_Config(array());
|
||||
}
|
||||
$this->setName('form_config_general');
|
||||
$this->addLanguageSelection($global);
|
||||
$this->addTimezoneSelection($global);
|
||||
$this->addModuleSettings($global);
|
||||
$this->addUserPreferencesDialog($preferences);
|
||||
|
||||
$this->setSubmitLabel('Save Changes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Zend_Config object containing the configuration set in this form
|
||||
*
|
||||
* @return Zend_Config
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
$config = $this->getConfiguration();
|
||||
if ($config->global === null) {
|
||||
$config->global = new Zend_Config(array(), true);
|
||||
}
|
||||
if ($config->preferences === null) {
|
||||
$config->preferences = new Zend_Config(array(), true);
|
||||
}
|
||||
|
||||
$values = $this->getValues();
|
||||
$cfg = clone $config;
|
||||
$cfg->global->language = $values['language'];
|
||||
$cfg->global->timezone = $values['timezone'];
|
||||
$cfg->global->modulePath = $values['module_path'];
|
||||
$cfg->preferences->type = $values['preferences_type'];
|
||||
if ($cfg->preferences->type === 'db') {
|
||||
$cfg->preferences->resource = $values['preferences_db_resource'];
|
||||
}
|
||||
|
||||
return $cfg;
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config;
|
||||
|
||||
use Zend_Config;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Web\Form\Validator\WritablePathValidator;
|
||||
|
||||
/**
|
||||
* Form class for setting the application wide logging configuration
|
||||
*/
|
||||
class LoggingForm extends Form
|
||||
{
|
||||
/**
|
||||
* Return the default logging directory for type "file"
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultLogDir()
|
||||
{
|
||||
return realpath(Icinga::app()->getApplicationDir() . '/../var/log/icingaweb.log');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create this logging configuration form
|
||||
*
|
||||
* @see Form::create()
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->setName('form_config_logging');
|
||||
|
||||
$config = $this->getConfiguration();
|
||||
if (($loggingConfig = $config->logging) === null) {
|
||||
$loggingConfig = new Zend_Config(array());
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'logging_enable',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Logging Enabled'),
|
||||
'helptext' => t('Check this to enable logging.'),
|
||||
'value' => $loggingConfig->enable ? 1 : 0
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'logging_level',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Logging Level'),
|
||||
'helptext' => t('The maximum loglevel to emit.'),
|
||||
'value' => intval($loggingConfig->get('level', 0)),
|
||||
'multiOptions' => array(
|
||||
0 => t('Error'),
|
||||
1 => t('Warning'),
|
||||
2 => t('Information'),
|
||||
3 => t('Debug')
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'logging_type',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Logging Type'),
|
||||
'helptext' => t('The type of logging to utilize.'),
|
||||
'value' => $loggingConfig->get('type', 'file'),
|
||||
'multiOptions' => array(
|
||||
'file' => t('File'),
|
||||
'syslog' => 'Syslog'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->enableAutoSubmit(array('logging_type'));
|
||||
|
||||
switch ($this->getRequest()->getParam('logging_type', $loggingConfig->get('type', 'file')))
|
||||
{
|
||||
case 'syslog':
|
||||
$this->addElement(
|
||||
'text',
|
||||
'logging_application',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Application Prefix'),
|
||||
'helptext' => t('The name of the application by which to prefix syslog messages.'),
|
||||
'value' => $loggingConfig->get('application', 'icingaweb'),
|
||||
'validators' => array(
|
||||
array(
|
||||
'Regex',
|
||||
false,
|
||||
array(
|
||||
'pattern' => '/^[^\W]+$/',
|
||||
'messages' => array(
|
||||
'regexNotMatch' => 'The application prefix cannot contain any whitespaces.'
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'logging_facility',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Facility'),
|
||||
'helptext' => t('The Syslog facility to utilize.'),
|
||||
'value' => $loggingConfig->get('facility', 'LOG_USER'),
|
||||
'multiOptions' => array(
|
||||
'LOG_USER' => 'LOG_USER'
|
||||
)
|
||||
)
|
||||
);
|
||||
break;
|
||||
case 'file':
|
||||
default:
|
||||
$this->addElement(
|
||||
'text',
|
||||
'logging_target',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'helptext' => t('The logfile to write messages to.'),
|
||||
'value' => $loggingConfig->target ? $loggingConfig->target : $this->getDefaultLogDir(),
|
||||
'validators' => array(new WritablePathValidator())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->setSubmitLabel('{{SAVE_ICON}} Save Changes');
|
||||
}
|
||||
|
||||
public function isValid($data) {
|
||||
foreach ($this->getElements() as $key => $element) {
|
||||
// Initialize all empty elements with their default values.
|
||||
if (!isset($data[$key])) {
|
||||
$data[$key] = $element->getValue();
|
||||
}
|
||||
}
|
||||
return parent::isValid($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Zend_Config object containing the state defined in this form
|
||||
*
|
||||
* @return Zend_Config The config defined in this form
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
$values = $this->getValues();
|
||||
$cfg = $this->getConfiguration()->toArray();
|
||||
|
||||
$cfg['logging']['enable'] = $values['logging_enable'] == 1;
|
||||
$cfg['logging']['level'] = $values['logging_level'];
|
||||
|
||||
switch ($values['logging_type'])
|
||||
{
|
||||
case 'file':
|
||||
$cfg['logging']['type'] = 'file';
|
||||
$cfg['logging']['target'] = $values['logging_target'];
|
||||
break;
|
||||
case 'syslog':
|
||||
$cfg['logging']['type'] = 'syslog';
|
||||
$cfg['logging']['application'] = $values['logging_application'];
|
||||
$cfg['logging']['facility'] = $values['logging_facility'];
|
||||
break;
|
||||
}
|
||||
|
||||
return new Zend_Config($cfg);
|
||||
}
|
||||
}
|
130
application/forms/Config/Resource/DbResourceForm.php
Normal file
130
application/forms/Config/Resource/DbResourceForm.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\Resource;
|
||||
|
||||
use Exception;
|
||||
use Zend_Config;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Form\Element\Number;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying database resources
|
||||
*/
|
||||
class DbResourceForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource_db');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'select',
|
||||
'db',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Type'),
|
||||
'description' => t('The type of SQL database'),
|
||||
'multiOptions' => array(
|
||||
'mysql' => 'MySQL',
|
||||
'pgsql' => 'PostgreSQL'
|
||||
//'oracle' => 'Oracle'
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'host',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Host'),
|
||||
'description' => t('The hostname of the database'),
|
||||
'value' => 'localhost'
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
new Number(
|
||||
array(
|
||||
'required' => true,
|
||||
'name' => 'port',
|
||||
'label' => t('Port'),
|
||||
'description' => t('The port to use'),
|
||||
'value' => 3306
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'dbname',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Name'),
|
||||
'description' => t('The name of the database to use')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'username',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Username'),
|
||||
'description' => t('The user name to use for authentication')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'password',
|
||||
'password',
|
||||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Password'),
|
||||
'description' => t('The password to use for authentication')
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the current configuration points to a valid resource
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
if (false === $this->isValidResource($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the resource configuration by trying to connect with it
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public function isValidResource(Form $form)
|
||||
{
|
||||
try {
|
||||
$resource = ResourceFactory::createResource(new Zend_Config($form->getValues()));
|
||||
$resource->getConnection()->getConnection();
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
50
application/forms/Config/Resource/FileResourceForm.php
Normal file
50
application/forms/Config/Resource/FileResourceForm.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\Resource;
|
||||
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Form\Validator\ReadablePathValidator;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying file resources
|
||||
*/
|
||||
class FileResourceForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource_file');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'filename',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'description' => t('The filename to fetch information from'),
|
||||
'validators' => array(new ReadablePathValidator())
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'fields',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Pattern'),
|
||||
'description' => t('The regular expression by which to identify columns')
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
116
application/forms/Config/Resource/LdapResourceForm.php
Normal file
116
application/forms/Config/Resource/LdapResourceForm.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\Resource;
|
||||
|
||||
use Exception;
|
||||
use Zend_Config;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Form\Element\Number;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying ldap resources
|
||||
*/
|
||||
class LdapResourceForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource_ldap');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'hostname',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Host'),
|
||||
'description' => t('The hostname or address of the LDAP server to use for authentication'),
|
||||
'value' => 'localhost'
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
new Number(
|
||||
array(
|
||||
'required' => true,
|
||||
'name' => 'port',
|
||||
'label' => t('Port'),
|
||||
'description' => t('The port of the LDAP server to use for authentication'),
|
||||
'value' => 389
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'root_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Root DN'),
|
||||
'description' => t('The path where users can be found on the ldap server')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'text',
|
||||
'bind_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Bind DN'),
|
||||
'description' => t('The user dn to use for querying the ldap server')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'password',
|
||||
'bind_pw',
|
||||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Bind Password'),
|
||||
'description' => t('The password to use for querying the ldap server')
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the current configuration points to a valid resource
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
if (false === $this->isValidResource($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the resource configuration by trying to connect with it
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public function isValidResource(Form $form)
|
||||
{
|
||||
try {
|
||||
$resource = ResourceFactory::createResource(new Zend_Config($form->getValues()));
|
||||
$resource->connect();
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
77
application/forms/Config/Resource/LivestatusResourceForm.php
Normal file
77
application/forms/Config/Resource/LivestatusResourceForm.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\Resource;
|
||||
|
||||
use Exception;
|
||||
use Zend_Config;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying livestatus resources
|
||||
*/
|
||||
class LivestatusResourceForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource_livestatus');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'socket',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Socket'),
|
||||
'description' => t('The path to your livestatus socket used for querying monitoring data'),
|
||||
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/rw/livestatus')
|
||||
)
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the current configuration points to a valid resource
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
if (false === $this->isValidResource($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the resource configuration by trying to connect with it
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public function isValidResource(Form $form)
|
||||
{
|
||||
try {
|
||||
$resource = ResourceFactory::createResource(new Zend_Config($form->getValues()));
|
||||
$resource->connect()->disconnect();
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
252
application/forms/Config/ResourceConfigForm.php
Normal file
252
application/forms/Config/ResourceConfigForm.php
Normal file
@ -0,0 +1,252 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Form\ConfigForm;
|
||||
use Icinga\Form\Config\Resource\DbResourceForm;
|
||||
use Icinga\Form\Config\Resource\FileResourceForm;
|
||||
use Icinga\Form\Config\Resource\LdapResourceForm;
|
||||
use Icinga\Form\Config\Resource\LivestatusResourceForm;
|
||||
use Icinga\Application\Platform;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
|
||||
class ResourceConfigForm extends ConfigForm
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a form object for the given resource type
|
||||
*
|
||||
* @param string $type The resource type for which to return a form
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
public function getResourceForm($type)
|
||||
{
|
||||
if ($type === 'db') {
|
||||
return new DbResourceForm();
|
||||
} elseif ($type === 'ldap') {
|
||||
return new LdapResourceForm();
|
||||
} elseif ($type === 'livestatus') {
|
||||
return new LivestatusResourceForm();
|
||||
} elseif ($type === 'file') {
|
||||
return new FileResourceForm();
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf(t('Invalid resource type "%s" provided'), $type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a particular resource
|
||||
*
|
||||
* The backend to add is identified by the array-key `name'.
|
||||
*
|
||||
* @param array $values The values to extend the configuration with
|
||||
*
|
||||
* @return self
|
||||
*
|
||||
* @thrwos InvalidArgumentException In case the resource does already exist
|
||||
*/
|
||||
public function add(array $values)
|
||||
{
|
||||
$name = isset($values['name']) ? $values['name'] : '';
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Resource name missing'));
|
||||
} elseif ($this->config->{$name} !== null) {
|
||||
throw new InvalidArgumentException(t('Resource already exists'));
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
$this->config->{$name} = $values;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a particular resource
|
||||
*
|
||||
* @param string $name The name of the resource to edit
|
||||
* @param array $values The values to edit the configuration with
|
||||
*
|
||||
* @return array The edited configuration
|
||||
*
|
||||
* @throws InvalidArgumentException In case the resource does not exist
|
||||
*/
|
||||
public function edit($name, array $values)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Old resource name missing'));
|
||||
} elseif (! ($newName = isset($values['name']) ? $values['name'] : '')) {
|
||||
throw new InvalidArgumentException(t('New resource name missing'));
|
||||
} elseif (($resourceConfig = $this->config->get($name)) === null) {
|
||||
throw new InvalidArgumentException(t('Unknown resource provided'));
|
||||
}
|
||||
|
||||
unset($values['name']);
|
||||
unset($this->config->{$name});
|
||||
$this->config->{$newName} = array_merge($resourceConfig->toArray(), $values);
|
||||
return $this->config->{$newName};
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a particular resource
|
||||
*
|
||||
* @param string $name The name of the resource to remove
|
||||
*
|
||||
* @return array The removed resource configuration
|
||||
*
|
||||
* @throws InvalidArgumentException In case the resource does not exist
|
||||
*/
|
||||
public function remove($name)
|
||||
{
|
||||
if (! $name) {
|
||||
throw new InvalidArgumentException(t('Resource name missing'));
|
||||
} elseif (($resourceConfig = $this->config->get($name)) === null) {
|
||||
throw new InvalidArgumentException(t('Unknown resource provided'));
|
||||
}
|
||||
|
||||
unset($this->config->{$name});
|
||||
return $resourceConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or edit a resource and save the configuration
|
||||
*
|
||||
* Performs a connectivity validation using the submitted values. A checkbox is
|
||||
* added to the form to skip the check if it fails and redirection is aborted.
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
if (($el = $this->getElement('force_creation')) === null || false === $el->isChecked()) {
|
||||
$resourceForm = $this->getResourceForm($this->getElement('type')->getValue());
|
||||
if (method_exists($resourceForm, 'isValidResource') && false === $resourceForm->isValidResource($this)) {
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$resource = $request->getQuery('resource');
|
||||
try {
|
||||
if ($resource === null) { // create new resource
|
||||
$this->add($this->getValues());
|
||||
$message = t('Resource "%s" has been successfully created');
|
||||
} else { // edit existing resource
|
||||
$this->edit($resource, $this->getValues());
|
||||
$message = t('Resource "%s" has been successfully changed');
|
||||
}
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->save()) {
|
||||
Notification::success(sprintf($message, $this->getElement('name')->getValue()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the form in case a resource is being edited
|
||||
*
|
||||
* @see Form::onRequest()
|
||||
*
|
||||
* @throws ConfigurationError In case the backend name is missing in the request or is invalid
|
||||
*/
|
||||
public function onRequest(Request $request)
|
||||
{
|
||||
$resource = $request->getQuery('resource');
|
||||
if ($resource !== null) {
|
||||
if ($resource === '') {
|
||||
throw new ConfigurationError(t('Resource name missing'));
|
||||
} elseif (false === isset($this->config->{$resource})) {
|
||||
throw new ConfigurationError(t('Unknown resource provided'));
|
||||
}
|
||||
|
||||
$configValues = $this->config->{$resource}->toArray();
|
||||
$configValues['name'] = $resource;
|
||||
$this->populate($configValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a checkbox to be displayed at the beginning of the form
|
||||
* which allows the user to skip the connection validation
|
||||
*
|
||||
* @return Zend_Form_Element
|
||||
*/
|
||||
protected function getForceCreationCheckbox()
|
||||
{
|
||||
return $this->createElement(
|
||||
'checkbox',
|
||||
'force_creation',
|
||||
array(
|
||||
'order' => 0,
|
||||
'ignore' => true,
|
||||
'label' => t('Force Changes'),
|
||||
'description' => t('Check this box to enforce changes without connectivity validation')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElemeents()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$resourceType = isset($formData['type']) ? $formData['type'] : 'db';
|
||||
|
||||
$resourceTypes = array(
|
||||
'file' => t('File'),
|
||||
'livestatus' => 'Livestatus',
|
||||
);
|
||||
if ($resourceType === 'ldap' || Platform::extensionLoaded('ldap')) {
|
||||
$resourceTypes['ldap'] = 'LDAP';
|
||||
}
|
||||
if ($resourceType === 'db' || Platform::extensionLoaded('mysql') || Platform::extensionLoaded('pgsql')) {
|
||||
$resourceTypes['db'] = t('SQL Database');
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'description' => t('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'type',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('Resource Type'),
|
||||
'description' => t('The type of resource'),
|
||||
'multiOptions' => $resourceTypes,
|
||||
'value' => $resourceType
|
||||
)
|
||||
);
|
||||
|
||||
if (isset($formData['force_creation']) && $formData['force_creation']) {
|
||||
// In case another error occured and the checkbox was displayed before
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
}
|
||||
|
||||
$this->addElements($this->getResourceForm($resourceType)->createElements($formData)->getElements());
|
||||
}
|
||||
}
|
@ -1,507 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Application\Platform;
|
||||
use Zend_Config;
|
||||
use Zend_Form_Element_Checkbox;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Web\Form\Element\Number;
|
||||
use Icinga\Web\Form\Decorator\HelpText;
|
||||
|
||||
class ResourceForm extends Form
|
||||
{
|
||||
/**
|
||||
* The resource
|
||||
*
|
||||
* @var Zend_Config
|
||||
*/
|
||||
protected $resource;
|
||||
|
||||
/**
|
||||
* The (new) name of the resource
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The old name of the resource
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $oldName;
|
||||
|
||||
/**
|
||||
* Set the current resource name
|
||||
*
|
||||
* @param string $name The name to set
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current resource name
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
$name = $this->getValue('resource_all_name');
|
||||
if (!$name) {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the original name of the resource
|
||||
*
|
||||
* @param string $name The name to set
|
||||
*/
|
||||
public function setOldName($name)
|
||||
{
|
||||
$this->oldName = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the resource name that was initially set
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getOldName()
|
||||
{
|
||||
$oldName = $this->getValue('resource_all_name_old');
|
||||
if (!$oldName) {
|
||||
return $this->oldName;
|
||||
}
|
||||
|
||||
return $oldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the resource configuration to edit.
|
||||
*
|
||||
* @param Zend_Config $resource The config to set
|
||||
*/
|
||||
public function setResource(Zend_Config $resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current resource configuration.
|
||||
*
|
||||
* @return Zend_Config
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
if (!isset($this->resource)) {
|
||||
$this->resource = new Zend_Config(array('type' => 'db'));
|
||||
}
|
||||
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
protected function addDbForm()
|
||||
{
|
||||
$this->addElement(
|
||||
'select',
|
||||
'resource_db_db',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Type'),
|
||||
'helptext' => t('The type of SQL database you want to create.'),
|
||||
'value' => $this->getResource()->get('db', 'mysql'),
|
||||
'multiOptions' => array(
|
||||
'mysql' => 'MySQL',
|
||||
'pgsql' => 'PostgreSQL'
|
||||
//'oracle' => 'Oracle'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_db_host',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Host'),
|
||||
'helptext' => t('The hostname of the database.'),
|
||||
'value' => $this->getResource()->get('host', 'localhost')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
new Number(
|
||||
array(
|
||||
'name' => 'resource_db_port',
|
||||
'required' => true,
|
||||
'label' => t('Port'),
|
||||
'helptext' => t('The port to use.'),
|
||||
'value' => $this->getResource()->get('port', 3306)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_db_dbname',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Name'),
|
||||
'helptext' => t('The name of the database to use'),
|
||||
'value' => $this->getResource()->get('dbname', '')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_db_username',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Username'),
|
||||
'helptext' => t('The user name to use for authentication.'),
|
||||
'value' => $this->getResource()->get('username', '')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'password',
|
||||
'resource_db_password',
|
||||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Password'),
|
||||
'helptext' => t('The password to use for authentication'),
|
||||
'value' => $this->getResource()->get('password', '')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function addStatusdatForm()
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_statusdat_status_file',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'helptext' => t('Location of your icinga status.dat file'),
|
||||
'value' => $this->getResource()->get('status_file', '/usr/local/icinga/var/status.dat')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_statusdat_object_file',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'helptext' => t('Location of your icinga objects.cache file'),
|
||||
'value' => $this->getResource()->get('status_file', '/usr/local/icinga/var/objects.cache')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function addLivestatusForm()
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_livestatus_socket',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Socket'),
|
||||
'helptext' => t('The path to your livestatus socket used for querying monitoring data'),
|
||||
'value' => $this->getResource()->get('socket', '/usr/local/icinga/var/rw/livestatus')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function addLdapForm()
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_ldap_hostname',
|
||||
array(
|
||||
'required' => true,
|
||||
'allowEmpty' => false,
|
||||
'label' => t('Host'),
|
||||
'helptext' => t('The hostname or address of the LDAP server to use for authentication'),
|
||||
'value' => $this->getResource()->get('hostname', 'localhost')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_ldap_root_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Root DN'),
|
||||
'helptext' => t('The path where users can be found on the ldap server'),
|
||||
'value' => $this->getResource()->get('root_dn', 'ou=people,dc=icinga,dc=org')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_ldap_bind_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Bind DN'),
|
||||
'helptext' => t('The user dn to use for querying the ldap server'),
|
||||
'value' => $this->getResource()->get('bind_dn', 'cn=admin,cn=config')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'password',
|
||||
'resource_ldap_bind_pw',
|
||||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Bind Password'),
|
||||
'helptext' => t('The password to use for querying the ldap server'),
|
||||
'value' => $this->getResource()->get('bind_pw', '')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function addFileForm()
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_file_filename',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'helptext' => t('The filename to fetch information from'),
|
||||
'value' => $this->getResource()->get('filename', '')
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_file_fields',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Pattern'),
|
||||
'helptext' => t('The regular expression by which to identify columns'),
|
||||
'value' => $this->getResource()->get('fields', '')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function addNameFields()
|
||||
{
|
||||
$this->addElement(
|
||||
'text',
|
||||
'resource_all_name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'helptext' => t('The unique name of this resource'),
|
||||
'value' => $this->getName()
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'hidden',
|
||||
'resource_all_name_old',
|
||||
array(
|
||||
'value' => $this->getOldName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add checkbox at the beginning of the form which allows to skip connection validation
|
||||
*/
|
||||
protected function addForceCreationCheckbox()
|
||||
{
|
||||
$checkbox = new Zend_Form_Element_Checkbox(
|
||||
array(
|
||||
'order' => 0,
|
||||
'name' => 'resource_force_creation',
|
||||
'label' => t('Force Changes'),
|
||||
'helptext' => t('Check this box to enforce changes without connectivity validation')
|
||||
)
|
||||
);
|
||||
$checkbox->addDecorator(new HelpText());
|
||||
$this->addElement($checkbox);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a select box for choosing the type to use for this backend
|
||||
*/
|
||||
protected function addTypeSelectionBox()
|
||||
{
|
||||
$this->addElement(
|
||||
'select',
|
||||
'resource_type',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Type'),
|
||||
'helptext' => t('The type of resource'),
|
||||
'value' => $this->getResource()->type,
|
||||
'multiOptions' => array(
|
||||
'db' => t('SQL Database'),
|
||||
'ldap' => 'LDAP',
|
||||
'statusdat' => 'Status.dat',
|
||||
'livestatus' => 'Livestatus',
|
||||
'file' => t('File')
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->enableAutoSubmit(array('resource_type'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate this form with the Zend validation mechanism and perform a validation of the connection
|
||||
*
|
||||
* If validation fails, the 'resource_force_creation' checkbox is prepended to the form to allow users to
|
||||
* skip the connection validation
|
||||
*
|
||||
* @param array $data The form input to validate
|
||||
*
|
||||
* @return bool True when validation succeeded, false if not
|
||||
*/
|
||||
public function isValid($data)
|
||||
{
|
||||
if (!parent::isValid($data)) {
|
||||
return false;
|
||||
}
|
||||
if (isset($data['resource_force_creation']) && $data['resource_force_creation']) {
|
||||
return true;
|
||||
}
|
||||
if (!$this->isValidResource()) {
|
||||
$this->addForceCreationCheckbox();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the changed resource is a valid resource, by instantiating it and
|
||||
* checking if a connection is possible
|
||||
*
|
||||
* @return bool True when a connection to the resource is possible
|
||||
*/
|
||||
public function isValidResource()
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
|
||||
try {
|
||||
switch ($config->type) {
|
||||
case 'db':
|
||||
/*
|
||||
* It should be possible to run icingaweb without the pgsql or mysql extension or Zend-Pdo-Classes,
|
||||
* in case they aren't actually used. When the user tries to create a resource that depends on an
|
||||
* uninstalled extension, an error should be displayed.
|
||||
*/
|
||||
if ($config->db === 'mysql' && ! Platform::extensionLoaded('mysql')) {
|
||||
$this->addErrorMessage(
|
||||
t('You need to install the php extension "mysql" and the ' .
|
||||
'Zend_Pdo_Mysql classes to use MySQL database resources.')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($config->db === 'pgsql' && ! Platform::extensionLoaded('pgsql')) {
|
||||
$this->addErrorMessage(
|
||||
t('You need to install the php extension "pgsql" and the ' .
|
||||
'Zend_Pdo_Pgsql classes to use PostgreSQL database resources.')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$resource = ResourceFactory::createResource($config);
|
||||
$resource->getConnection()->getConnection();
|
||||
break;
|
||||
case 'statusdat':
|
||||
if (!file_exists($config->object_file) || !file_exists($config->status_file)) {
|
||||
$this->addErrorMessage(
|
||||
t('Connectivity validation failed, the provided file does not exist.')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'livestatus':
|
||||
$resource = ResourceFactory::createResource($config);
|
||||
$resource->connect()->disconnect();
|
||||
break;
|
||||
case 'ldap':
|
||||
$resource = ResourceFactory::createResource($config);
|
||||
$resource->connect();
|
||||
break;
|
||||
case 'file':
|
||||
if (!file_exists($config->filename)) {
|
||||
$this->addErrorMessage(
|
||||
t('Connectivity validation failed, the provided file does not exist.')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->addErrorMessage(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$this->addNameFields();
|
||||
$this->addTypeSelectionBox();
|
||||
|
||||
switch ($this->getRequest()->getParam('resource_type', $this->getResource()->type)) {
|
||||
case 'db':
|
||||
$this->addDbForm();
|
||||
break;
|
||||
case 'statusdat':
|
||||
$this->addStatusdatForm();
|
||||
break;
|
||||
case 'livestatus':
|
||||
$this->addLivestatusForm();
|
||||
break;
|
||||
case 'ldap':
|
||||
$this->addLdapForm();
|
||||
break;
|
||||
case 'file':
|
||||
$this->addFileForm();
|
||||
break;
|
||||
}
|
||||
|
||||
$this->setSubmitLabel('{{SAVE_ICON}} Save Changes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a configuration containing the backend settings entered in this form
|
||||
*
|
||||
* @return Zend_Config The updated configuration for this backend
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
$values = $this->getValues();
|
||||
|
||||
$result = array('type' => $values['resource_type']);
|
||||
foreach ($values as $key => $value) {
|
||||
if ($key !== 'resource_type' && $key !== 'resource_all_name' && $key !== 'resource_all_name_old') {
|
||||
$configKey = explode('_', $key, 3);
|
||||
if (count($configKey) === 3) {
|
||||
$result[$configKey[2]] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Zend_Config($result);
|
||||
}
|
||||
}
|
68
application/forms/ConfigForm.php
Normal file
68
application/forms/ConfigForm.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Config\PreservingIniWriter;
|
||||
|
||||
/**
|
||||
* Form base-class providing standard functionality for configuration forms
|
||||
*/
|
||||
class ConfigForm extends Form
|
||||
{
|
||||
/**
|
||||
* The configuration to work with
|
||||
*
|
||||
* @var Config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Set the configuration to use when populating the form or when saving the user's input
|
||||
*
|
||||
* @param Config $config The configuration to use
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setIniConfig(Config $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist the current configuration to disk
|
||||
*
|
||||
* If an error occurs the user is shown a view describing the issue and displaying the raw INI configuration.
|
||||
*
|
||||
* @return bool Whether the configuration could be persisted
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$writer = new PreservingIniWriter(
|
||||
array(
|
||||
'config' => $this->config,
|
||||
'filename' => $this->config->getConfigFile()
|
||||
)
|
||||
);
|
||||
|
||||
try {
|
||||
$writer->write();
|
||||
} catch (Exception $e) {
|
||||
$this->addDecorator('ViewScript', array(
|
||||
'viewModule' => 'default',
|
||||
'viewScript' => 'showConfiguration.phtml',
|
||||
'errorMessage' => $e->getMessage(),
|
||||
'configString' => $writer->render(),
|
||||
'filePath' => $this->config->getConfigFile()
|
||||
));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
22
application/forms/ConfirmRemovalForm.php
Normal file
22
application/forms/ConfirmRemovalForm.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form;
|
||||
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form for confirming removal of an object
|
||||
*/
|
||||
class ConfirmRemovalForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initalize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_confirm_removal');
|
||||
$this->setSubmitLabel(t('Confirm Removal'));
|
||||
}
|
||||
}
|
@ -5,12 +5,8 @@
|
||||
namespace Icinga\Form\Dashboard;
|
||||
|
||||
use Icinga\Application\Config as IcingaConfig;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Widget\Dashboard;
|
||||
use Zend_Form_Element_Text;
|
||||
use Zend_Form_Element_Submit;
|
||||
use Zend_Form_Element_Hidden;
|
||||
use Zend_Form_Element_Select;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Form to add an url a dashboard pane
|
||||
@ -18,124 +14,103 @@ use Zend_Form_Element_Select;
|
||||
class AddUrlForm extends Form
|
||||
{
|
||||
/**
|
||||
* Add a selection box for different panes to the form
|
||||
*
|
||||
* @param Dashboard $dashboard The dashboard to retrieve the panes from
|
||||
* Initialize this form
|
||||
*/
|
||||
private function addPaneSelectionBox(Dashboard $dashboard)
|
||||
public function init()
|
||||
{
|
||||
$selectPane = new Zend_Form_Element_Select(
|
||||
'pane',
|
||||
array(
|
||||
'label' => 'Dashboard',
|
||||
'required' => true,
|
||||
'style' => 'display:inline-block;',
|
||||
|
||||
'multiOptions' => $dashboard->getPaneKeyTitleArray()
|
||||
)
|
||||
);
|
||||
|
||||
$newDashboardBtn = new Zend_Form_Element_Submit(
|
||||
'create_new_pane',
|
||||
array(
|
||||
'label' => 'Create A New Pane',
|
||||
'required' => false,
|
||||
'class' => 'btn btn-default',
|
||||
'style' => 'display:inline-block'
|
||||
)
|
||||
);
|
||||
|
||||
$newDashboardBtn->removeDecorator('DtDdWrapper');
|
||||
$selectPane->removeDecorator('DtDdWrapper');
|
||||
$selectPane->removeDecorator('htmlTag');
|
||||
|
||||
$this->addElement($selectPane);
|
||||
$this->addElement($newDashboardBtn);
|
||||
$this->enableAutoSubmit(array('create_new_pane'));
|
||||
$this->setName('form_dashboard_addurl');
|
||||
$this->setSubmitLabel(t('Add To Dashboard'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a textfield for creating a new pane to this form
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
private function addNewPaneTextField($showExistingButton = true)
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$txtCreatePane = new Zend_Form_Element_Text(
|
||||
'pane',
|
||||
array(
|
||||
'label' => 'New Dashboard Title',
|
||||
'required' => true,
|
||||
'style' => 'display:inline-block'
|
||||
)
|
||||
);
|
||||
|
||||
// Marks this field as a new pane (and prevents the checkbox being displayed when validation errors occur)
|
||||
$markAsNewPane = new Zend_Form_Element_Hidden(
|
||||
'create_new_pane',
|
||||
array(
|
||||
'required' => true,
|
||||
'value' => 1
|
||||
)
|
||||
);
|
||||
|
||||
$cancelDashboardBtn = new Zend_Form_Element_Submit(
|
||||
'use_existing_dashboard',
|
||||
array(
|
||||
'class' => 'btn',
|
||||
'escape' => false,
|
||||
'label' => 'Use An Existing Dashboard',
|
||||
'required' => false
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
$cancelDashboardBtn->removeDecorator('DtDdWrapper');
|
||||
$txtCreatePane->removeDecorator('DtDdWrapper');
|
||||
$txtCreatePane->removeDecorator('htmlTag');
|
||||
|
||||
$this->addElement($txtCreatePane);
|
||||
if ($showExistingButton) {
|
||||
$this->addElement($cancelDashboardBtn);
|
||||
}
|
||||
$this->addElement($markAsNewPane);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add elements to this form (used by extending classes)
|
||||
*/
|
||||
protected function create()
|
||||
{
|
||||
$dashboard = new Dashboard();
|
||||
$this->setName('form_dashboard_add');
|
||||
$dashboard->readConfig(IcingaConfig::app('dashboard/dashboard'));
|
||||
$this->addElement(
|
||||
'text',
|
||||
'url',
|
||||
array(
|
||||
'label' => 'Url',
|
||||
'required' => true,
|
||||
'value' => htmlspecialchars_decode($this->getRequest()->getParam('url', ''))
|
||||
'required' => true,
|
||||
'label' => t('Url'),
|
||||
'helptext' => t('The url being loaded in the dashlet')
|
||||
)
|
||||
);
|
||||
$elems = $dashboard->getPaneKeyTitleArray();
|
||||
|
||||
if (empty($elems) || // show textfield instead of combobox when no pane is available
|
||||
($this->getRequest()->getPost('create_new_pane', '0') && // or when a new pane should be created (+ button)
|
||||
!$this->getRequest()->getPost('use_existing_dashboard', '0')) // and the user didn't click the 'use
|
||||
// existing' button
|
||||
$paneSelectionValues = $this->getDashboardPaneSelectionValues();
|
||||
if (empty($paneSelectionValues) ||
|
||||
((isset($formData['create_new_pane']) && $formData['create_new_pane'] != false) &&
|
||||
(false === isset($formData['use_existing_dashboard']) || $formData['use_existing_dashboard'] != true))
|
||||
) {
|
||||
$this->addNewPaneTextField(!empty($elems));
|
||||
$this->addElement(
|
||||
'text',
|
||||
'pane',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t("The New Pane's Title"),
|
||||
'style' => 'display: inline-block'
|
||||
)
|
||||
);
|
||||
$this->addElement( // Prevent the button from being displayed again on validation errors
|
||||
'hidden',
|
||||
'create_new_pane',
|
||||
array(
|
||||
'value' => 1
|
||||
)
|
||||
);
|
||||
if (false === empty($paneSelectionValues)) {
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'use_existing_dashboard',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => t('Use An Existing Pane'),
|
||||
'style' => 'display: inline-block'
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$this->addPaneSelectionBox($dashboard);
|
||||
$this->addElement(
|
||||
'select',
|
||||
'pane',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Pane'),
|
||||
'style' => 'display: inline-block;',
|
||||
'multiOptions' => $paneSelectionValues
|
||||
)
|
||||
);
|
||||
$this->addElement(
|
||||
'submit',
|
||||
'create_new_pane',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'label' => t('Create A New Pane'),
|
||||
'style' => 'display: inline-block'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'text',
|
||||
'component',
|
||||
array(
|
||||
'label' => 'Title',
|
||||
'required' => true,
|
||||
'required' => true,
|
||||
'label' => t('Title'),
|
||||
'helptext' => t('The title for the dashlet')
|
||||
)
|
||||
);
|
||||
$this->setSubmitLabel("Add To Dashboard");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the names and titles of the available dashboard panes as key-value array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDashboardPaneSelectionValues()
|
||||
{
|
||||
$dashboard = new Dashboard();
|
||||
$dashboard->readConfig(IcingaConfig::app('dashboard/dashboard'));
|
||||
return $dashboard->getPaneKeyTitleArray();
|
||||
}
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Install;
|
||||
|
||||
use Zend_Config;
|
||||
use Icinga\Web\Wizard\Page;
|
||||
use Icinga\Form\Config\LoggingForm;
|
||||
|
||||
class LoggingPage extends Page
|
||||
{
|
||||
/**
|
||||
* The logging form
|
||||
*
|
||||
* @var LoggingForm
|
||||
*/
|
||||
protected $loggingForm;
|
||||
|
||||
/**
|
||||
* Initialize this LoggingPage
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('logging');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return the logging form
|
||||
*
|
||||
* @return LoggingForm
|
||||
*/
|
||||
protected function createForm()
|
||||
{
|
||||
if ($this->loggingForm === null) {
|
||||
$this->loggingForm = new LoggingForm();
|
||||
$this->loggingForm->hideButtons();
|
||||
$this->loggingForm->setTokenDisabled();
|
||||
$this->loggingForm->setRequest($this->getRequest());
|
||||
$this->loggingForm->setConfiguration($this->getConfiguration());
|
||||
}
|
||||
|
||||
return $this->loggingForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create this wizard page
|
||||
*/
|
||||
protected function create()
|
||||
{
|
||||
$loggingForm = $this->createForm();
|
||||
$loggingForm->buildForm(); // Needs to get called manually as it's nothing that Zend knows about
|
||||
$this->addSubForm($loggingForm, $loggingForm->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a config containing all values provided by the user
|
||||
*
|
||||
* @return Zend_Config
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->createForm()->getConfig();
|
||||
}
|
||||
}
|
@ -1,163 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Preference;
|
||||
|
||||
use DateTimeZone;
|
||||
use Icinga\Util\TimezoneDetect;
|
||||
use Zend_Config;
|
||||
use Zend_Form_Element_Text;
|
||||
use Zend_Form_Element_Select;
|
||||
use Zend_View_Helper_DateFormat;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Form\Validator\TimeFormatValidator;
|
||||
use Icinga\Web\Form\Validator\DateFormatValidator;
|
||||
use Icinga\Util\Translator;
|
||||
|
||||
/**
|
||||
* General user preferences
|
||||
*/
|
||||
class GeneralForm extends Form
|
||||
{
|
||||
/**
|
||||
* Add a select field for setting the user's language
|
||||
*
|
||||
* Possible values are determined by Translator::getAvailableLocaleCodes.
|
||||
* Also, a 'use default format' checkbox is added in order to allow a user to discard his overwritten setting
|
||||
*
|
||||
* @param Zend_Config $cfg The "global" section of the config.ini to be used as default value
|
||||
*/
|
||||
private function addLanguageSelection(Zend_Config $cfg)
|
||||
{
|
||||
$languages = array();
|
||||
foreach (Translator::getAvailableLocaleCodes() as $language) {
|
||||
$languages[$language] = $language;
|
||||
}
|
||||
$prefs = $this->getUserPreferences();
|
||||
$useDefaultLanguage = $this->getRequest()->getParam('default_language', !$prefs->has('app.language'));
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'default_language',
|
||||
array(
|
||||
'label' => t('Use Default Language'),
|
||||
'value' => $useDefaultLanguage,
|
||||
'required' => true
|
||||
)
|
||||
);
|
||||
$selectOptions = array(
|
||||
'label' => t('Your Current Language'),
|
||||
'required' => !$useDefaultLanguage,
|
||||
'multiOptions' => $languages,
|
||||
'helptext' => t('Use the following language to display texts and messages'),
|
||||
'value' => $prefs->get('app.language', $cfg->get('language', Translator::DEFAULT_LOCALE))
|
||||
);
|
||||
if ($useDefaultLanguage) {
|
||||
$selectOptions['disabled'] = 'disabled';
|
||||
}
|
||||
$this->addElement('select', 'language', $selectOptions);
|
||||
$this->enableAutoSubmit(array('default_language'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a select field for setting the user's timezone.
|
||||
*
|
||||
* Possible values are determined by DateTimeZone::listIdentifiers
|
||||
* Also, a 'use default format' checkbox is added in order to allow a user to discard his overwritten setting
|
||||
*
|
||||
* @param Zend_Config $cfg The "global" section of the config.ini to be used as default value
|
||||
*/
|
||||
private function addTimezoneSelection(Zend_Config $cfg)
|
||||
{
|
||||
$prefs = $this->getUserPreferences();
|
||||
$useGlobalTimezone = $this->getRequest()->getParam('default_timezone', !$prefs->has('app.timezone'));
|
||||
$detect = new TimezoneDetect();
|
||||
|
||||
$tzList = array();
|
||||
foreach (DateTimeZone::listIdentifiers() as $tz) {
|
||||
$tzList[$tz] = $tz;
|
||||
}
|
||||
|
||||
$helptext = 'Use the following timezone for dates and times';
|
||||
|
||||
if ($useGlobalTimezone && $detect->success() === true) {
|
||||
$helptext .= '<br />' . t('Currently your time was detected to be')
|
||||
. ': '
|
||||
. '<strong>' . $detect->getTimezoneName() . '</strong>';
|
||||
}
|
||||
|
||||
$selectTimezone = new Zend_Form_Element_Select(
|
||||
array(
|
||||
'name' => 'timezone',
|
||||
'label' => 'Your Current Timezone',
|
||||
'required' => !$useGlobalTimezone,
|
||||
'multiOptions' => $tzList,
|
||||
'helptext' => $helptext,
|
||||
'value' => $prefs->get('app.timezone', $cfg->get('timezone', date_default_timezone_get()))
|
||||
)
|
||||
);
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'default_timezone',
|
||||
array(
|
||||
'label' => 'Use Default Timezone',
|
||||
'value' => $useGlobalTimezone,
|
||||
'required' => true
|
||||
)
|
||||
);
|
||||
if ($useGlobalTimezone) {
|
||||
$selectTimezone->setAttrib('disabled', 1);
|
||||
}
|
||||
|
||||
$this->addElement($selectTimezone);
|
||||
|
||||
$this->enableAutoSubmit(array('default_timezone'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the general form, using the global configuration as fallback values for preferences
|
||||
*
|
||||
* @see Form::create()
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->setName('form_preference_set');
|
||||
|
||||
$config = $this->getConfiguration();
|
||||
$global = $config->global;
|
||||
if ($global === null) {
|
||||
$global = new Zend_Config(array());
|
||||
}
|
||||
|
||||
$this->addLanguageSelection($global);
|
||||
$this->addTimezoneSelection($global);
|
||||
|
||||
$this->setSubmitLabel('Save Changes');
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'show_benchmark',
|
||||
array(
|
||||
'label' => 'Use benchmark',
|
||||
'value' => $this->getUserPreferences()->get('app.show_benchmark')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array containing the preferences set in this form
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getPreferences()
|
||||
{
|
||||
$values = $this->getValues();
|
||||
return array(
|
||||
'app.language' => $values['default_language'] ? null : $values['language'],
|
||||
'app.timezone' => $values['default_timezone'] ? null : $values['timezone'],
|
||||
'app.show_benchmark' => $values['show_benchmark'] === '1' ? true : false
|
||||
);
|
||||
}
|
||||
}
|
225
application/forms/PreferenceForm.php
Normal file
225
application/forms/PreferenceForm.php
Normal file
@ -0,0 +1,225 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form;
|
||||
|
||||
use Exception;
|
||||
use DateTimeZone;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Session;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Util\Translator;
|
||||
use Icinga\Util\TimezoneDetect;
|
||||
use Icinga\User\Preferences;
|
||||
use Icinga\User\Preferences\PreferencesStore;
|
||||
|
||||
/**
|
||||
* Form class to adjust user preferences
|
||||
*/
|
||||
class PreferenceForm extends Form
|
||||
{
|
||||
/**
|
||||
* The preferences to work with
|
||||
*
|
||||
* @var Preferences
|
||||
*/
|
||||
protected $preferences;
|
||||
|
||||
/**
|
||||
* The preference store to use
|
||||
*
|
||||
* @var PreferencesStore
|
||||
*/
|
||||
protected $store;
|
||||
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_preferences');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set preferences to work with
|
||||
*
|
||||
* @param Preferences $preferences The preferences to work with
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setPreferences(Preferences $preferences)
|
||||
{
|
||||
$this->preferences = $preferences;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the preference store to use
|
||||
*
|
||||
* @param PreferencesStore $store The preference store to use
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setStore(PreferencesStore $store)
|
||||
{
|
||||
$this->store = $store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist preferences
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$this->store->load(); // Necessary for patching existing preferences
|
||||
$this->store->save($this->preferences);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust preferences and persist them
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
$webPreferences = $this->preferences->get('icingaweb', array());
|
||||
foreach ($this->getValues() as $key => $value) {
|
||||
if ($value === null) {
|
||||
if (isset($webPreferences[$key])) {
|
||||
unset($webPreferences[$key]);
|
||||
}
|
||||
} else {
|
||||
$webPreferences[$key] = $value;
|
||||
}
|
||||
}
|
||||
$this->preferences->icingaweb = $webPreferences;
|
||||
|
||||
// TODO: Is this even necessary in case the session is written on response?
|
||||
$session = Session::getSession();
|
||||
$session->user->setPreferences($this->preferences);
|
||||
$session->write();
|
||||
|
||||
try {
|
||||
$this->save();
|
||||
Notification::success(t('Preferences successfully saved'));
|
||||
} catch (Exception $e) {
|
||||
Notification::error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate preferences
|
||||
*
|
||||
* @see Form::onRequest()
|
||||
*/
|
||||
public function onRequest(Request $request)
|
||||
{
|
||||
$values = $this->preferences->get('icingaweb', array());
|
||||
$values['browser_language'] = false === isset($values['language']);
|
||||
$values['local_timezone'] = false === isset($values['timezone']);
|
||||
$this->populate($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$languages = array();
|
||||
foreach (Translator::getAvailableLocaleCodes() as $language) {
|
||||
$languages[$language] = $language;
|
||||
}
|
||||
|
||||
$tzList = array();
|
||||
foreach (DateTimeZone::listIdentifiers() as $tz) {
|
||||
$tzList[$tz] = $tz;
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'browser_language',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'value' => true,
|
||||
'label' => t('Use your browser\'s language suggestions')
|
||||
)
|
||||
);
|
||||
|
||||
$useBrowserLanguage = isset($formData['browser_language']) ? $formData['browser_language'] == 1 : true;
|
||||
$languageSelection = $this->createElement(
|
||||
'select',
|
||||
'language',
|
||||
array(
|
||||
'required' => false === $useBrowserLanguage,
|
||||
'label' => t('Your Current Language'),
|
||||
'description' => t('Use the following language to display texts and messages'),
|
||||
'multiOptions' => $languages,
|
||||
'value' => substr(setlocale(LC_ALL, 0), 0, 5)
|
||||
)
|
||||
);
|
||||
if ($useBrowserLanguage) {
|
||||
$languageSelection->setAttrib('disabled', 'disabled');
|
||||
}
|
||||
$this->addElement($languageSelection);
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'local_timezone',
|
||||
array(
|
||||
'ignore' => true,
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'value' => true,
|
||||
'label' => t('Use your local timezone')
|
||||
)
|
||||
);
|
||||
|
||||
$useLocalTimezone = isset($formData['local_timezone']) ? $formData['local_timezone'] == 1 : true;
|
||||
$timezoneSelection = $this->createElement(
|
||||
'select',
|
||||
'timezone',
|
||||
array(
|
||||
'required' => false === $useLocalTimezone,
|
||||
'label' => t('Your Current Timezone'),
|
||||
'description' => t('Use the following timezone for dates and times'),
|
||||
'multiOptions' => $tzList,
|
||||
'value' => $this->getDefaultTimezone()
|
||||
)
|
||||
);
|
||||
if ($useLocalTimezone) {
|
||||
$timezoneSelection->setAttrib('disabled', 'disabled');
|
||||
}
|
||||
$this->addElement($timezoneSelection);
|
||||
|
||||
$this->addElement(
|
||||
'checkbox',
|
||||
'show_benchmark',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Use benchmark')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current default timezone
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getDefaultTimezone()
|
||||
{
|
||||
$detect = new TimezoneDetect();
|
||||
if ($detect->success()) {
|
||||
return $detect->getTimezoneName();
|
||||
} else {
|
||||
return date_default_timezone_get();
|
||||
}
|
||||
}
|
||||
}
|
@ -486,7 +486,7 @@ msgstr "Die Objekt-Klasse welche benutzt wird, um Benutzer auf diesem LDAP-Serve
|
||||
|
||||
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:182
|
||||
msgid "The password to use for authentication"
|
||||
msgstr "Das Kennwort welche zur Authentifizierung benutzt werden soll"
|
||||
msgstr "Das Kennwort welches zur Authentifizierung benutzt werden soll"
|
||||
|
||||
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:270
|
||||
msgid "The password to use for querying the ldap server"
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Util\DateTimeFactory;
|
||||
use Icinga\Web\Form\Validator\DateTimeValidator;
|
||||
|
||||
/**
|
||||
* Helper to format date and time. Utilizes DateTimeFactory to ensure time zone awareness
|
||||
@ -57,7 +56,7 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
|
||||
public function format($timestamp, $format)
|
||||
{
|
||||
$dt = DateTimeFactory::create();
|
||||
if (DateTimeValidator::isUnixTimestamp($timestamp)) {
|
||||
if (DateTimeFactory::isUnixTimestamp($timestamp)) {
|
||||
$dt->setTimestamp($timestamp);
|
||||
} else {
|
||||
return $timestamp;
|
||||
|
@ -2,18 +2,30 @@
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
use \Zend_View_Helper_FormElement;
|
||||
|
||||
/**
|
||||
* Helper to generate a "datetime" element
|
||||
* Render date-and-time input controls
|
||||
*/
|
||||
class Zend_View_Helper_FormDateTime extends Zend_View_Helper_FormElement
|
||||
{
|
||||
/**
|
||||
* Generate a 'datetime' element
|
||||
* Format date and time
|
||||
*
|
||||
* @param DateTime $dateTime
|
||||
* @param bool $local
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function formatDate(DateTime $dateTime, $local)
|
||||
{
|
||||
$format = (bool) $local === true ? 'Y-m-d\TH:i:s' : DateTime::RFC3339;
|
||||
return $dateTime->format($format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the date-and-time input control
|
||||
*
|
||||
* @param string $name The element name
|
||||
* @param int $value The default timestamp
|
||||
* @param DateTime $value The default timestamp
|
||||
* @param array $attribs Attributes for the element tag
|
||||
*
|
||||
* @return string The element XHTML
|
||||
@ -21,50 +33,41 @@ class Zend_View_Helper_FormDateTime extends Zend_View_Helper_FormElement
|
||||
public function formDateTime($name, $value = null, $attribs = null)
|
||||
{
|
||||
$info = $this->_getInfo($name, $value, $attribs);
|
||||
extract($info); // name, value, attribs, options, listsep, disable
|
||||
// Is it disabled?
|
||||
extract($info); // name, id, value, attribs, options, listsep, disable
|
||||
/** @var string $id */
|
||||
/** @var bool $disable */
|
||||
$disabled = '';
|
||||
if ($disabled) {
|
||||
if ($disable) {
|
||||
$disabled = ' disabled="disabled"';
|
||||
}
|
||||
|
||||
$jspicker = (isset($attribs['jspicker']) && $attribs['jspicker'] === true) ? true : false;
|
||||
|
||||
if (isset($value) && !empty($value)) {
|
||||
if ($jspicker) {
|
||||
$value = ' value="' . $this->view->dateFormat()->format($value, $attribs['defaultFormat']) . '"';
|
||||
} else {
|
||||
$value = ' value="' . $this->view->dateFormat()->formatDateTime($value) . '"';
|
||||
}
|
||||
} else {
|
||||
$value = '';
|
||||
if ($value instanceof DateTime) {
|
||||
// If value was valid, it's a DateTime object
|
||||
$value = $this->formatDate($value, $attribs['local']);
|
||||
}
|
||||
|
||||
// Build the element
|
||||
$xhtml = '<div class="datetime' . (($jspicker === true) ? ' input-group' : ''). '">';
|
||||
|
||||
$xhtml .= '<input type="text" name="' . $name . '"'
|
||||
. ' id="' . $name . '"'
|
||||
. $value
|
||||
. $disabled
|
||||
. $this->_htmlAttribs($attribs);
|
||||
|
||||
if ($jspicker === true) {
|
||||
$xhtml .= 'data-icinga-component="app/datetime"';
|
||||
$min = '';
|
||||
if (! empty($attribs['min'])) {
|
||||
$min = sprintf(' min="%s"', $this->formatDate($attribs['min'], $attribs['local']));
|
||||
}
|
||||
|
||||
$xhtml .= $this->getClosingBracket();
|
||||
|
||||
if ($jspicker === true) {
|
||||
$xhtml .= '<span class="input-group-addon">'
|
||||
. '<a href="#">'
|
||||
. '<i class="icinga-icon-reschedule"></i>'
|
||||
. '</a>'
|
||||
. '</span>';
|
||||
unset($attribs['min']); // Unset min to not render it again in $this->_htmlAttribs($attribs)
|
||||
$max = '';
|
||||
if (! empty($attribs['max'])) {
|
||||
$max = sprintf(' max="%s"', $this->formatDate($attribs['max'], $attribs['local']));
|
||||
}
|
||||
|
||||
$xhtml .= '</div>';
|
||||
|
||||
return $xhtml;
|
||||
unset($attribs['max']); // Unset max to not render it again in $this->_htmlAttribs($attribs)
|
||||
$type = $attribs['local'] === true ? 'datetime-local' : 'datetime';
|
||||
unset($attribs['local']); // Unset local to not render it again in $this->_htmlAttribs($attribs)
|
||||
$html5 = sprintf(
|
||||
'<input type="%s" name="%s" id="%s" value="%s"%s%s%s%s%s',
|
||||
$type,
|
||||
$this->view->escape($name),
|
||||
$this->view->escape($id),
|
||||
$this->view->escape($value),
|
||||
$min,
|
||||
$max,
|
||||
$disabled,
|
||||
$this->_htmlAttribs($attribs),
|
||||
$this->getClosingBracket()
|
||||
);
|
||||
return $html5;
|
||||
}
|
||||
}
|
||||
|
@ -2,29 +2,79 @@
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
use \Zend_View_Helper_FormElement;
|
||||
|
||||
/**
|
||||
* Helper to generate a number input
|
||||
* Render number input controls
|
||||
*/
|
||||
class Zend_View_Helper_FormNumber extends \Zend_View_Helper_FormText
|
||||
class Zend_View_Helper_FormNumber extends Zend_View_Helper_FormElement
|
||||
{
|
||||
/**
|
||||
* Generates a html number input
|
||||
* Format a number
|
||||
*
|
||||
* @access public
|
||||
* @param $number
|
||||
*
|
||||
* @param string $name The element name.
|
||||
* @param string $value The default value.
|
||||
* @param array $attribs Attributes which should be added to the input tag.
|
||||
* @return string
|
||||
*/
|
||||
public function formatNumber($number)
|
||||
{
|
||||
if (empty($number)) {
|
||||
return $number;
|
||||
}
|
||||
return $this->view->escape(
|
||||
sprintf(
|
||||
ctype_digit((string) $number) ? '%d' : '%F',
|
||||
$number
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the number input control
|
||||
*
|
||||
* @return string The input tag and options XHTML.
|
||||
* @param string $name
|
||||
* @param int $value
|
||||
* @param array $attribs
|
||||
*
|
||||
* @return string The rendered number input control
|
||||
*/
|
||||
public function formNumber($name, $value = null, $attribs = null)
|
||||
{
|
||||
return '<input type="number"'
|
||||
. ' name="' . $this->view->escape($name) . '"'
|
||||
. ' value="' . $this->view->escape($value) . '"'
|
||||
. ' id="' . $this->view->escape($name) . '"'
|
||||
. $this->_htmlAttribs($attribs)
|
||||
. $this->getClosingBracket();
|
||||
$info = $this->_getInfo($name, $value, $attribs);
|
||||
extract($info); // name, id, value, attribs, options, listsep, disable
|
||||
/** @var string $id */
|
||||
/** @var bool $disable */
|
||||
$disabled = '';
|
||||
if ($disable) {
|
||||
$disabled = ' disabled="disabled"';
|
||||
}
|
||||
$min = '';
|
||||
if (isset($attribs['min'])) {
|
||||
$min = sprintf(' min="%s"', $this->formatNumber($attribs['min']));
|
||||
}
|
||||
unset($attribs['min']); // Unset min to not render it again in $this->_htmlAttribs($attribs)
|
||||
$max = '';
|
||||
if (isset($attribs['max'])) {
|
||||
$max = sprintf(' max="%s"', $this->formatNumber($attribs['max']));
|
||||
}
|
||||
unset($attribs['max']); // Unset max to not render it again in $this->_htmlAttribs($attribs)
|
||||
$step = '';
|
||||
if (isset($attribs['step'])) {
|
||||
$step = sprintf(' step="%s"', $attribs['step'] === 'any' ? 'any' : $this->formatNumber($attribs['step']));
|
||||
}
|
||||
unset($attribs['step']); // Unset step to not render it again in $this->_htmlAttribs($attribs)
|
||||
$html5 = sprintf(
|
||||
'<input type="number" name="%s" id="%s" value="%s"%s%s%s%s%s%s',
|
||||
$this->view->escape($name),
|
||||
$this->view->escape($id),
|
||||
$this->view->escape($this->formatNumber($value)),
|
||||
$min,
|
||||
$max,
|
||||
$step,
|
||||
$disabled,
|
||||
$this->_htmlAttribs($attribs),
|
||||
$this->getClosingBracket()
|
||||
);
|
||||
return $html5;
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,9 @@ class Zend_View_Helper_Util extends Zend_View_Helper_Abstract
|
||||
return date('H:i d.m.Y', $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Not used. This is monitoring module stuff.
|
||||
*/
|
||||
public static function getHostStateClassName($state)
|
||||
{
|
||||
$class = 'unknown';
|
||||
@ -82,6 +85,9 @@ class Zend_View_Helper_Util extends Zend_View_Helper_Abstract
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Crap. This is monitoring module stuff.
|
||||
*/
|
||||
public static function getHostStateName($state)
|
||||
{
|
||||
$states = array(
|
||||
@ -98,6 +104,9 @@ class Zend_View_Helper_Util extends Zend_View_Helper_Abstract
|
||||
return sprintf('OUT OF BOUNDS (%s)', var_export($state, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Crap. This is monitoring module stuff.
|
||||
*/
|
||||
public static function getServiceStateName($state)
|
||||
{
|
||||
if ($state === null) { $state = 3; } // really?
|
||||
|
@ -1,45 +0,0 @@
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
</div>
|
||||
|
||||
<div class="content" data-base-target="_next">
|
||||
<?php
|
||||
|
||||
if (isset($this->messageBox)) {
|
||||
// TODO: Get rid of such boxes -> notifications?
|
||||
echo $this->messageBox->render();
|
||||
}
|
||||
?>
|
||||
|
||||
<p>
|
||||
<a href="<?= $this->href('/config/createAuthenticationBackend', array('type' => 'ldap')) ?>"><?= $this->icon('create.png'); ?> Create A New LDAP Authentication Backend</a>
|
||||
<br />
|
||||
<a href="<?= $this->href('/config/createAuthenticationBackend', array('type' => 'db')) ?>"><?= $this->icon('create.png'); ?> Create A New DB Authentication Backend</a>
|
||||
</p>
|
||||
|
||||
<table class="action">
|
||||
<thead>
|
||||
<th>Resource</th>
|
||||
<th style="width: 5em">Remove</th>
|
||||
<th style="width: 5em">Order</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->backends as $backend): ?>
|
||||
<tr>
|
||||
<td class="action">
|
||||
<a href="<?= $this->href('config/editAuthenticationBackend', array('auth_backend' => $backend->name)) ?>">
|
||||
<?= $this->icon('edit.png') ?> <?= $this->escape($backend->name); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="<?= $this->href('config/removeAuthenticationBackend', array('auth_backend' => $backend->name)) ?>">
|
||||
<?= $this->icon('remove.png', 'Remove') ?>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<?= $backend->reorderForm; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
</div>
|
@ -1,15 +1,10 @@
|
||||
<h4>
|
||||
<i class="icinga-icon-create"></i>
|
||||
Create New Authentication Backend
|
||||
</h4>
|
||||
|
||||
|
||||
<?php if (isset($this->messageBox)): ?>
|
||||
<?= $this->messageBox->render() ?>
|
||||
<?php endif ?>
|
||||
|
||||
<div class="controls">
|
||||
<?= $this->tabs->showOnlyCloseButton() ?>
|
||||
</div>
|
||||
<h4><?= $this->translate('Create New Authentication Backend'); ?></h4>
|
||||
<p>
|
||||
Create a new backend for authenticating your users. This backend will be added at the end of your authentication order.
|
||||
<?= $this->translate(
|
||||
'Create a new backend for authenticating your users. This backend will be added at the end of your authentication order.'
|
||||
); ?>
|
||||
</p>
|
||||
|
||||
<?= $this->form ?>
|
||||
<?= $form; ?>
|
@ -1,18 +1,5 @@
|
||||
<h4>
|
||||
<i class="icinga-icon-edit"></i>
|
||||
Edit Backend "<?= $this->escape($this->name); ?>"
|
||||
</h4>
|
||||
|
||||
<?php if (isset($this->messageBox)): ?>
|
||||
<?= $this->messageBox->render() ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($this->form->getErrorMessages()): ?>
|
||||
<div>
|
||||
<?php foreach ($this->form->getErrorMessages() as $error): ?>
|
||||
<?= $this->escape($error); ?><br/>
|
||||
<?php endforeach; ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs->showOnlyCloseButton() ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?= $this->form ?>
|
||||
<h4><?= $this->translate('Edit Backend'); ?></h4>
|
||||
<?= $form; ?>
|
@ -1,10 +1,5 @@
|
||||
<h4>
|
||||
<i class="icinga-icon-remove"></i>
|
||||
Remove Backend "<?= $this->escape($this->name); ?>"
|
||||
</h4>
|
||||
|
||||
<?php if (isset($this->messageBox)): ?>
|
||||
<?= $this->messageBox->render() ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?= $this->form ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs->showOnlyCloseButton() ?>
|
||||
</div>
|
||||
<h4><?= $this->translate('Remove Backend'); ?></h4>
|
||||
<?= $form; ?>
|
@ -0,0 +1,11 @@
|
||||
<div class="controls">
|
||||
<?= $tabs; ?>
|
||||
</div>
|
||||
<div class="content" data-base-target="_next">
|
||||
<p>
|
||||
<a href="<?= $this->href('/config/createAuthenticationBackend'); ?>">
|
||||
<?= $this->icon('create.png'); ?><?= $this->translate('Create A New Authentication Backend'); ?>
|
||||
</a>
|
||||
</p>
|
||||
<?= $form; ?>
|
||||
</div>
|
@ -1,6 +1,6 @@
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<h1>Installed Modules</h1>
|
||||
<h1><?= $this->translate('Installed Modules') ?></h1>
|
||||
<?= $this->paginationControl($modules) ?>
|
||||
</div>
|
||||
|
||||
@ -11,9 +11,9 @@
|
||||
<tr>
|
||||
<td>
|
||||
<?php if ($module->enabled): ?>
|
||||
<?= $this->icon('success.png', 'Module is enabled') ?>
|
||||
<?= $this->icon('success.png', $this->translate('Module is enabled')) ?>
|
||||
<?php else: ?>
|
||||
<?= $this->icon('remove.png', 'Module is disabled') ?>
|
||||
<?= $this->icon('remove.png', $this->translate('Module is disabled')) ?>
|
||||
<? endif ?>
|
||||
<a href="<?= $this->url(
|
||||
'config/module/',
|
||||
|
@ -1,30 +1,32 @@
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<?= $tabs; ?>
|
||||
</div>
|
||||
|
||||
<div class="content" data-base-target="_next">
|
||||
<?php
|
||||
|
||||
if (isset($this->messageBox)) {
|
||||
// TODO: Get rid of messageBoxes in favour of notifications
|
||||
echo $this->messageBox->render();
|
||||
}
|
||||
|
||||
?>
|
||||
<p><a href="<?= $this->href('/config/createresource') ?>"><?= $this->icon('create.png'); ?> Create A New Resource</a></p>
|
||||
|
||||
<table class="action">
|
||||
<thead>
|
||||
<th>Resource</th>
|
||||
<th style="width: 5em">Remove</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<p>
|
||||
<a href="<?= $this->href('/config/createresource'); ?>">
|
||||
<?= $this->icon('create.png'); ?> <?= $this->translate('Create A New Resource'); ?>
|
||||
</a>
|
||||
</p>
|
||||
<table class="action">
|
||||
<thead>
|
||||
<th><?= $this->translate('Resource'); ?></th>
|
||||
<th style="width: 5em"><?= $this->translate('Remove'); ?></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($this->resources as $name => $resource): ?>
|
||||
<tr>
|
||||
<td><a href="<?= $this->href('config/editresource', array('resource' => $name)) ?>"><?= $this->icon('edit.png') ?> <?= $this->escape($name); ?></td>
|
||||
<td style="text-align: center"><a href="<?= $this->href('config/removeresource', array('resource' => $name)) ?>"><?= $this->icon('remove.png'); ?></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?= $this->href('config/editresource', array('resource' => $name)); ?>">
|
||||
<?= $this->icon('edit.png'); ?> <?= $this->escape($name); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td style="text-align: center">
|
||||
<a href="<?= $this->href('config/removeresource', array('resource' => $name)); ?>">
|
||||
<?= $this->icon('remove.png'); ?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
@ -1,14 +1,6 @@
|
||||
<h4>
|
||||
<i class="icinga-icon-create"></i>
|
||||
Create New Resource
|
||||
</h4>
|
||||
|
||||
<?php if (isset($this->messageBox)): ?>
|
||||
<?= $this->messageBox->render() ?>
|
||||
<?php endif ?>
|
||||
|
||||
<p>
|
||||
Resources are entities that provide data to Icingaweb.
|
||||
</p>
|
||||
|
||||
<?= $this->form ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs->showOnlyCloseButton() ?>
|
||||
</div>
|
||||
<h4><?= $this->translate('Create A New Resource'); ?></h4>
|
||||
<p><?= $this->translate('Resources are entities that provide data to Icinga Web 2.'); ?></p>
|
||||
<?= $form; ?>
|
@ -1,18 +1,5 @@
|
||||
<h4>
|
||||
<i class="icinga-icon-edit"></i>
|
||||
Edit Resource "<?= $this->escape($this->name); ?>"
|
||||
</h4>
|
||||
|
||||
<?php if (isset($this->messageBox)): ?>
|
||||
<?= $this->messageBox->render() ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($this->form->getErrorMessages()): ?>
|
||||
<div>
|
||||
<?php foreach ($this->form->getErrorMessages() as $error): ?>
|
||||
<?= $this->escape($error); ?><br/>
|
||||
<?php endforeach; ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs->showOnlyCloseButton() ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?= $this->form ?>
|
||||
<h4><?= $this->translate('Edit Existing Resource'); ?></h4>
|
||||
<?= $form; ?>
|
@ -1,10 +1,5 @@
|
||||
<h4>
|
||||
<i class="icinga-icon-remove"></i>
|
||||
Remove Resource "<?= $this->escape($this->name); ?>"
|
||||
</h4>
|
||||
|
||||
<?php if (isset($this->messageBox)): ?>
|
||||
<?= $this->messageBox->render() ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?= $this->form ?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs->showOnlyCloseButton() ?>
|
||||
</div>
|
||||
<h4><?= $this->translate('Remove Existing Resource'); ?></h4>
|
||||
<?= $form; ?>
|
@ -1,31 +0,0 @@
|
||||
<?= $this->tabs->render($this); ?>
|
||||
|
||||
|
||||
<br/>
|
||||
<div>
|
||||
<h4><i>WARNING ICON</i>Saving "<?= $this->escape($this->file); ?>.ini" Failed</h4>
|
||||
<br/>
|
||||
<p>
|
||||
Your <?= $this->escape($this->file); ?> configuration couldn't be stored (error: "<?= $this->exceptionMessage; ?>").<br/>
|
||||
This could have one or more of the following reasons:
|
||||
</p>
|
||||
<ul>
|
||||
<li>You don't have file-system permissions to write to the <?= $this->escape($this->file); ?>.ini file</li>
|
||||
<li>Something went wrong while writing the file</li>
|
||||
<li>There's an application error preventing you from persisting the configuration</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Details can be seen in your application log (if you don't have access to this file, call your administrator in this case).
|
||||
<br/>
|
||||
In case you can access the configuration file (config/<?= $this->escape($this->file); ?>.ini) by yourself, you can open it and
|
||||
insert the config manually:
|
||||
</p>
|
||||
<p>
|
||||
<pre>
|
||||
<code>
|
||||
<?= $this->escape($this->iniConfigurationString); ?>
|
||||
</code>
|
||||
</pre>
|
||||
</p>
|
@ -11,7 +11,4 @@
|
||||
<hr />
|
||||
<pre><?= $this->escape($stackTrace) ?></pre>
|
||||
<?php endif ?>
|
||||
<?php if (isset($this->messageBox)) : ?>
|
||||
<?= $this->messageBox->render(); ?>
|
||||
<? endif ?>
|
||||
</div>
|
||||
|
40
application/views/scripts/form/reorder-authbackend.phtml
Normal file
40
application/views/scripts/form/reorder-authbackend.phtml
Normal file
@ -0,0 +1,40 @@
|
||||
<form id="<?= $form->getName(); ?>" name="<?= $form->getName(); ?>" enctype="<?= $form->getEncType(); ?>" method="<?= $form->getMethod(); ?>">
|
||||
<table class="action">
|
||||
<thead>
|
||||
<th>Backend</th>
|
||||
<th style="width: 5em"><?= $this->translate('Remove'); ?></th>
|
||||
<th style="width: 5em"><?= $this->translate('Order'); ?></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $backendNames = $form->getBackendOrder(); ?>
|
||||
<?php for ($i = 0; $i < count($backendNames); $i++): ?>
|
||||
<tr>
|
||||
<td class="action">
|
||||
<a href="<?= $this->href('config/editAuthenticationBackend', array('auth_backend' => $backendNames[$i])); ?>">
|
||||
<?= $this->icon('edit.png'); ?> <?= $this->escape($backendNames[$i]); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="<?= $this->href('config/removeAuthenticationBackend', array('auth_backend' => $backendNames[$i])); ?>">
|
||||
<?= $this->icon('remove.png', $this->translate('Remove')); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($i > 0): ?>
|
||||
<button type="submit" name="backend_newpos" value="<?= sprintf('%s|%s', $backendNames[$i], $i - 1); ?>">
|
||||
<?= $this->icon('up.png', $this->translate('Move up in authentication order')); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php if ($i + 1 < count($backendNames)): ?>
|
||||
<button type="submit" name="backend_newpos" value="<?= sprintf('%s|%s', $backendNames[$i], $i + 1); ?>">
|
||||
<?= $this->icon('down.png', $this->translate('Move down in authentication order')); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endfor; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?= $form->getElement($form->getTokenElementName()); ?>
|
||||
<?= $form->getElement($form->getUidElementName()); ?>
|
||||
</form>
|
@ -1,7 +1,7 @@
|
||||
<div class="controls">
|
||||
<?= $this->tabs->render($this); ?>
|
||||
<?= $tabs; ?>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<?= $this->form ?>
|
||||
</div>
|
||||
<?= $form; ?>
|
||||
</div>
|
28
application/views/scripts/showConfiguration.phtml
Normal file
28
application/views/scripts/showConfiguration.phtml
Normal file
@ -0,0 +1,28 @@
|
||||
<div>
|
||||
<h4><?= $this->translate('Saving Configuration Failed'); ?></h4>
|
||||
<br>
|
||||
<p>
|
||||
<?= sprintf(
|
||||
$this->translate('The file %s couldn\'t be stored. (Error: "%s")'),
|
||||
$this->escape($filePath),
|
||||
$this->escape($errorMessage)
|
||||
); ?>
|
||||
<br>
|
||||
<?= $this->translate('This could have one or more of the following reasons:'); ?>
|
||||
</p>
|
||||
<ul>
|
||||
<li><?= $this->translate('You don\'t have file-system permissions to write to the file'); ?></li>
|
||||
<li><?= $this->translate('Something went wrong while writing the file'); ?></li>
|
||||
<li><?= $this->translate('There\'s an application error preventing you from persisting the configuration'); ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>
|
||||
<?= $this->translate('Details can be found in the application log. (If you don\'t have access to this log, call your administrator in this case)'); ?>
|
||||
<br>
|
||||
<?= $this->translate('In case you can access the file by yourself, you can open it and insert the config manually:'); ?>
|
||||
</p>
|
||||
<p>
|
||||
<pre>
|
||||
<code><?= $this->escape($configString); ?></code>
|
||||
</pre>
|
||||
</p>
|
@ -18,6 +18,10 @@ backend = ldap
|
||||
resource = internal_ldap
|
||||
user_class = @ldap_user_objectclass@
|
||||
user_name_attribute = @ldap_attribute_username@
|
||||
group_base_dn = @ldap_group_base_dn@
|
||||
group_attribute = @ldap_group_attribute@
|
||||
group_member_attribute = @ldap_group_member_attribute@
|
||||
group_class = @ldap_group_class@
|
||||
|
||||
[internal_db_authentication]
|
||||
@internal_auth_disabled@
|
||||
|
@ -26,12 +26,12 @@
|
||||
|
||||
%define revision 1
|
||||
|
||||
%define configdir %{_sysconfdir}/icingaweb
|
||||
%define sharedir %{_datadir}/icingaweb
|
||||
%define prefixdir %{_datadir}/icingaweb
|
||||
%define logdir %{sharedir}/log
|
||||
%define configdir %{_sysconfdir}/%{name}
|
||||
%define sharedir %{_datadir}/%{name}
|
||||
%define prefixdir %{_datadir}/%{name}
|
||||
%define usermodparam -a -G
|
||||
%define logdir %{_localstatedir}/log/icingaweb
|
||||
%define logdir %{_localstatedir}/log/%{name}
|
||||
%define docdir %{sharedir}/log
|
||||
|
||||
%if "%{_vendor}" == "suse"
|
||||
%define phpname php5
|
||||
@ -172,25 +172,26 @@ install -D -m0644 packages/rpm/etc/httpd/conf.d/icingaweb.conf %{buildroot}/%{ap
|
||||
# install public, library, modules
|
||||
%{__mkdir} -p %{buildroot}/%{sharedir}
|
||||
%{__mkdir} -p %{buildroot}/%{logdir}
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/icingaweb
|
||||
%{__mkdir} -p %{buildroot}/%{docdir}
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/dashboard
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/icingaweb/modules
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/icingaweb/modules/monitoring
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/icingaweb/enabledModules
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/modules
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring
|
||||
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/enabledModules
|
||||
|
||||
%{__cp} -r application library modules public %{buildroot}/%{sharedir}/
|
||||
%{__cp} -r application doc library modules public %{buildroot}/%{sharedir}/
|
||||
|
||||
## config
|
||||
# authentication is db only
|
||||
install -D -m0644 packages/rpm/etc/icingaweb/authentication.ini %{buildroot}/%{_sysconfdir}/icingaweb/authentication.ini
|
||||
install -D -m0644 packages/rpm/etc/%{name}/authentication.ini %{buildroot}/%{_sysconfdir}/%{name}/authentication.ini
|
||||
# custom resource paths
|
||||
install -D -m0644 packages/rpm/etc/icingaweb/resources.ini %{buildroot}/%{_sysconfdir}/icingaweb/resources.ini
|
||||
install -D -m0644 packages/rpm/etc/%{name}/resources.ini %{buildroot}/%{_sysconfdir}/%{name}/resources.ini
|
||||
# monitoring module (icinga2)
|
||||
install -D -m0644 packages/rpm/etc/icingaweb/modules/monitoring/backends.ini %{buildroot}/%{_sysconfdir}/icingaweb/modules/monitoring/backends.ini
|
||||
install -D -m0644 packages/rpm/etc/icingaweb/modules/monitoring/instances.ini %{buildroot}/%{_sysconfdir}/icingaweb/modules/monitoring/instances.ini
|
||||
install -D -m0644 packages/rpm/etc/%{name}/modules/monitoring/backends.ini %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring/backends.ini
|
||||
install -D -m0644 packages/rpm/etc/%{name}/modules/monitoring/instances.ini %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring/instances.ini
|
||||
|
||||
# enable the monitoring module by default
|
||||
ln -s %{sharedir}/modules/monitoring %{buildroot}/%{_sysconfdir}/icingaweb/enabledModules/monitoring
|
||||
ln -s %{sharedir}/modules/monitoring %{buildroot}/%{_sysconfdir}/%{name}/enabledModules/monitoring
|
||||
## config
|
||||
|
||||
# install icingacli
|
||||
@ -228,6 +229,8 @@ fi
|
||||
%config(noreplace) %attr(-,%{apacheuser},%{apachegroup}) %{configdir}
|
||||
# logs
|
||||
%attr(2775,%{apacheuser},%{apachegroup}) %dir %{logdir}
|
||||
# shipped docs
|
||||
%attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/doc
|
||||
|
||||
%files -n php-Icinga
|
||||
%attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/application
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
namespace Icinga\Application;
|
||||
|
||||
use ErrorException;
|
||||
use Exception;
|
||||
use Zend_Config;
|
||||
use Icinga\Application\Modules\Manager as ModuleManager;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
@ -348,11 +348,7 @@ abstract class ApplicationBootstrap
|
||||
Logger::create(
|
||||
new Zend_Config(
|
||||
array(
|
||||
'enable' => true,
|
||||
'level' => Logger::$ERROR,
|
||||
'type' => 'syslog',
|
||||
'facility' => 'LOG_USER',
|
||||
'application' => 'icingaweb'
|
||||
'log' => 'syslog'
|
||||
)
|
||||
)
|
||||
);
|
||||
@ -383,9 +379,20 @@ abstract class ApplicationBootstrap
|
||||
*/
|
||||
protected function setupErrorHandling()
|
||||
{
|
||||
error_reporting(E_ALL | E_NOTICE);
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
ini_set('display_startup_errors', 1);
|
||||
ini_set('display_errors', 1);
|
||||
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
|
||||
if (error_reporting() === 0) {
|
||||
// Error was suppressed with the @-operator
|
||||
return false; // Continue with the normal error handler
|
||||
}
|
||||
switch($errno) {
|
||||
case E_STRICT:
|
||||
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||
}
|
||||
return false; // Continue with the normal error handler
|
||||
});
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -51,10 +51,9 @@ class Cli extends ApplicationBootstrap
|
||||
Logger::create(
|
||||
new Zend_Config(
|
||||
array(
|
||||
'enable' => true,
|
||||
'level' => Logger::$INFO,
|
||||
'type' => 'file',
|
||||
'target' => 'php://stderr'
|
||||
'level' => Logger::INFO,
|
||||
'log' => 'file',
|
||||
'file' => 'php://stderr'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -7,7 +7,6 @@ namespace Icinga\Application;
|
||||
use Zend_Config;
|
||||
use Zend_Config_Ini;
|
||||
use Icinga\Exception\NotReadableError;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
|
||||
/**
|
||||
* Global registry of application and module configuration.
|
||||
@ -22,11 +21,11 @@ class Config extends Zend_Config
|
||||
public static $configDir;
|
||||
|
||||
/**
|
||||
* The INI file this configuration has been loaded from
|
||||
* The INI file this configuration has been loaded from or should be written to
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $configFile;
|
||||
protected $configFile;
|
||||
|
||||
/**
|
||||
* Application config instances per file
|
||||
@ -42,30 +41,28 @@ class Config extends Zend_Config
|
||||
*/
|
||||
protected static $modules = array();
|
||||
|
||||
private $instance;
|
||||
|
||||
/**
|
||||
* Load configuration from the config file $filename
|
||||
* Load configuration from the given INI file
|
||||
*
|
||||
* @param string $file The file to parse
|
||||
*
|
||||
* @param string $filename The filename to parse
|
||||
|
||||
* @throws NotReadableError When the file does not exist or cannot be read
|
||||
*/
|
||||
public function __construct($filename)
|
||||
public static function fromIni($file)
|
||||
{
|
||||
parent::__construct(array(), true);
|
||||
$filepath = realpath($filename);
|
||||
$config = new static(array(), true);
|
||||
$filepath = realpath($file);
|
||||
|
||||
if ($filepath === false) {
|
||||
$this->configFile = $filename;
|
||||
$config->setConfigFile($file);
|
||||
} elseif (is_readable($filepath)) {
|
||||
$this->configFile = $filepath;
|
||||
$this->merge(new Zend_Config_Ini($filepath));
|
||||
$config->setConfigFile($filepath);
|
||||
$config->merge(new Zend_Config_Ini($filepath));
|
||||
} else {
|
||||
throw new NotReadableError(
|
||||
'Cannot read config file "%s". Permission denied',
|
||||
$filename
|
||||
);
|
||||
throw new NotReadableError('Cannot read config file "%s". Permission denied', $filepath);
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,7 +77,7 @@ class Config extends Zend_Config
|
||||
public static function app($configname = 'config', $fromDisk = false)
|
||||
{
|
||||
if (!isset(self::$app[$configname]) || $fromDisk) {
|
||||
self::$app[$configname] = new Config(self::resolvePath($configname . '.ini'));
|
||||
self::$app[$configname] = Config::fromIni(self::resolvePath($configname . '.ini'));
|
||||
}
|
||||
return self::$app[$configname];
|
||||
}
|
||||
@ -113,7 +110,7 @@ class Config extends Zend_Config
|
||||
}
|
||||
$moduleConfigs = self::$modules[$modulename];
|
||||
if (!isset($moduleConfigs[$configname]) || $fromDisk) {
|
||||
$moduleConfigs[$configname] = new Config(
|
||||
$moduleConfigs[$configname] = Config::fromIni(
|
||||
self::resolvePath('modules/' . $modulename . '/' . $configname . '.ini')
|
||||
);
|
||||
}
|
||||
@ -138,15 +135,28 @@ class Config extends Zend_Config
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the application wide config file
|
||||
* Return this config's file path
|
||||
*
|
||||
* @return string
|
||||
* @return string
|
||||
*/
|
||||
public function getConfigFile()
|
||||
{
|
||||
return $this->configFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this config's file path
|
||||
*
|
||||
* @param string $filepath The path to the config file
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setConfigFile($filepath)
|
||||
{
|
||||
$this->configFile = $filepath;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend configuration base dir if input is relative
|
||||
*
|
||||
|
@ -918,10 +918,21 @@ class Module
|
||||
* Translate a string with the global mt()
|
||||
*
|
||||
* @param $string
|
||||
* @param null $context
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
protected function translate($string)
|
||||
protected function translate($string, $context = null)
|
||||
{
|
||||
return mt($this->name, $string);
|
||||
return mt($this->name, $string, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see Translator::translatePlural() For the function documentation.
|
||||
*/
|
||||
protected function translatePlural($textSingular, $textPlural, $number, $context = null)
|
||||
{
|
||||
return mtp($this->name, $textSingular, $textPlural, $number, $context);
|
||||
}
|
||||
}
|
||||
|
@ -278,7 +278,8 @@ class Web extends ApplicationBootstrap
|
||||
|
||||
if ($this->user !== null && $this->user->getPreferences() !== null) {
|
||||
$detect = new TimezoneDetect();
|
||||
$userTimezone = $this->user->getPreferences()->get('app.timezone', $detect->getTimezoneName());
|
||||
$userTimezone = $this->user->getPreferences()
|
||||
->getValue('icingaweb', 'timezone', $detect->getTimezoneName());
|
||||
}
|
||||
|
||||
try {
|
||||
@ -302,7 +303,7 @@ class Web extends ApplicationBootstrap
|
||||
{
|
||||
parent::setupInternationalization();
|
||||
if ($this->user !== null && $this->user->getPreferences() !== null
|
||||
&& (($locale = $this->user->getPreferences()->get('app.language')) !== null)
|
||||
&& (($locale = $this->user->getPreferences()->getValue('icingaweb', 'language')) !== null)
|
||||
) {
|
||||
try {
|
||||
Translator::setupLocale($locale);
|
||||
|
@ -5,23 +5,85 @@
|
||||
use Icinga\Util\Translator;
|
||||
|
||||
if (extension_loaded('gettext')) {
|
||||
function t($messageId)
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see Translator::translate() For the function documentation.
|
||||
*/
|
||||
function t($messageId, $context = null)
|
||||
{
|
||||
return Translator::translate($messageId, Translator::DEFAULT_DOMAIN);
|
||||
return Translator::translate($messageId, Translator::DEFAULT_DOMAIN, $context);
|
||||
}
|
||||
|
||||
function mt($domain, $messageId)
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see Translator::translate() For the function documentation.
|
||||
*/
|
||||
function mt($domain, $messageId, $context = null)
|
||||
{
|
||||
return Translator::translate($messageId, $domain);
|
||||
return Translator::translate($messageId, $domain, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see Translator::translatePlural() For the function documentation.
|
||||
*/
|
||||
function tp($messageId, $messageId2, $number, $context = null)
|
||||
{
|
||||
return Translator::translatePlural($messageId, $messageId2, $number, Translator::DEFAULT_DOMAIN, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see Translator::translatePlural() For the function documentation.
|
||||
*/
|
||||
function mtp($domain, $messageId, $messageId2, $number, $context = null)
|
||||
{
|
||||
return Translator::translatePlural($messageId, $messageId2, $number, $domain, $context);
|
||||
}
|
||||
|
||||
} else {
|
||||
function t($messageId)
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see Translator::translate() For the function documentation.
|
||||
*/
|
||||
function t($messageId, $context = null)
|
||||
{
|
||||
return $messageId;
|
||||
}
|
||||
|
||||
function mt($domain, $messageId)
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see Translator::translate() For the function documentation.
|
||||
*/
|
||||
function mt($domain, $messageId, $context = null)
|
||||
{
|
||||
return $messageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see Translator::translatePlural() For the function documentation.
|
||||
*/
|
||||
function tp($messageId, $messageId2, $number, $context = null)
|
||||
{
|
||||
if ((int) $number !== 1) {
|
||||
return $messageId2;
|
||||
}
|
||||
return $messageId;
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPDoc)
|
||||
* @see Translator::translatePlural() For the function documentation.
|
||||
*/
|
||||
function mtp($domain, $messageId, $messageId2, $number, $context = null)
|
||||
{
|
||||
if ((int) $number !== 1) {
|
||||
return $messageId2;
|
||||
}
|
||||
return $messageId;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -52,12 +52,8 @@ class AdmissionLoader
|
||||
return $permissions;
|
||||
}
|
||||
foreach ($config as $section) {
|
||||
if ($this->match($section, $username, $groups)) {
|
||||
foreach ($section as $key => $value) {
|
||||
if (strpos($key, 'permission') === 0) {
|
||||
$permissions = array_merge($permissions, String::trimSplit($value));
|
||||
}
|
||||
}
|
||||
if ($this->match($section, $username, $groups) && isset($section->permissions)) {
|
||||
$permissions += String::trimSplit($section->permissions);
|
||||
}
|
||||
}
|
||||
return $permissions;
|
||||
@ -79,12 +75,12 @@ class AdmissionLoader
|
||||
} catch (NotReadableError $e) {
|
||||
return $restrictions;
|
||||
}
|
||||
foreach ($config as $section) {
|
||||
foreach ($config as $name => $section) {
|
||||
if ($this->match($section, $username, $groups)) {
|
||||
if (!array_key_exists($section->name, $restrictions)) {
|
||||
$restrictions[$section->name] = array();
|
||||
}
|
||||
$restrictions[$section->name][] = $section->restriction;
|
||||
$restrictions[$section->name][$name] = $section->restriction;
|
||||
}
|
||||
}
|
||||
return $restrictions;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
namespace Icinga\Authentication\Backend;
|
||||
|
||||
use Icinga\Logger\Logger;
|
||||
use Icinga\User;
|
||||
use Icinga\Authentication\UserBackend;
|
||||
use Icinga\Protocol\Ldap\Connection;
|
||||
@ -23,11 +24,14 @@ class LdapUserBackend extends UserBackend
|
||||
|
||||
protected $userNameAttribute;
|
||||
|
||||
public function __construct(Connection $conn, $userClass, $userNameAttribute)
|
||||
protected $groupOptions;
|
||||
|
||||
public function __construct(Connection $conn, $userClass, $userNameAttribute, $groupOptions = null)
|
||||
{
|
||||
$this->conn = $conn;
|
||||
$this->userClass = $userClass;
|
||||
$this->userNameAttribute = $userNameAttribute;
|
||||
$this->groupOptions = $groupOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,6 +87,43 @@ class LdapUserBackend extends UserBackend
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the user groups
|
||||
*
|
||||
* @TODO: Subject to change, see #7343
|
||||
*
|
||||
* @param string $dn
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getGroups($dn)
|
||||
{
|
||||
if (empty($this->groupOptions) || ! isset($this->groupOptions['group_base_dn'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$q = $this->conn->select()
|
||||
->setBase($this->groupOptions['group_base_dn'])
|
||||
->from(
|
||||
$this->groupOptions['group_class'],
|
||||
array($this->groupOptions['group_attribute'])
|
||||
)
|
||||
->where(
|
||||
$this->groupOptions['group_member_attribute'],
|
||||
$dn
|
||||
);
|
||||
|
||||
$result = $this->conn->fetchAll($q);
|
||||
|
||||
$groups = array();
|
||||
|
||||
foreach ($result as $group) {
|
||||
$groups[] = $group->{$this->groupOptions['group_attribute']};
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the given user exists
|
||||
*
|
||||
@ -127,10 +168,15 @@ class LdapUserBackend extends UserBackend
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return $this->conn->testCredentials(
|
||||
$this->conn->fetchDN($this->createQuery($user->getUsername())),
|
||||
$userDn = $this->conn->fetchDN($this->createQuery($user->getUsername()));
|
||||
$authenticated = $this->conn->testCredentials(
|
||||
$userDn,
|
||||
$password
|
||||
);
|
||||
if ($authenticated) {
|
||||
$user->setGroups($this->getGroups($userDn));
|
||||
}
|
||||
return $authenticated;
|
||||
} catch (LdapException $e) {
|
||||
// Error during authentication of this specific user
|
||||
throw new AuthenticationException(
|
||||
@ -160,4 +206,3 @@ class LdapUserBackend extends UserBackend
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,30 +113,32 @@ class Manager
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to authenticate the user with the current session
|
||||
* Try to authenticate the user with the current session
|
||||
*
|
||||
* Authentication for externally-authenticated users will be revoked if the username changed or external
|
||||
* authentication is no longer in effect
|
||||
*/
|
||||
public function authenticateFromSession()
|
||||
{
|
||||
$this->user = Session::getSession()->get('user');
|
||||
|
||||
if ($this->user !== null && $this->user->isRemoteUser() === true) {
|
||||
list($originUsername, $field) = $this->user->getRemoteUserInformation();
|
||||
if (array_key_exists($field, $_SERVER) && $_SERVER[$field] !== $originUsername) {
|
||||
if (! array_key_exists($field, $_SERVER) || $_SERVER[$field] !== $originUsername) {
|
||||
$this->removeAuthorization();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the user is currently authenticated
|
||||
* Whether the user is authenticated
|
||||
*
|
||||
* @param Boolean $ignoreSession Set to true to prevent authentication by session
|
||||
* @param bool $ignoreSession True to prevent session authentication
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAuthenticated($ignoreSession = false)
|
||||
{
|
||||
if ($this->user === null && !$ignoreSession) {
|
||||
if ($this->user === null && ! $ignoreSession) {
|
||||
$this->authenticateFromSession();
|
||||
}
|
||||
return is_object($this->user);
|
||||
@ -145,25 +147,16 @@ class Manager
|
||||
/**
|
||||
* Whether an authenticated user has a given permission
|
||||
*
|
||||
* This is true if the user owns this permission, false if not.
|
||||
* Also false if there is no authenticated user
|
||||
*
|
||||
* TODO: I'd like to see wildcard support, e.g. module/*
|
||||
*
|
||||
* @param string $permission Permission name
|
||||
* @return bool
|
||||
*
|
||||
* @return bool True if the user owns the given permission, false if not or if not authenticated
|
||||
*/
|
||||
public function hasPermission($permission)
|
||||
{
|
||||
if (! $this->isAuthenticated()) {
|
||||
return false;
|
||||
}
|
||||
foreach ($this->user->getPermissions() as $p) {
|
||||
if ($p === $permission) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return $this->user->can($permission);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,26 +93,44 @@ abstract class UserBackend implements Countable
|
||||
$backend = new DbUserBackend($resource);
|
||||
break;
|
||||
case 'msldap':
|
||||
$groupOptions = array(
|
||||
'group_base_dn' => $backendConfig->group_base_dn,
|
||||
'group_attribute' => $backendConfig->group_attribute,
|
||||
'group_member_attribute' => $backendConfig->group_member_attribute,
|
||||
'group_class' => $backendConfig->group_class
|
||||
);
|
||||
$backend = new LdapUserBackend(
|
||||
$resource,
|
||||
$backendConfig->get('user_class', 'user'),
|
||||
$backendConfig->get('user_name_attribute', 'sAMAccountName')
|
||||
$backendConfig->get('user_name_attribute', 'sAMAccountName'),
|
||||
$groupOptions
|
||||
);
|
||||
break;
|
||||
case 'ldap':
|
||||
if (($userClass = $backendConfig->user_class) === null) {
|
||||
if ($backendConfig->user_class === null) {
|
||||
throw new ConfigurationError(
|
||||
'Authentication configuration for backend "%s" is missing the user_class directive',
|
||||
$name
|
||||
);
|
||||
}
|
||||
if (($userNameAttribute = $backendConfig->user_name_attribute) === null) {
|
||||
if ($backendConfig->user_name_attribute === null) {
|
||||
throw new ConfigurationError(
|
||||
'Authentication configuration for backend "%s" is missing the user_name_attribute directive',
|
||||
$name
|
||||
);
|
||||
}
|
||||
$backend = new LdapUserBackend($resource, $userClass, $userNameAttribute);
|
||||
$groupOptions = array(
|
||||
'group_base_dn' => $backendConfig->group_base_dn,
|
||||
'group_attribute' => $backendConfig->group_attribute,
|
||||
'group_member_attribute' => $backendConfig->group_member_attribute,
|
||||
'group_class' => $backendConfig->group_class
|
||||
);
|
||||
$backend = new LdapUserBackend(
|
||||
$resource,
|
||||
$backendConfig->user_class,
|
||||
$backendConfig->user_name_attribute,
|
||||
$groupOptions
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new ConfigurationError(
|
||||
|
@ -108,6 +108,18 @@ class Params
|
||||
return $this->standalone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support isset() and empty() checks on options
|
||||
*
|
||||
* @param $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
return isset($this->params[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Params::get()
|
||||
*/
|
||||
|
@ -59,6 +59,13 @@ class DbQuery extends SimpleQuery
|
||||
*/
|
||||
protected $count;
|
||||
|
||||
/**
|
||||
* GROUP BY clauses
|
||||
*
|
||||
* @var string|array
|
||||
*/
|
||||
protected $group;
|
||||
|
||||
protected function init()
|
||||
{
|
||||
$this->db = $this->ds->getDbAdapter();
|
||||
@ -89,17 +96,21 @@ class DbQuery extends SimpleQuery
|
||||
public function getSelectQuery()
|
||||
{
|
||||
$select = $this->dbSelect();
|
||||
|
||||
// Add order fields to select for postgres distinct queries (#6351)
|
||||
if ($this->hasOrder()
|
||||
&& $this->getDatasource()->getDbType() === 'pgsql'
|
||||
&& $select->getPart(Zend_Db_Select::DISTINCT) === true) {
|
||||
foreach ($this->getOrder() as $fieldAndDirection) {
|
||||
list($alias, $field) = explode('.', $fieldAndDirection[0]);
|
||||
$this->columns[$field] = $fieldAndDirection[0];
|
||||
if (array_search($fieldAndDirection[0], $this->columns) === false) {
|
||||
$this->columns[] = $fieldAndDirection[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->group) {
|
||||
$select->group($this->group);
|
||||
}
|
||||
|
||||
$select->columns($this->columns);
|
||||
$this->applyFilterSql($select);
|
||||
|
||||
@ -117,7 +128,7 @@ class DbQuery extends SimpleQuery
|
||||
return $select;
|
||||
}
|
||||
|
||||
protected function applyFilterSql($query)
|
||||
public function applyFilterSql($query)
|
||||
{
|
||||
$where = $this->renderFilter($this->filter);
|
||||
if ($where !== '') {
|
||||
@ -223,7 +234,7 @@ class DbQuery extends SimpleQuery
|
||||
*/
|
||||
public function isTimestamp($field)
|
||||
{
|
||||
return $this;
|
||||
return false;
|
||||
}
|
||||
|
||||
public function whereToSql($col, $sign, $expression)
|
||||
@ -253,6 +264,7 @@ class DbQuery extends SimpleQuery
|
||||
|
||||
$this->applyFilterSql($count);
|
||||
if ($this->useSubqueryCount) {
|
||||
$count->columns($this->columns);
|
||||
$columns = array('cnt' => 'COUNT(*)');
|
||||
return $this->db->select()->from($count, $columns);
|
||||
}
|
||||
@ -300,4 +312,17 @@ class DbQuery extends SimpleQuery
|
||||
{
|
||||
return (string) $this->getSelectQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a GROUP BY clause
|
||||
*
|
||||
* @param string|array $group
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function group($group)
|
||||
{
|
||||
$this->group = $group;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@ class FilterExpression extends Filter
|
||||
|
||||
public function __construct($column, $sign, $expression)
|
||||
{
|
||||
$column = trim($column);
|
||||
$expression = is_array($expression) ? array_map('trim', $expression) : trim($expression);
|
||||
$this->column = $column;
|
||||
$this->sign = $sign;
|
||||
$this->expression = $expression;
|
||||
|
@ -10,7 +10,6 @@ use Icinga\Util\ConfigAwareFactory;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Data\Db\DbConnection;
|
||||
use Icinga\Protocol\Livestatus\Connection as LivestatusConnection;
|
||||
use Icinga\Protocol\Statusdat\Reader as StatusdatReader;
|
||||
use Icinga\Protocol\Ldap\Connection as LdapConnection;
|
||||
use Icinga\Protocol\File\FileReader;
|
||||
|
||||
@ -102,7 +101,7 @@ class ResourceFactory implements ConfigAwareFactory
|
||||
*
|
||||
* @param Zend_Config $config The configuration for the created resource.
|
||||
*
|
||||
* @return DbConnection|LdapConnection|LivestatusConnection|StatusdatReader An objects that can be used to access
|
||||
* @return DbConnection|LdapConnection|LivestatusConnection An object that can be used to access
|
||||
* the given resource. The returned class depends on the configuration property 'type'.
|
||||
* @throws ConfigurationError When an unsupported type is given
|
||||
*/
|
||||
@ -115,9 +114,6 @@ class ResourceFactory implements ConfigAwareFactory
|
||||
case 'ldap':
|
||||
$resource = new LdapConnection($config);
|
||||
break;
|
||||
case 'statusdat':
|
||||
$resource = new StatusdatReader($config);
|
||||
break;
|
||||
case 'livestatus':
|
||||
$resource = new LivestatusConnection($config->socket);
|
||||
break;
|
||||
@ -137,7 +133,7 @@ class ResourceFactory implements ConfigAwareFactory
|
||||
* Create a resource from name
|
||||
*
|
||||
* @param string $resourceName
|
||||
* @return DbConnection|LdapConnection|LivestatusConnection|StatusdatReader
|
||||
* @return DbConnection|LdapConnection|LivestatusConnection
|
||||
*/
|
||||
public static function create($resourceName)
|
||||
{
|
||||
|
10
library/Icinga/Exception/InvalidPropertyException.php
Normal file
10
library/Icinga/Exception/InvalidPropertyException.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Exception;
|
||||
|
||||
/**
|
||||
* Exception thrown if a property does not exist
|
||||
*/
|
||||
class InvalidPropertyException extends IcingaException {}
|
12
library/Icinga/Exception/QueryException.php
Normal file
12
library/Icinga/Exception/QueryException.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Exception;
|
||||
|
||||
/**
|
||||
* Exception thrown if a query contains invalid parameters
|
||||
*/
|
||||
class QueryException extends IcingaException
|
||||
{
|
||||
}
|
@ -7,58 +7,109 @@ namespace Icinga\Logger;
|
||||
use Exception;
|
||||
use Zend_Config;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Logger\Writer\FileWriter;
|
||||
use Icinga\Logger\Writer\SyslogWriter;
|
||||
|
||||
/**
|
||||
* Singleton logger
|
||||
* Logger
|
||||
*/
|
||||
class Logger
|
||||
{
|
||||
/**
|
||||
* Debug message
|
||||
*/
|
||||
const DEBUG = 1;
|
||||
|
||||
/**
|
||||
* Informational message
|
||||
*/
|
||||
const INFO = 2;
|
||||
|
||||
/**
|
||||
* Warning message
|
||||
*/
|
||||
const WARNING = 4;
|
||||
|
||||
/**
|
||||
* Error message
|
||||
*/
|
||||
const ERROR = 8;
|
||||
|
||||
/**
|
||||
* Log levels
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $levels = array(
|
||||
Logger::DEBUG => 'DEBUG',
|
||||
Logger::INFO => 'INFO',
|
||||
Logger::WARNING => 'WARNING',
|
||||
Logger::ERROR => 'ERROR'
|
||||
);
|
||||
|
||||
/**
|
||||
* This logger's instance
|
||||
*
|
||||
* @var Logger
|
||||
* @var static
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* The log writer to use
|
||||
* Log writer
|
||||
*
|
||||
* @var \Icinga\Logger\LogWriter
|
||||
*/
|
||||
protected $writer;
|
||||
|
||||
/**
|
||||
* The configured type
|
||||
*
|
||||
* @string Type (syslog, file)
|
||||
*/
|
||||
protected $type = 'none';
|
||||
|
||||
/**
|
||||
* The maximum severity to emit
|
||||
* Maximum level to emit
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $verbosity;
|
||||
|
||||
/**
|
||||
* The supported severities
|
||||
*/
|
||||
public static $ERROR = 0;
|
||||
public static $WARNING = 1;
|
||||
public static $INFO = 2;
|
||||
public static $DEBUG = 3;
|
||||
protected $level;
|
||||
|
||||
/**
|
||||
* Create a new logger object
|
||||
*
|
||||
* @param Zend_Config $config
|
||||
* @param Zend_Config $config
|
||||
*
|
||||
* @throws ConfigurationError If the logging configuration directive 'log' is missing or if the logging level is
|
||||
* not defined
|
||||
*/
|
||||
public function __construct(Zend_Config $config)
|
||||
{
|
||||
$this->verbosity = $config->level;
|
||||
if ($config->log === null) {
|
||||
throw new ConfigurationError('Required logging configuration directive \'log\' missing');
|
||||
}
|
||||
|
||||
if ($config->enable) {
|
||||
if (($level = $config->level) !== null) {
|
||||
if (is_numeric($level)) {
|
||||
if (! isset(static::$levels[(int) $level])) {
|
||||
throw new ConfigurationError(
|
||||
'Can\'t set logging level %d. Logging level is not defined. Use one of %s or one of the'
|
||||
. ' Logger\'s constants.',
|
||||
$level,
|
||||
implode(', ', array_keys(static::$levels))
|
||||
);
|
||||
}
|
||||
$this->level = static::$levels[(int) $level];
|
||||
} else {
|
||||
$level = strtoupper($level);
|
||||
$levels = array_flip(static::$levels);
|
||||
if (! isset($levels[$level])) {
|
||||
throw new ConfigurationError(
|
||||
'Can\'t set logging level "%s". Logging level is not defined. Use one of %s.',
|
||||
$level,
|
||||
implode(', ', array_keys($levels))
|
||||
);
|
||||
}
|
||||
$this->level = $levels[$level];
|
||||
}
|
||||
} else {
|
||||
$this->level = static::ERROR;
|
||||
}
|
||||
|
||||
if (strtolower($config->get('log', 'syslog')) !== 'none') {
|
||||
$this->writer = $this->createWriter($config);
|
||||
}
|
||||
}
|
||||
@ -67,14 +118,17 @@ class Logger
|
||||
* Create a new logger object
|
||||
*
|
||||
* @param Zend_Config $config
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function create(Zend_Config $config)
|
||||
{
|
||||
static::$instance = new static($config);
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a log writer
|
||||
* Create a log writer
|
||||
*
|
||||
* @param Zend_Config $config The configuration to initialize the writer with
|
||||
*
|
||||
@ -83,28 +137,26 @@ class Logger
|
||||
*/
|
||||
protected function createWriter(Zend_Config $config)
|
||||
{
|
||||
$class = 'Icinga\\Logger\\Writer\\' . ucfirst(strtolower($config->type)) . 'Writer';
|
||||
if (!class_exists($class)) {
|
||||
$class = 'Icinga\\Logger\\Writer\\' . ucfirst(strtolower($config->log)) . 'Writer';
|
||||
if (! class_exists($class)) {
|
||||
throw new ConfigurationError(
|
||||
'Cannot find log writer of type "%s"',
|
||||
$config->type
|
||||
$config->log
|
||||
);
|
||||
}
|
||||
$this->type = $config->type;
|
||||
|
||||
return new $class($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a message to the log
|
||||
* Log a message
|
||||
*
|
||||
* @param string $message The message to write
|
||||
* @param int $severity The severity to use
|
||||
* @param int $level The logging level
|
||||
* @param string $message The log message
|
||||
*/
|
||||
public function log($message, $severity)
|
||||
public function log($level, $message)
|
||||
{
|
||||
if ($this->writer !== null && $this->verbosity >= $severity) {
|
||||
$this->writer->log($severity, $message);
|
||||
if ($this->writer !== null && $this->level >= $level) {
|
||||
$this->writer->log($level, $message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,7 +214,7 @@ class Logger
|
||||
public static function error()
|
||||
{
|
||||
if (static::$instance !== null && func_num_args() > 0) {
|
||||
static::$instance->log(static::formatMessage(func_get_args()), static::$ERROR);
|
||||
static::$instance->log(static::ERROR, static::formatMessage(func_get_args()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +226,7 @@ class Logger
|
||||
public static function warning()
|
||||
{
|
||||
if (static::$instance !== null && func_num_args() > 0) {
|
||||
static::$instance->log(static::formatMessage(func_get_args()), static::$WARNING);
|
||||
static::$instance->log(static::WARNING, static::formatMessage(func_get_args()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,7 +238,7 @@ class Logger
|
||||
public static function info()
|
||||
{
|
||||
if (static::$instance !== null && func_num_args() > 0) {
|
||||
static::$instance->log(static::formatMessage(func_get_args()), static::$INFO);
|
||||
static::$instance->log(static::INFO, static::formatMessage(func_get_args()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,7 +250,7 @@ class Logger
|
||||
public static function debug()
|
||||
{
|
||||
if (static::$instance !== null && func_num_args() > 0) {
|
||||
static::$instance->log(static::formatMessage(func_get_args()), static::$DEBUG);
|
||||
static::$instance->log(static::DEBUG, static::formatMessage(func_get_args()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,20 +264,30 @@ class Logger
|
||||
return $this->writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the logger writing to Syslog?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function writesToSyslog()
|
||||
{
|
||||
return static::$instance && static::$instance->type === 'syslog';
|
||||
return static::$instance && static::$instance instanceof SyslogWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the logger writing to a file?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function writesToFile()
|
||||
{
|
||||
return static::$instance && static::$instance->type === 'file';
|
||||
return static::$instance && static::$instance instanceof FileWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this' instance
|
||||
*
|
||||
* @return Logger
|
||||
* @return static
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
|
@ -5,38 +5,43 @@
|
||||
namespace Icinga\Logger\Writer;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Exception\IcingaException;
|
||||
use Zend_Config;
|
||||
use Icinga\Util\File;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Logger\Logger;
|
||||
use Icinga\Logger\LogWriter;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Util\File;
|
||||
|
||||
/**
|
||||
* Class to write log messages to a file
|
||||
* Log to a file
|
||||
*/
|
||||
class FileWriter extends LogWriter
|
||||
{
|
||||
/**
|
||||
* The path to the file
|
||||
* Path to the file
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* Create a new log writer initialized with the given configuration
|
||||
* Create a new file log writer
|
||||
*
|
||||
* @throws ConfigurationError In case the log path does not exist
|
||||
* @param Zend_Config $config
|
||||
*
|
||||
* @throws ConfigurationError If the configuration directive 'file' is missing or if the path to 'file' does
|
||||
* not exist or if writing to 'file' is not possible
|
||||
*/
|
||||
public function __construct(Zend_Config $config)
|
||||
{
|
||||
$this->path = $config->target;
|
||||
if ($config->file === null) {
|
||||
throw new ConfigurationError('Required logging configuration directive \'file\' missing');
|
||||
}
|
||||
$this->file = $config->file;
|
||||
|
||||
if (substr($this->path, 0, 6) !== 'php://' && false === file_exists(dirname($this->path))) {
|
||||
if (substr($this->file, 0, 6) !== 'php://' && ! file_exists(dirname($this->file))) {
|
||||
throw new ConfigurationError(
|
||||
'Log path "%s" does not exist',
|
||||
dirname($this->path)
|
||||
dirname($this->file)
|
||||
);
|
||||
}
|
||||
|
||||
@ -45,70 +50,32 @@ class FileWriter extends LogWriter
|
||||
} catch (Exception $e) {
|
||||
throw new ConfigurationError(
|
||||
'Cannot write to log file "%s" (%s)',
|
||||
$this->path,
|
||||
$this->file,
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message with the given severity
|
||||
* Log a message
|
||||
*
|
||||
* @param int $severity The severity to use
|
||||
* @param string $message The message to log
|
||||
* @param int $level The logging level
|
||||
* @param string $message The log message
|
||||
*/
|
||||
public function log($severity, $message)
|
||||
public function log($level, $message)
|
||||
{
|
||||
$this->write(date('c') . ' ' . $this->getSeverityString($severity) . ' ' . $message . PHP_EOL);
|
||||
$this->write(date('c') . ' - ' . Logger::$levels[$level] . ' - ' . $message . PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation for the given severity
|
||||
* Write a message to the log
|
||||
*
|
||||
* @param string $severity The severity to use
|
||||
*
|
||||
* @return string The string representation of the severity
|
||||
*
|
||||
* @throws IcingaException In case the given severity is unknown
|
||||
* @param string $message
|
||||
*/
|
||||
protected function getSeverityString($severity)
|
||||
protected function write($message)
|
||||
{
|
||||
switch ($severity) {
|
||||
case Logger::$ERROR:
|
||||
return '- ERROR -';
|
||||
case Logger::$WARNING:
|
||||
return '- WARNING -';
|
||||
case Logger::$INFO:
|
||||
return '- INFO -';
|
||||
case Logger::$DEBUG:
|
||||
return '- DEBUG -';
|
||||
default:
|
||||
throw new IcingaException(
|
||||
'Unknown severity "%s"',
|
||||
$severity
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a message to the path
|
||||
*
|
||||
* @param string $text The message to write
|
||||
*
|
||||
* @throws Exception In case write acess to the path failed
|
||||
*/
|
||||
protected function write($text)
|
||||
{
|
||||
$file = new File($this->path, 'a');
|
||||
$file->fwrite($text);
|
||||
$file = new File($this->file, 'a');
|
||||
$file->fwrite($message);
|
||||
$file->fflush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
||||
|
@ -4,27 +4,24 @@
|
||||
|
||||
namespace Icinga\Logger\Writer;
|
||||
|
||||
use Exception;
|
||||
use Zend_Config;
|
||||
use Icinga\Logger\Logger;
|
||||
use Icinga\Logger\LogWriter;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
/**
|
||||
* Class to write messages to syslog
|
||||
* Log to the syslog service
|
||||
*/
|
||||
class SyslogWriter extends LogWriter
|
||||
{
|
||||
/**
|
||||
* The facility where to write messages to
|
||||
* Syslog facility
|
||||
*
|
||||
* @var string
|
||||
* @var int
|
||||
*/
|
||||
protected $facility;
|
||||
|
||||
/**
|
||||
* The prefix to prepend to each message
|
||||
* Prefix to prepend to each message
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
@ -35,79 +32,42 @@ class SyslogWriter extends LogWriter
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $facilities = array(
|
||||
'LOG_USER' => LOG_USER
|
||||
public static $facilities = array(
|
||||
'user' => LOG_USER
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new log writer initialized with the given configuration
|
||||
* Log level to syslog severity map
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $severityMap = array(
|
||||
Logger::ERROR => LOG_ERR,
|
||||
Logger::WARNING => LOG_WARNING,
|
||||
Logger::INFO => LOG_INFO,
|
||||
Logger::DEBUG => LOG_DEBUG
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new syslog log writer
|
||||
*
|
||||
* @param Zend_Config $config
|
||||
*/
|
||||
public function __construct(Zend_Config $config)
|
||||
{
|
||||
if (!array_key_exists($config->facility, $this->facilities)) {
|
||||
throw new ConfigurationError(
|
||||
'Cannot create syslog writer with unknown facility "%s"',
|
||||
$config->facility
|
||||
);
|
||||
}
|
||||
|
||||
$this->ident = $config->application;
|
||||
$this->facility = $this->facilities[$config->facility];
|
||||
$this->ident = $config->get('application', 'icingaweb');
|
||||
$this->facility = static::$facilities['user'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message with the given severity
|
||||
* Log a message
|
||||
*
|
||||
* @param int $severity The severity to use
|
||||
* @param string $message The message to log
|
||||
*
|
||||
* @throws Exception In case the given severity cannot be mapped to a valid syslog priority
|
||||
* @param int $level The logging level
|
||||
* @param string $message The log message
|
||||
*/
|
||||
public function log($severity, $message)
|
||||
public function log($level, $message)
|
||||
{
|
||||
$priorities = array(
|
||||
Logger::$ERROR => LOG_ERR,
|
||||
Logger::$WARNING => LOG_WARNING,
|
||||
Logger::$INFO => LOG_INFO,
|
||||
Logger::$DEBUG => LOG_DEBUG
|
||||
);
|
||||
|
||||
if (!array_key_exists($severity, $priorities)) {
|
||||
throw new IcingaException(
|
||||
'Severity "%s" cannot be mapped to a valid syslog priority',
|
||||
$severity
|
||||
);
|
||||
}
|
||||
|
||||
$this->open();
|
||||
$this->write($priorities[$severity], $message);
|
||||
$this->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a new syslog connection
|
||||
*/
|
||||
protected function open()
|
||||
{
|
||||
openlog($this->ident, 0, $this->facility);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a message to the syslog connection
|
||||
*
|
||||
* @param int $priority The priority to use
|
||||
* @param string $message The message to write
|
||||
*/
|
||||
protected function write($priority, $message)
|
||||
{
|
||||
syslog($priority, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the syslog connection
|
||||
*/
|
||||
protected function close()
|
||||
{
|
||||
closelog();
|
||||
openlog($this->ident, LOG_PID, $this->facility);
|
||||
syslog(static::$severityMap[$level], $message);
|
||||
}
|
||||
}
|
||||
|
@ -1,177 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Commandpipe;
|
||||
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
|
||||
/**
|
||||
* Base class for any concrete command implementation
|
||||
*/
|
||||
abstract class Command
|
||||
{
|
||||
/**
|
||||
* Whether hosts are ignored in case of a host- or servicegroup
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $withoutHosts = false;
|
||||
|
||||
/**
|
||||
* Whether services are ignored in case of a host- or servicegroup
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $withoutServices = false;
|
||||
|
||||
/**
|
||||
* Whether child hosts are going to be included in case of a host command
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $withChildren = false;
|
||||
|
||||
/**
|
||||
* Whether only services are going to be included in case of a host command
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $onlyServices = false;
|
||||
|
||||
/**
|
||||
* Whether it is a global command or not
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $globalCommand = false;
|
||||
|
||||
/**
|
||||
* Set whether this command should only affect the services of a host- or servicegroup
|
||||
*
|
||||
* @param bool $state
|
||||
* @return self
|
||||
*/
|
||||
public function excludeHosts($state = true)
|
||||
{
|
||||
$this->withoutHosts = (bool) $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this command should only affect the hosts of a host- or servicegroup
|
||||
*
|
||||
* @param bool $state
|
||||
* @return self
|
||||
*/
|
||||
public function excludeServices($state = true)
|
||||
{
|
||||
$this->withoutServices = (bool) $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this command should also affect all children hosts of a host
|
||||
*
|
||||
* @param bool $state
|
||||
* @return self
|
||||
*/
|
||||
public function includeChildren($state = true)
|
||||
{
|
||||
$this->withChildren = (bool) $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this command only affects the services associated with a particular host
|
||||
*
|
||||
* @param bool $state
|
||||
* @return self
|
||||
*/
|
||||
public function excludeHost($state = true)
|
||||
{
|
||||
$this->onlyServices = (bool) $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for flag whether a command is global
|
||||
* @return bool
|
||||
*/
|
||||
public function provideGlobalCommand()
|
||||
{
|
||||
return (bool) $this->globalCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this command's arguments in the order expected by the actual command definition
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getArguments();
|
||||
|
||||
/**
|
||||
* Return the command as a string with the given host being inserted
|
||||
*
|
||||
* @param string $hostname The name of the host to insert
|
||||
*
|
||||
* @return string The string representation of the command
|
||||
*/
|
||||
abstract public function getHostCommand($hostname);
|
||||
|
||||
/**
|
||||
* Return the command as a string with the given host and service being inserted
|
||||
*
|
||||
* @param string $hostname The name of the host to insert
|
||||
* @param string $servicename The name of the service to insert
|
||||
*
|
||||
* @return string The string representation of the command
|
||||
*/
|
||||
abstract public function getServiceCommand($hostname, $servicename);
|
||||
|
||||
/**
|
||||
* Return the command as a string with the given hostgroup being inserted
|
||||
*
|
||||
* @param string $hostgroup The name of the hostgroup to insert
|
||||
*
|
||||
* @return string The string representation of the command
|
||||
*/
|
||||
public function getHostgroupCommand($hostgroup)
|
||||
{
|
||||
throw new ProgrammingError(
|
||||
'%s does not provide a hostgroup command',
|
||||
get_class($this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the command as a string with the given servicegroup being inserted
|
||||
*
|
||||
* @param string $servicegroup The name of the servicegroup to insert
|
||||
*
|
||||
* @return string The string representation of the command
|
||||
*/
|
||||
public function getServicegroupCommand($servicegroup)
|
||||
{
|
||||
throw new ProgrammingError(
|
||||
'%s does not provide a servicegroup command',
|
||||
get_class($this)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the command as a string for the whole instance
|
||||
*
|
||||
* @param string $instance
|
||||
*
|
||||
* @return string
|
||||
* @throws ProgrammingError
|
||||
*/
|
||||
public function getGlobalCommand($instance = null)
|
||||
{
|
||||
throw new ProgrammingError(
|
||||
'%s does not provide a global command',
|
||||
getclass($this)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,603 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Commandpipe;
|
||||
|
||||
use Icinga\Protocol\Commandpipe\Transport\Transport;
|
||||
use Icinga\Protocol\Commandpipe\Transport\LocalPipe;
|
||||
use Icinga\Protocol\Commandpipe\Transport\SecureShell;
|
||||
|
||||
/**
|
||||
* Class to the access icinga CommandPipe via a @see Icinga\Protocol\Commandpipe\Transport.php
|
||||
*
|
||||
* Will be configured using the instances.ini
|
||||
*/
|
||||
class CommandPipe
|
||||
{
|
||||
/**
|
||||
* The name of this class as defined in the instances.ini
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name = "";
|
||||
|
||||
/**
|
||||
* The underlying @see Icinga\Protocol\Commandpipe\Transport.php class handling communication with icinga
|
||||
*
|
||||
* @var Icinga\Protocol\Commandpipe\Transport
|
||||
*/
|
||||
private $transport = null;
|
||||
|
||||
/**
|
||||
* Constant identifying a monitoring object as host
|
||||
*/
|
||||
const TYPE_HOST = "HOST";
|
||||
|
||||
/**
|
||||
* Constant identifying a monitoring object as service
|
||||
*/
|
||||
const TYPE_SERVICE = "SVC";
|
||||
|
||||
/**
|
||||
* Constant identifying a monitoring object as hostgroup
|
||||
*/
|
||||
const TYPE_HOSTGROUP = "HOSTGROUP";
|
||||
|
||||
/**
|
||||
* Constant identifying a monitoring object as servicegroups
|
||||
*/
|
||||
const TYPE_SERVICEGROUP = "SERVICEGROUP";
|
||||
|
||||
/**
|
||||
* Notification option (use logical OR for combination)
|
||||
*
|
||||
* Broadcast (send notification to all normal and all escalated contacts for the service)
|
||||
*/
|
||||
const NOTIFY_BROADCAST = 1;
|
||||
|
||||
/**
|
||||
* Notification option (use logical OR for combination)
|
||||
*
|
||||
* notification is sent out regardless of current time, whether or not notifications are enabled, etc.
|
||||
*/
|
||||
const NOTIFY_FORCED = 2;
|
||||
|
||||
/**
|
||||
* Notification option (use logical OR for combination)
|
||||
*
|
||||
* Increment current notification # for the service(this is not done by default for custom notifications)
|
||||
*/
|
||||
const NOTIFY_INCREMENT = 4;
|
||||
|
||||
/**
|
||||
* Create a new CommandPipe class which accesses the icinga.cmd pipe as defined in $config
|
||||
*
|
||||
* @param \Zend_Config $config
|
||||
*/
|
||||
public function __construct(\Zend_Config $config)
|
||||
{
|
||||
$this->getTransportForConfiguration($config);
|
||||
$this->name = $config->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the @see Icinga\Protocol\Commandpipe\Transport.php class that will be used for accessing the command pipe
|
||||
*
|
||||
* Currently this method uses SecureShell when a host is given, otherwise it assumes the pipe is accessible
|
||||
* via the machines filesystem
|
||||
*
|
||||
* @param \Zend_Config $config The configuration as defined in the instances.ini
|
||||
*/
|
||||
private function getTransportForConfiguration(\Zend_Config $config)
|
||||
{
|
||||
if (isset($config->host)) {
|
||||
$this->transport = new SecureShell();
|
||||
$this->transport->setEndpoint($config);
|
||||
} else {
|
||||
$this->transport = new LocalPipe();
|
||||
$this->transport->setEndpoint($config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the command string $command to the icinga pipe
|
||||
*
|
||||
* This method just delegates the send command to the underlying transport
|
||||
*
|
||||
* @param String $command The command string to send, without the timestamp
|
||||
*/
|
||||
public function send($command)
|
||||
{
|
||||
$this->transport->send($this->escape($command));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the given command string with escaped newlines
|
||||
*
|
||||
* @param string $command The command string to escape
|
||||
*
|
||||
* @return string The escaped command string
|
||||
*/
|
||||
public function escape($command)
|
||||
{
|
||||
return str_replace(array("\r", "\n"), array('\r', '\n'), $command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a command to the icinga pipe
|
||||
*
|
||||
* @param Command $command
|
||||
* @param array $objects
|
||||
*/
|
||||
public function sendCommand(Command $command, array $objects = array())
|
||||
{
|
||||
if ($command->provideGlobalCommand() === true) {
|
||||
$this->send($command->getGlobalCommand());
|
||||
} else {
|
||||
foreach ($objects as $object) {
|
||||
$objectType = $this->getObjectType($object);
|
||||
if ($objectType === self::TYPE_SERVICE) {
|
||||
$this->send($command->getServiceCommand($object->host_name, $object->service_description));
|
||||
} else {
|
||||
$this->send($command->getHostCommand($object->host_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the acknowledgements of the provided objects
|
||||
*
|
||||
* @param array $objects An array of mixed service and host objects whose acknowledgments will be removed
|
||||
*/
|
||||
public function removeAcknowledge($objects)
|
||||
{
|
||||
foreach ($objects as $object) {
|
||||
if (isset($object->service_description)) {
|
||||
$this->send("REMOVE_SVC_ACKNOWLEDGEMENT;$object->host_name;$object->service_description");
|
||||
} else {
|
||||
$this->send("REMOVE_HOST_ACKNOWLEDGEMENT;$object->host_name");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the submitted comments
|
||||
*
|
||||
* @param array $objectsOrComments An array of hosts and services (to remove all their comments)
|
||||
* or single comment objects to remove
|
||||
*/
|
||||
public function removeComment($objectsOrComments)
|
||||
{
|
||||
foreach ($objectsOrComments as $object) {
|
||||
if (isset($object->comment_id)) {
|
||||
if (isset($object->service_description)) {
|
||||
$type = "SERVICE_COMMENT";
|
||||
} else {
|
||||
$type = "HOST_COMMENT";
|
||||
}
|
||||
$this->send("DEL_{$type};" . intval($object->comment_id));
|
||||
} else {
|
||||
if (isset($object->service_description)) {
|
||||
$type = "SERVICE_COMMENT";
|
||||
} else {
|
||||
$type = "HOST_COMMENT";
|
||||
}
|
||||
$cmd = "DEL_ALL_{$type}S;" . $object->host_name;
|
||||
if ($type == "SERVICE_COMMENT") {
|
||||
$cmd .= ";" . $object->service_description;
|
||||
}
|
||||
$this->send($cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Globally enable notifications for this instance
|
||||
*
|
||||
*/
|
||||
public function enableGlobalNotifications()
|
||||
{
|
||||
$this->send("ENABLE_NOTIFICATIONS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Globally disable notifications for this instance
|
||||
*
|
||||
*/
|
||||
public function disableGlobalNotifications()
|
||||
{
|
||||
$this->send("DISABLE_NOTIFICATIONS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object type of the provided object (TYPE_SERVICE or TYPE_HOST)
|
||||
*
|
||||
* @param $object The object to identify
|
||||
* @return string TYPE_SERVICE or TYPE_HOST
|
||||
*/
|
||||
private function getObjectType($object)
|
||||
{
|
||||
//@TODO: This must be refactored once more commands are supported
|
||||
if (isset($object->service_description)) {
|
||||
return self::TYPE_SERVICE;
|
||||
}
|
||||
return self::TYPE_HOST;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove downtimes for objects
|
||||
*
|
||||
* @param array $objects An array containing hosts, service or downtime objects
|
||||
* @param int $starttime An optional starttime to use for the DEL_DOWNTIME_BY_HOST_NAME command
|
||||
*/
|
||||
public function removeDowntime($objects, $starttime = 0)
|
||||
{
|
||||
foreach ($objects as $object) {
|
||||
$type = $this->getObjectType($object);
|
||||
if (isset($object->downtime_id)) {
|
||||
$this->send("DEL_" . $type . "_DOWNTIME;" . $object->downtime_id);
|
||||
continue;
|
||||
}
|
||||
$cmd = "DEL_DOWNTIME_BY_HOST_NAME;" . $object->host_name;
|
||||
if ($type == self::TYPE_SERVICE) {
|
||||
$cmd .= ";" . $object->service_description;
|
||||
}
|
||||
if ($starttime != 0) {
|
||||
$cmd .= ";" . $starttime;
|
||||
}
|
||||
$this->send($cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart the icinga instance
|
||||
*
|
||||
*/
|
||||
public function restartIcinga()
|
||||
{
|
||||
$this->send("RESTART_PROCESS");
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify monitoring flags for the provided objects
|
||||
*
|
||||
* @param array $objects An arry of service and/or host objects to modify
|
||||
* @param PropertyModifier $flags The Monitoring attributes to modify
|
||||
*/
|
||||
public function setMonitoringProperties($objects, PropertyModifier $flags)
|
||||
{
|
||||
foreach ($objects as $object) {
|
||||
$type = $this->getObjectType($object);
|
||||
$formatArray = $flags->getFormatString($type);
|
||||
foreach ($formatArray as $format) {
|
||||
$format .= ";"
|
||||
. $object->host_name
|
||||
. ($type == self::TYPE_SERVICE ? ";" . $object->service_description : "");
|
||||
$this->send($format);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable active checks for all provided objects
|
||||
*
|
||||
* @param array $objects An array containing services and hosts to enable active checks for
|
||||
*/
|
||||
public function enableActiveChecks($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::ACTIVE => PropertyModifier::STATE_ENABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable active checks for all provided objects
|
||||
*
|
||||
* @param array $objects An array containing services and hosts to disable active checks
|
||||
*/
|
||||
public function disableActiveChecks($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::ACTIVE => PropertyModifier::STATE_DISABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable passive checks for all provided objects
|
||||
*
|
||||
* @param array $objects An array containing services and hosts to enable passive checks for
|
||||
*/
|
||||
public function enablePassiveChecks($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::PASSIVE => PropertyModifier::STATE_ENABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable passive checks for all provided objects
|
||||
*
|
||||
* @param array $objects An array containing services and hosts to enable passive checks for
|
||||
*/
|
||||
public function disablePassiveChecks($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::PASSIVE => PropertyModifier::STATE_DISABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable flap detection for all provided objects
|
||||
*
|
||||
* @param array $objects An array containing services and hosts to enable flap detection
|
||||
*
|
||||
*/
|
||||
public function enableFlappingDetection($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::FLAPPING => PropertyModifier::STATE_ENABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable flap detection for all provided objects
|
||||
*
|
||||
* @param array $objects An array containing services and hosts to disable flap detection
|
||||
*
|
||||
*/
|
||||
public function disableFlappingDetection($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::FLAPPING => PropertyModifier::STATE_DISABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable notifications for all provided objects
|
||||
*
|
||||
* @param array $objects An array containing services and hosts to enable notification
|
||||
*
|
||||
*/
|
||||
public function enableNotifications($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::NOTIFICATIONS => PropertyModifier::STATE_ENABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable flap detection for all provided objects
|
||||
*
|
||||
* @param array $objects An array containing services and hosts to disable notifications
|
||||
*
|
||||
*/
|
||||
public function disableNotifications($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::NOTIFICATIONS => PropertyModifier::STATE_DISABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable freshness checks for all provided objects
|
||||
*
|
||||
* @param array $objects An array of hosts and/or services
|
||||
*/
|
||||
public function enableFreshnessChecks($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::FRESHNESS => PropertyModifier::STATE_ENABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable freshness checks for all provided objects
|
||||
*
|
||||
* @param array $objects An array of hosts and/or services
|
||||
*/
|
||||
public function disableFreshnessChecks($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::FRESHNESS => PropertyModifier::STATE_DISABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable event handler for all provided objects
|
||||
*
|
||||
* @param array $objects An array of hosts and/or services
|
||||
*/
|
||||
public function enableEventHandler($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::EVENTHANDLER => PropertyModifier::STATE_ENABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable event handler for all provided objects
|
||||
*
|
||||
* @param array $objects An array of hosts and/or services
|
||||
*/
|
||||
public function disableEventHandler($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::EVENTHANDLER => PropertyModifier::STATE_DISABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable performance data parsing for all provided objects
|
||||
*
|
||||
* @param array $objects An array of hosts and/or services
|
||||
*/
|
||||
public function enablePerfdata($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::PERFDATA => PropertyModifier::STATE_ENABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable performance data parsing for all provided objects
|
||||
*
|
||||
* @param array $objects An array of hosts and/or services
|
||||
*/
|
||||
public function disablePerfdata($objects)
|
||||
{
|
||||
$this->setMonitoringProperties(
|
||||
$objects,
|
||||
new PropertyModifier(
|
||||
array(
|
||||
PropertyModifier::PERFDATA => PropertyModifier::STATE_DISABLE
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable notifications for all services of the provided hosts
|
||||
*
|
||||
* @param array $objects An array of hosts
|
||||
*/
|
||||
public function disableNotificationsForServices($objects)
|
||||
{
|
||||
foreach ($objects as $host) {
|
||||
$msg = 'DISABLE_HOST_SVC_NOTIFICATIONS;'.$host->host_name;
|
||||
$this->send($msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable notifications for all services of the provided hosts
|
||||
*
|
||||
* @param array $objects An array of hosts
|
||||
*/
|
||||
public function enableNotificationsForServices($objects)
|
||||
{
|
||||
foreach ($objects as $host) {
|
||||
$msg = 'ENABLE_HOST_SVC_NOTIFICATIONS;'.$host->host_name;
|
||||
$this->send($msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable active checks for all services of the provided hosts
|
||||
*
|
||||
* @param array $objects An array of hosts
|
||||
*/
|
||||
public function disableActiveChecksWithChildren($objects)
|
||||
{
|
||||
foreach ($objects as $host) {
|
||||
$msg = 'DISABLE_HOST_SVC_CHECKS;'.$host->host_name;
|
||||
$this->send($msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable active checks for all services of the provided hosts
|
||||
*
|
||||
* @param array $objects An array of hosts
|
||||
*/
|
||||
public function enableActiveChecksWithChildren($objects)
|
||||
{
|
||||
foreach ($objects as $host) {
|
||||
$msg = 'ENABLE_HOST_SVC_CHECKS;'.$host->host_name;
|
||||
$this->send($msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset modified attributes for all provided objects
|
||||
*
|
||||
* @param array $objects An array of hosts and services
|
||||
*/
|
||||
public function resetAttributes($objects)
|
||||
{
|
||||
foreach ($objects as $object) {
|
||||
$type = $this->getObjectType($object);
|
||||
if ($type === self::TYPE_SERVICE) {
|
||||
$this->send('CHANGE_SVC_MODATTR;'.$object->host_name.';'.$object->service_description.';0');
|
||||
} else {
|
||||
$this->send('CHANGE_HOST_MODATTR;'.$object->host_name.';0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transport handler that handles actual sending of commands
|
||||
*
|
||||
* @return Transport
|
||||
*/
|
||||
public function getTransport()
|
||||
{
|
||||
return $this->transport;
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Commandpipe;
|
||||
|
||||
/**
|
||||
* Container for comment information that can be send to Icinga's external command pipe
|
||||
*/
|
||||
class Comment
|
||||
{
|
||||
/**
|
||||
* Whether this comment is persistent or not
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $persistent;
|
||||
|
||||
/**
|
||||
* The author of this comment
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $author;
|
||||
|
||||
/**
|
||||
* The text of this comment
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $content;
|
||||
|
||||
/**
|
||||
* Create a new comment object
|
||||
*
|
||||
* @param string $author The name of the comment's author
|
||||
* @param string $content The text for this comment
|
||||
* @param bool $persistent Whether this comment should be persistent or not
|
||||
*/
|
||||
public function __construct($author, $content, $persistent = false)
|
||||
{
|
||||
$this->author = $author;
|
||||
$this->content = $content;
|
||||
$this->persistent = $persistent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this comment's properties as list of command parameters
|
||||
*
|
||||
* @param bool $ignorePersistentFlag Whether the persistent flag should be included or not
|
||||
* @return array
|
||||
*/
|
||||
public function getArguments($ignorePersistentFlag = false)
|
||||
{
|
||||
if ($ignorePersistentFlag) {
|
||||
return array($this->author, $this->content);
|
||||
} else {
|
||||
return array($this->persistent ? '1' : '0', $this->author, $this->content);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Commandpipe\Exception;
|
||||
|
||||
/**
|
||||
* Exception class for unknown/invalid external commands
|
||||
*/
|
||||
class InvalidCommandException extends \Exception
|
||||
{
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Commandpipe;
|
||||
|
||||
/**
|
||||
* Container class to modify a few monitoring attributes at oncee
|
||||
*
|
||||
*/
|
||||
class PropertyModifier
|
||||
{
|
||||
/**
|
||||
* Set an attribute to be enabled in the command
|
||||
*/
|
||||
const STATE_ENABLE = 1;
|
||||
|
||||
/**
|
||||
* Set an attribute to be disabled in the command
|
||||
*/
|
||||
const STATE_DISABLE = 0;
|
||||
|
||||
/**
|
||||
* Set an attribute to not be modified in the command
|
||||
*/
|
||||
const STATE_KEEP = -1;
|
||||
|
||||
/**
|
||||
* Template for enabling/disabling flap detection
|
||||
*/
|
||||
const FLAPPING = "%s_FLAP_DETECTION";
|
||||
|
||||
/**
|
||||
* Template for enabling/disabling active checks
|
||||
*/
|
||||
const ACTIVE = "%s_CHECK";
|
||||
|
||||
/**
|
||||
* Template for enabling/disabling passive checks
|
||||
*/
|
||||
const PASSIVE = "PASSIVE_%s_CHECKS";
|
||||
|
||||
/**
|
||||
* Template for enabling/disabling notification
|
||||
*/
|
||||
const NOTIFICATIONS = "%s_NOTIFICATIONS";
|
||||
|
||||
/**
|
||||
* Template for enabling/disabling freshness checks
|
||||
*/
|
||||
const FRESHNESS = "%s_FRESHNESS_CHECKS";
|
||||
|
||||
/**
|
||||
* Template for enabling/disabling event handler
|
||||
*/
|
||||
const EVENTHANDLER = "%s_EVENT_HANDLER";
|
||||
|
||||
/**
|
||||
* The state that will be applied when fetching this container for an object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $flags = array(
|
||||
self::FLAPPING => self::STATE_KEEP,
|
||||
self::ACTIVE => self::STATE_KEEP,
|
||||
self::PASSIVE => self::STATE_KEEP,
|
||||
self::NOTIFICATIONS => self::STATE_KEEP,
|
||||
self::FRESHNESS => self::STATE_KEEP,
|
||||
self::EVENTHANDLER => self::STATE_KEEP
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new PropertyModified object using the given flags
|
||||
*
|
||||
* @param array $flags Flags to enable/disable/keep different monitoring attributes
|
||||
*/
|
||||
public function __construct(array $flags)
|
||||
{
|
||||
foreach ($flags as $type => $value) {
|
||||
if (isset($this->flags[$type])) {
|
||||
$this->flags[$type] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return this object as a template for the given object type
|
||||
*
|
||||
* @param $type Either CommandPipe::TYPE_HOST or CommandPipe::TYPE_SERVICE
|
||||
* @return array An array of external command templates for the given type representing the containers state
|
||||
*/
|
||||
public function getFormatString($type)
|
||||
{
|
||||
$cmd = array();
|
||||
foreach ($this->flags as $cmdTemplate => $setting) {
|
||||
if ($setting == self::STATE_KEEP) {
|
||||
continue;
|
||||
}
|
||||
$commandString = ($setting == self::STATE_ENABLE ? "ENABLE_" : "DISABLE_");
|
||||
$targetString = $type;
|
||||
if ($type == CommandPipe::TYPE_SERVICE && $cmdTemplate == self::FRESHNESS) {
|
||||
// the external command definition is inconsistent here..
|
||||
$targetString = "SERVICE";
|
||||
}
|
||||
$commandString .= sprintf($cmdTemplate, $targetString);
|
||||
$cmd[] = $commandString;
|
||||
}
|
||||
return $cmd;
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Commandpipe\Transport;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Util\File;
|
||||
use Icinga\Logger\Logger;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
|
||||
/**
|
||||
* CommandPipe Transport class that writes to a file accessible by the filesystem
|
||||
*/
|
||||
class LocalPipe implements Transport
|
||||
{
|
||||
/**
|
||||
* The path of the icinga commandpipe
|
||||
*
|
||||
* @var String
|
||||
*/
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* The mode to use to access the pipe
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $openMode = "wn";
|
||||
|
||||
/**
|
||||
* @see Transport::setEndpoint()
|
||||
*/
|
||||
public function setEndpoint(\Zend_Config $config)
|
||||
{
|
||||
$this->path = isset($config->path) ? $config->path : '/usr/local/icinga/var/rw/icinga.cmd';
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Transport::send()
|
||||
*/
|
||||
public function send($message)
|
||||
{
|
||||
Logger::debug('Attempting to send external icinga command %s to local command file ', $message, $this->path);
|
||||
|
||||
try {
|
||||
$file = new File($this->path, $this->openMode);
|
||||
$file->fwrite('[' . time() . '] ' . $message . PHP_EOL);
|
||||
$file->fflush();
|
||||
} catch (Exception $e) {
|
||||
throw new ConfigurationError(
|
||||
'Could not open icinga command pipe at "%s" (%s)',
|
||||
$this->path,
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
Logger::debug('Command sent: [' . time() . '] ' . $message . PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the open mode (useful for testing)
|
||||
*
|
||||
* @param string $mode The mode to use to access the pipe
|
||||
*/
|
||||
public function setOpenMode($mode)
|
||||
{
|
||||
$this->openMode = $mode;
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Commandpipe\Transport;
|
||||
|
||||
use RuntimeException;
|
||||
use Zend_Config;
|
||||
use Icinga\Logger\Logger;
|
||||
|
||||
/**
|
||||
* Command pipe transport class that uses ssh for connecting to a remote filesystem with the icinga.cmd pipe
|
||||
*
|
||||
* The remote host must have KeyAuth enabled for this user
|
||||
*/
|
||||
class SecureShell implements Transport
|
||||
{
|
||||
/**
|
||||
* The remote host to connect to
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $host = 'localhost';
|
||||
|
||||
/**
|
||||
* The location of the icinga pipe on the remote host
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $path = "/usr/local/icinga/var/rw/icinga.cmd";
|
||||
|
||||
/**
|
||||
* The SSH port of the remote host
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $port = 22;
|
||||
|
||||
/**
|
||||
* The user to authenticate with on the remote host
|
||||
*
|
||||
* @var String
|
||||
*/
|
||||
private $user = null;
|
||||
|
||||
/**
|
||||
* Overwrite the target file of this Transport class using the given config from instances.ini
|
||||
*
|
||||
* @param Zend_Config $config
|
||||
*
|
||||
* @see Transport::setEndpoint()
|
||||
*/
|
||||
public function setEndpoint(Zend_Config $config)
|
||||
{
|
||||
$this->host = isset($config->host) ? $config->host : 'localhost';
|
||||
$this->port = isset($config->port) ? $config->port : 22;
|
||||
$this->user = isset($config->user) ? $config->user : null;
|
||||
$this->path = isset($config->path) ? $config->path : '/usr/local/icinga/var/rw/icinga.cmd';
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the given external command to the command pipe
|
||||
*
|
||||
* @param string $command
|
||||
*
|
||||
* @throws RuntimeException When the command could not be sent to the remote Icinga host
|
||||
* @see Transport::send()
|
||||
*/
|
||||
public function send($command)
|
||||
{
|
||||
$retCode = 0;
|
||||
$output = array();
|
||||
Logger::debug(
|
||||
'Icinga instance is on different host, attempting to send command %s via ssh to %s:%s/%s',
|
||||
$command,
|
||||
$this->host,
|
||||
$this->port,
|
||||
$this->path
|
||||
);
|
||||
$hostConnector = $this->user ? $this->user . "@" . $this->host : $this->host;
|
||||
$command = escapeshellarg('['. time() .'] ' . $command);
|
||||
$sshCommand = sprintf(
|
||||
'ssh -o BatchMode=yes -o KbdInteractiveAuthentication=no %s -p %d'
|
||||
. ' "echo %s > %s" 2>&1',
|
||||
$hostConnector,
|
||||
$this->port,
|
||||
$command,
|
||||
$this->path
|
||||
);
|
||||
|
||||
exec($sshCommand, $output, $retCode);
|
||||
Logger::debug("Command '%s' exited with %d: %s", $sshCommand, $retCode, $output);
|
||||
|
||||
if ($retCode != 0) {
|
||||
$msg = 'Could not send command to remote Icinga host: '
|
||||
. implode(PHP_EOL, $output)
|
||||
. " (returncode $retCode)";
|
||||
Logger::error($msg);
|
||||
throw new RuntimeException($msg);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Commandpipe\Transport;
|
||||
|
||||
use Zend_Config;
|
||||
|
||||
/**
|
||||
* Interface for Transport classes handling the concrete access to the command pipe
|
||||
*/
|
||||
interface Transport
|
||||
{
|
||||
/**
|
||||
* Overwrite the target file of this Transport class using the given config from instances.ini
|
||||
*
|
||||
* @param Zend_Config $config A configuration file containing a 'path' setting
|
||||
*/
|
||||
public function setEndpoint(Zend_Config $config);
|
||||
|
||||
/**
|
||||
* Write the given external command to the command pipe
|
||||
*
|
||||
* @param string $message The command to send, without the timestamp (this will be added here)
|
||||
*/
|
||||
public function send($message);
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
|
||||
namespace Icinga\Protocol\File;
|
||||
|
||||
use FilterIterator;
|
||||
use Icinga\Util\EnumeratingFilterIterator;
|
||||
use Icinga\Util\File;
|
||||
|
||||
/**
|
||||
@ -12,7 +12,7 @@ use Icinga\Util\File;
|
||||
*
|
||||
* Iterate over a file, yielding only fields of non-empty lines which match a PCRE expression
|
||||
*/
|
||||
class FileIterator extends FilterIterator
|
||||
class FileIterator extends EnumeratingFilterIterator
|
||||
{
|
||||
/**
|
||||
* A PCRE string with the fields to extract from the file's lines as named subpatterns
|
||||
|
@ -6,7 +6,6 @@ namespace Icinga\Protocol\File;
|
||||
|
||||
use Icinga\Data\Selectable;
|
||||
use Countable;
|
||||
use Icinga\Util\Enumerate;
|
||||
use Zend_Config;
|
||||
|
||||
/**
|
||||
@ -53,9 +52,7 @@ class FileReader implements Selectable, Countable
|
||||
*/
|
||||
public function iterate()
|
||||
{
|
||||
return new Enumerate(
|
||||
new FileIterator($this->filename, $this->fields)
|
||||
);
|
||||
return new FileIterator($this->filename, $this->fields);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,13 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat\Exception;
|
||||
|
||||
/**
|
||||
* Class ParsingException
|
||||
* @package Icinga\Protocol\Statusdat\Exception
|
||||
*/
|
||||
class ParsingException extends \RuntimeException
|
||||
{
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
|
||||
interface IReader
|
||||
{
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getState();
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function getObjectByName($type, $name);
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
|
||||
/**
|
||||
* Class ObjectContainer
|
||||
* @package Icinga\Protocol\Statusdat
|
||||
*/
|
||||
class ObjectContainer extends \stdClass
|
||||
{
|
||||
/**
|
||||
* @var \stdClass
|
||||
*/
|
||||
public $ref;
|
||||
|
||||
/**
|
||||
* @var IReader
|
||||
*/
|
||||
public $reader;
|
||||
|
||||
/**
|
||||
* @param \stdClass $obj
|
||||
* @param IReader $reader
|
||||
*/
|
||||
public function __construct(&$obj, IReader &$reader)
|
||||
{
|
||||
$this->ref = & $obj;
|
||||
$this->reader = & $reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $attribute
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function __get($attribute)
|
||||
{
|
||||
$exploded = explode(".", $attribute);
|
||||
$result = $this->ref;
|
||||
|
||||
foreach ($exploded as $elem) {
|
||||
if (isset($result->$elem)) {
|
||||
$result = $result->$elem;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -1,422 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
|
||||
use Icinga\Util\File;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Protocol\Statusdat\Exception\ParsingException as ParsingException;
|
||||
|
||||
/**
|
||||
* Status.dat and object.cache parser implementation
|
||||
*/
|
||||
class Parser
|
||||
{
|
||||
/**
|
||||
* An array of objects that couldn't be resolved yet due to missing dependencies
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $deferred = array();
|
||||
|
||||
/**
|
||||
* The currently read file
|
||||
*
|
||||
* @var File
|
||||
*/
|
||||
private $file;
|
||||
|
||||
/**
|
||||
* String representation of the currently parsed object type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $currentObjectType;
|
||||
|
||||
/**
|
||||
* The current state type (host, service)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $currentStateType;
|
||||
|
||||
/**
|
||||
* The internal representation of the icinga statue
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $icingaState;
|
||||
|
||||
/**
|
||||
* The current line being read
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $lineCtr = 0;
|
||||
|
||||
/**
|
||||
* Create a new parser using the given file
|
||||
*
|
||||
* @param File $file The file to parse
|
||||
* @param array $baseState The state to use for the base
|
||||
*/
|
||||
public function __construct(File $file, $baseState = null)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->icingaState = $baseState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given file handle as an objects file and read object information
|
||||
*/
|
||||
public function parseObjectsFile()
|
||||
{
|
||||
$DEFINE = strlen('define ');
|
||||
$this->icingaState = array();
|
||||
foreach ($this->file as $line) {
|
||||
$line = trim($line);
|
||||
$this->lineCtr++;
|
||||
if ($line === '' || $line[0] === '#') {
|
||||
continue;
|
||||
}
|
||||
$this->currentObjectType = trim(substr($line, $DEFINE, -1));
|
||||
if (!isset($this->icingaState[$this->currentObjectType])) {
|
||||
$this->icingaState[$this->currentObjectType] = array();
|
||||
}
|
||||
$this->readCurrentObject();
|
||||
}
|
||||
$this->processDeferred();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given file as an status.dat file and read runtime information
|
||||
*
|
||||
* @param File $file The file to parse or null to parse the one passed to the constructor
|
||||
*/
|
||||
public function parseRuntimeState(File $file = null)
|
||||
{
|
||||
if ($file != null) {
|
||||
$this->file = $file;
|
||||
} else {
|
||||
$file = $this->file;
|
||||
}
|
||||
|
||||
if (!$this->icingaState) {
|
||||
throw new ProgrammingError('Tried to read runtime state without existing objects data');
|
||||
}
|
||||
$this->overwrites = array();
|
||||
foreach ($file as $line) {
|
||||
$line = trim($line);
|
||||
$this->lineCtr++;
|
||||
if ($line === '' || $line[0] === '#') {
|
||||
continue;
|
||||
}
|
||||
$this->currentStateType = trim(substr($line, 0, -1));
|
||||
$this->readCurrentState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the next object from the object.cache file handle
|
||||
*
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private function readCurrentObject()
|
||||
{
|
||||
$monitoringObject = new PrintableObject();
|
||||
foreach ($this->file as $line) {
|
||||
$line = explode("\t", trim($line), 2);
|
||||
$this->lineCtr++;
|
||||
if (!$line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// End of object
|
||||
if ($line[0] === '}') {
|
||||
$this->registerObject($monitoringObject);
|
||||
return;
|
||||
}
|
||||
if (!isset($line[1])) {
|
||||
$line[1] = '';
|
||||
}
|
||||
$monitoringObject->{$line[0]} = trim($line[1]);
|
||||
}
|
||||
throw new ParsingException('Unexpected EOF in objects.cache, line ' . $this->lineCtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the next state from the status.dat file handler
|
||||
*
|
||||
* @throws Exception\ParsingException
|
||||
*/
|
||||
private function readCurrentState()
|
||||
{
|
||||
$statusdatObject = new RuntimeStateContainer();
|
||||
|
||||
$objectType = $this->getObjectTypeForState();
|
||||
|
||||
if ($objectType != 'host' && $objectType != 'service') {
|
||||
$this->skipObject(); // ignore unknown objects
|
||||
return;
|
||||
}
|
||||
if (!isset($this->icingaState[$this->currentObjectType])) {
|
||||
throw new ParsingException("No $this->currentObjectType objects registered in objects.cache");
|
||||
}
|
||||
$base = & $this->icingaState[$this->currentObjectType];
|
||||
$state = $this->skipObject(true);
|
||||
$statusdatObject->runtimeState = & $state;
|
||||
$name = $this->getObjectIdentifier($statusdatObject);
|
||||
|
||||
if (!isset($base[$name])) {
|
||||
throw new ParsingException(
|
||||
"Unknown object $name " . $this->currentObjectType . ' - '
|
||||
. print_r(
|
||||
$statusdatObject,
|
||||
true
|
||||
)
|
||||
. "\n" . print_r($base, true)
|
||||
);
|
||||
}
|
||||
$type = substr($this->currentStateType, strlen($objectType));
|
||||
|
||||
if ($type == 'status') {
|
||||
// directly set the status to the status field of the given object
|
||||
$base[$name]->status = & $statusdatObject;
|
||||
} else {
|
||||
if (!isset($base[$name]->$type) || !in_array($base[$name]->$type, $this->overwrites)) {
|
||||
$base[$name]->$type = array();
|
||||
$this->overwrites[] = & $base[$name]->$type;
|
||||
}
|
||||
array_push($base[$name]->$type, $statusdatObject);
|
||||
$this->currentObjectType = $type;
|
||||
if (!isset($this->icingaState[$type])) {
|
||||
$this->icingaState[$type] = array();
|
||||
}
|
||||
$this->icingaState[$type][] = &$statusdatObject;
|
||||
$id = $this->getObjectIdentifier($statusdatObject);
|
||||
if ($id !== false && isset($this->icingaState[$objectType][$id])) {
|
||||
$statusdatObject->$objectType = $this->icingaState[$objectType][$id];
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the corresponding object type name for the given state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getObjectTypeForState()
|
||||
{
|
||||
$pos = strpos($this->currentStateType, 'service');
|
||||
|
||||
if ($pos === false) {
|
||||
$pos = strpos($this->currentStateType, 'host');
|
||||
} else {
|
||||
$this->currentObjectType = 'service';
|
||||
return 'service';
|
||||
}
|
||||
|
||||
if ($pos === false) {
|
||||
return $this->currentStateType;
|
||||
} else {
|
||||
$this->currentObjectType = 'host';
|
||||
return 'host';
|
||||
}
|
||||
|
||||
return $this->currentObjectType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip the current object definition
|
||||
*
|
||||
* @param bool $returnString If true, the object string will be returned
|
||||
* @return string The skipped object if $returnString is true
|
||||
*/
|
||||
protected function skipObject($returnString = false)
|
||||
{
|
||||
if (!$returnString) {
|
||||
while (trim($this->file->fgets()) !== '}') {
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
$str = '';
|
||||
while (($val = trim($this->file->fgets())) !== '}') {
|
||||
$str .= $val . "\n";
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given object in the icinga state
|
||||
*
|
||||
* @param object $object The monitoring object to register
|
||||
*/
|
||||
protected function registerObject(&$object)
|
||||
{
|
||||
|
||||
$name = $this->getObjectIdentifier($object);
|
||||
if ($name !== false) {
|
||||
$this->icingaState[$this->currentObjectType][$name] = &$object;
|
||||
}
|
||||
$this->registerObjectAsProperty($object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given object as a property in related objects
|
||||
*
|
||||
* This registers for example hosts underneath their hostgroup and vice cersa
|
||||
*
|
||||
* @param object $object The object to register as a property
|
||||
*/
|
||||
protected function registerObjectAsProperty(&$object)
|
||||
{
|
||||
if ($this->currentObjectType == 'service'
|
||||
|| $this->currentObjectType == 'host'
|
||||
|| $this->currentObjectType == 'contact') {
|
||||
return null;
|
||||
}
|
||||
$isService = strpos($this->currentObjectType, 'service') !== false;
|
||||
$isHost = strpos($this->currentObjectType, 'host') !== false;
|
||||
$isContact = strpos($this->currentObjectType, 'contact') !== false;
|
||||
$name = $this->getObjectIdentifier($object);
|
||||
|
||||
if ($isService === false && $isHost === false && $isContact === false) {
|
||||
// this would be error in the parser implementation
|
||||
return null;
|
||||
}
|
||||
$property = $this->currentObjectType;
|
||||
if ($isService) {
|
||||
$this->currentObjectType = 'service';
|
||||
$property = substr($property, strlen('service'));
|
||||
} elseif ($isHost) {
|
||||
$this->currentObjectType = 'host';
|
||||
$property = substr($property, strlen('host'));
|
||||
} elseif ($isContact) {
|
||||
$this->currentObjectType = 'contact';
|
||||
$property = substr($property, strlen('contact'));
|
||||
}
|
||||
|
||||
if (!isset($this->icingaState[$this->currentObjectType])) {
|
||||
return $this->deferRegistration($object, $this->currentObjectType . $property);
|
||||
}
|
||||
|
||||
// @TODO: Clean up, this differates between 1:n and 1:1 references
|
||||
if (strpos($property, 'group') !== false) {
|
||||
$sourceIdentifier = $this->getMembers($object);
|
||||
foreach ($sourceIdentifier as $id) {
|
||||
$source = $this->icingaState[$this->currentObjectType][$id];
|
||||
if (!isset($source->$property)) {
|
||||
$source->$property = array();
|
||||
}
|
||||
$type = $this->currentObjectType;
|
||||
if (!isset($object->$type)) {
|
||||
$object->$type = array();
|
||||
}
|
||||
// add the member to the group object
|
||||
array_push($object->$type, $source);
|
||||
// add the group to the member object
|
||||
array_push($source->$property, $name);
|
||||
}
|
||||
} else {
|
||||
$source = $this->icingaState[$this->currentObjectType][$this->getObjectIdentifier($object)];
|
||||
if (!isset($source->$property)) {
|
||||
$source->$property = array();
|
||||
}
|
||||
|
||||
array_push($source->$property, $object);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defer registration of the given object
|
||||
*
|
||||
* @param object $object The object to defer
|
||||
* @param String $objType The name of the object type
|
||||
*/
|
||||
protected function deferRegistration($object, $objType)
|
||||
{
|
||||
$this->deferred[] = array($object, $objType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process deferred objects
|
||||
*/
|
||||
protected function processDeferred()
|
||||
{
|
||||
foreach ($this->deferred as $obj) {
|
||||
$this->currentObjectType = $obj[1];
|
||||
$this->registerObjectAsProperty($obj[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resolved members directive of an object
|
||||
*
|
||||
* @param object $object The object to get the members from
|
||||
* @return array An array of member names
|
||||
*/
|
||||
protected function getMembers(&$object)
|
||||
{
|
||||
if (!isset($object->members)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$members = explode(',', $object->members);
|
||||
|
||||
if ($this->currentObjectType == 'service') {
|
||||
$res = array();
|
||||
for ($i = 0; $i < count($members); $i += 2) {
|
||||
$res[] = $members[$i] . ';' . $members[$i + 1];
|
||||
}
|
||||
return $res;
|
||||
} else {
|
||||
return $members;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unique name of the given object
|
||||
*
|
||||
* @param object $object The object to retrieve the name from
|
||||
* @return string The name of the object or null if no name can be retrieved
|
||||
*/
|
||||
protected function getObjectIdentifier(&$object)
|
||||
{
|
||||
if ($this->currentObjectType == 'contact') {
|
||||
return $object->contact_name;
|
||||
}
|
||||
|
||||
if ($this->currentObjectType == 'service') {
|
||||
return $object->host_name . ';' . $object->service_description;
|
||||
}
|
||||
$name = $this->currentObjectType . '_name';
|
||||
if (isset($object->{$name})) {
|
||||
return $object->{$name};
|
||||
}
|
||||
if (isset($object->service_description)) {
|
||||
return $object->host_name . ';' . $object->service_description;
|
||||
} elseif (isset($object->host_name)) {
|
||||
return $object->host_name;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the internal state of the parser
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function getRuntimeState()
|
||||
{
|
||||
return $this->icingaState;
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
|
||||
class PrintableObject
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
if (isset($this->contact_name)) {
|
||||
return $this->contact_name;
|
||||
} elseif (isset($this->service_description)) {
|
||||
return $this->service_description;
|
||||
} elseif (isset($this->host_name)) {
|
||||
return $this->host_name;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
@ -1,460 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Data\SimpleQuery;
|
||||
use Icinga\Protocol\Statusdat\View\MonitoringObjectList;
|
||||
use Icinga\Protocol\Statusdat\Query\IQueryPart;
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
/**
|
||||
* Base implementation for Statusdat queries.
|
||||
*/
|
||||
class Query extends SimpleQuery
|
||||
{
|
||||
/**
|
||||
* An array denoting valid targets by mapping the query target to
|
||||
* the 'define' directives found in the status.dat/objects.cache files
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $VALID_TARGETS = array(
|
||||
'hosts' => array('host'),
|
||||
'services' => array('service'),
|
||||
'downtimes' => array('downtime'),
|
||||
'groups' => array('hostgroup', 'servicegroup'),
|
||||
'hostgroups' => array('hostgroup'),
|
||||
'servicegroups' => array('servicegroup'),
|
||||
'comments' => array('comment'),
|
||||
'contacts' => array('contact'),
|
||||
'contactgroups' => array('contactgroup')
|
||||
);
|
||||
|
||||
/**
|
||||
* The current StatusDat query that will be applied upon calling fetchAll
|
||||
*
|
||||
* @var IQueryPart
|
||||
*/
|
||||
private $queryFilter = null;
|
||||
|
||||
/**
|
||||
* The current query source being used
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $source = '';
|
||||
|
||||
/**
|
||||
* An array containing all columns used for sorting
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $orderColumns = array();
|
||||
|
||||
/**
|
||||
* An array containig all columns used for (simple) grouping
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $groupColumns = array();
|
||||
|
||||
/**
|
||||
* An optional function callback to use for more specific grouping
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $groupByFn = null;
|
||||
|
||||
/**
|
||||
* The scope index for the callback function
|
||||
*/
|
||||
const FN_SCOPE = 0;
|
||||
|
||||
/**
|
||||
* The name index for the callback function
|
||||
*/
|
||||
const FN_NAME = 1;
|
||||
|
||||
/**
|
||||
* Return true if columns are set for this query
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasColumns()
|
||||
{
|
||||
$columns = $this->getColumns();
|
||||
return !empty($columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status.dat specific IQueryPart filter to use
|
||||
*
|
||||
* @param IQueryPart $filter
|
||||
*/
|
||||
public function setQueryFilter($filter)
|
||||
{
|
||||
$this->queryFilter = $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order the query result by the given columns
|
||||
*
|
||||
* @param String|array $columns An array of columns to order by
|
||||
* @param String $dir The direction (asc or desc) in string form
|
||||
*
|
||||
* @return $this Fluent interface
|
||||
*/
|
||||
public function order($columns, $dir = null, $isFunction = false)
|
||||
{
|
||||
if ($dir && strtolower($dir) == 'desc') {
|
||||
$dir = self::SORT_DESC;
|
||||
} else {
|
||||
$dir = self::SORT_ASC;
|
||||
}
|
||||
if (!is_array($columns)) {
|
||||
$columns = array($columns);
|
||||
}
|
||||
|
||||
foreach ($columns as $col) {
|
||||
if (($pos = strpos($col, ' ')) !== false) {
|
||||
$dir = strtoupper(substr($col, $pos + 1));
|
||||
if ($dir === 'DESC') {
|
||||
$dir = self::SORT_DESC;
|
||||
} else {
|
||||
$dir = self::SORT_ASC;
|
||||
}
|
||||
$col = substr($col, 0, $pos);
|
||||
} else {
|
||||
$col = $col;
|
||||
}
|
||||
|
||||
$this->orderColumns[] = array($col, $dir);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order the query result using the callback to retrieve values for items
|
||||
*
|
||||
* @param array $columns A scope, function array to use for retrieving the values when ordering
|
||||
* @param String $dir The direction (asc or desc) in string form
|
||||
*
|
||||
* @return $this Fluent interface
|
||||
*/
|
||||
public function orderByFn(array $callBack, $dir = null)
|
||||
{
|
||||
if ($dir && strtolower($dir) == 'desc') {
|
||||
$dir = self::SORT_DESC;
|
||||
} else {
|
||||
$dir = self::SORT_ASC;
|
||||
}
|
||||
$this->orderColumns[] = array($callBack, $dir);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the query target
|
||||
*
|
||||
* @param String $table The table/target to select the query from
|
||||
* @param array $columns An array of attributes to use (required for fetchPairs())
|
||||
*
|
||||
* @return $this Fluent interface
|
||||
* @throws IcingaException If the target is unknonw
|
||||
*/
|
||||
public function from($table, array $attributes = null)
|
||||
{
|
||||
if (!$this->getColumns() && $attributes) {
|
||||
$this->setColumns($attributes);
|
||||
}
|
||||
if (isset(self::$VALID_TARGETS[$table])) {
|
||||
$this->source = $table;
|
||||
} else {
|
||||
throw new IcingaException(
|
||||
'Unknown from target for status.dat :%s',
|
||||
$table
|
||||
);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an index of all objects matching the filter of this query
|
||||
*
|
||||
* This index will be used for ordering, grouping and limiting
|
||||
*/
|
||||
private function getFilteredIndices($classType = '\Icinga\Protocol\Statusdat\Query\Group')
|
||||
{
|
||||
$baseGroup = $this->queryFilter;
|
||||
$state = $this->ds->getState();
|
||||
$result = array();
|
||||
$source = self::$VALID_TARGETS[$this->source];
|
||||
|
||||
foreach ($source as $target) {
|
||||
|
||||
if (! isset($state[$target])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$indexes = array_keys($state[$target]);
|
||||
if ($baseGroup) {
|
||||
$baseGroup->setQuery($this);
|
||||
$idx = array_keys($state[$target]);
|
||||
$indexes = $baseGroup->filter($state[$target], $idx);
|
||||
}
|
||||
if (!isset($result[$target])) {
|
||||
$result[$target] = $indexes;
|
||||
} else {
|
||||
array_merge($result[$target], $indexes);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order the given result set
|
||||
*
|
||||
* @param array $indices The result set of the query that should be ordered
|
||||
*/
|
||||
private function orderIndices(array &$indices)
|
||||
{
|
||||
if (!empty($this->orderColumns)) {
|
||||
foreach ($indices as $type => &$subindices) {
|
||||
$this->currentType = $type;
|
||||
usort($subindices, array($this, 'orderResult'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a query
|
||||
*
|
||||
* This is just a dummy function to allow a more convenient syntax
|
||||
*
|
||||
* @return self Fluent interface
|
||||
*/
|
||||
public function select()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order implementation called by usort
|
||||
*
|
||||
* @param String $a The left object index
|
||||
* @param Strinv $b The right object index
|
||||
* @return int 0, 1 or -1, see usort for detail
|
||||
*/
|
||||
private function orderResult($a, $b)
|
||||
{
|
||||
$o1 = $this->ds->getObjectByName($this->currentType, $a);
|
||||
$o2 = $this->ds->getObjectByName($this->currentType, $b);
|
||||
$result = 0;
|
||||
|
||||
foreach ($this->orderColumns as &$col) {
|
||||
if (is_array($col[0])) {
|
||||
// sort by function
|
||||
$result += $col[1] * strnatcasecmp(
|
||||
$col[0][0]->$col[0][1]($o1),
|
||||
$col[0][0]->$col[0][1]($o2)
|
||||
);
|
||||
} else {
|
||||
$result += $col[1] * strnatcasecmp($o1->{$col[0]}, $o2->{$col[0]});
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit the given resultset
|
||||
*
|
||||
* @param array $indices The filtered, ordered indices
|
||||
*/
|
||||
private function limitIndices(array &$indices)
|
||||
{
|
||||
foreach ($indices as $type => $subindices) {
|
||||
$indices[$type] = array_slice($subindices, $this->getOffset(), $this->getLimit());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given function for grouping the result
|
||||
*
|
||||
* @param String $fn The function to use for grouping
|
||||
* @param Object $scope An optional scope to use instead of $this
|
||||
*
|
||||
* @return self Fluent interface
|
||||
*/
|
||||
public function groupByFunction($fn, $scope = null)
|
||||
{
|
||||
$this->groupByFn = array($scope ? $scope : $this, $fn);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Group by the given column
|
||||
*
|
||||
* @param array|string $columns The columns to use for grouping
|
||||
* @return self Fluent interface
|
||||
* @see Query::columnGroupFn() The implementation used for grouping
|
||||
*/
|
||||
public function groupByColumns($columns)
|
||||
{
|
||||
if (!is_array($columns)) {
|
||||
$columns = array($columns);
|
||||
}
|
||||
$this->groupColumns = $columns;
|
||||
$this->groupByFn = array($this, 'columnGroupFn');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The internal handler function used by the group function
|
||||
*
|
||||
* @param array $indices The indices to group
|
||||
* @return array The grouped result set
|
||||
*/
|
||||
private function columnGroupFn(array &$indices)
|
||||
{
|
||||
$cols = $this->groupColumns;
|
||||
$result = array();
|
||||
foreach ($indices as $type => $subindices) {
|
||||
foreach ($subindices as $objectIndex) {
|
||||
$r = $this->ds->getObjectByName($type, $objectIndex);
|
||||
$hash = '';
|
||||
$cols = array();
|
||||
foreach ($this->groupColumns as $col) {
|
||||
$hash = md5($hash . $r->$col);
|
||||
$cols[$col] = $r->$col;
|
||||
}
|
||||
if (!isset($result[$hash])) {
|
||||
$result[$hash] = (object)array(
|
||||
'columns' => (object)$cols,
|
||||
'count' => 0
|
||||
);
|
||||
}
|
||||
$result[$hash]->count++;
|
||||
}
|
||||
}
|
||||
return array_values($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query Filter, Order, Group, Limit and return the result set
|
||||
*
|
||||
* @return array The resultset matching this query
|
||||
*/
|
||||
public function getResult()
|
||||
{
|
||||
$indices = $this->getFilteredIndices();
|
||||
$this->orderIndices($indices);
|
||||
if ($this->groupByFn) {
|
||||
$scope = $this->groupByFn[self::FN_SCOPE];
|
||||
$fn = $this->groupByFn[self::FN_NAME];
|
||||
|
||||
return $scope->$fn($indices);
|
||||
}
|
||||
|
||||
$this->limitIndices($indices);
|
||||
|
||||
$result = array();
|
||||
$state = $this->ds->getState();
|
||||
|
||||
foreach ($indices as $type => $subindices) {
|
||||
foreach ($subindices as $index) {
|
||||
$result[] = & $state[$type][$index];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Apply all filters of this filterable on the datasource
|
||||
*/
|
||||
public function applyFilter()
|
||||
{
|
||||
$parser = new TreeToStatusdatQueryParser();
|
||||
if ($this->getFilter()) {
|
||||
$query = $parser->treeToQuery($this->getFilter(), $this);
|
||||
$this->setQueryFilter($query);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only the first row fetched from the result set
|
||||
*
|
||||
* @return MonitoringObjectList The monitoring object matching this query
|
||||
*/
|
||||
public function fetchRow()
|
||||
{
|
||||
$rs = $this->fetchAll();
|
||||
$rs->rewind();
|
||||
return $rs->current();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the result as an associative array using the first column as the key and the second as the value
|
||||
*
|
||||
* @return array An associative array with the result
|
||||
* @throws IcingaException If no attributes are defined
|
||||
*/
|
||||
public function fetchPairs()
|
||||
{
|
||||
$result = array();
|
||||
if (count($this->getColumns()) < 2) {
|
||||
throw new IcingaException(
|
||||
'Status.dat "fetchPairs()" query expects at least columns to be set in the query expression'
|
||||
);
|
||||
}
|
||||
$attributes = $this->getColumns();
|
||||
|
||||
$param1 = $attributes[0];
|
||||
$param2 = $attributes[1];
|
||||
foreach ($this->fetchAll() as $resultList) {
|
||||
$result[$resultList->$param1] = $resultList->$param2;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all results
|
||||
*
|
||||
* @return MonitoringObjectList An MonitoringObjectList wrapping the given resultset
|
||||
*/
|
||||
public function fetchAll()
|
||||
{
|
||||
$this->applyFilter();
|
||||
if (!isset($this->cursor)) {
|
||||
$result = $this->getResult();
|
||||
$this->cursor = new MonitoringObjectList($result, $this);
|
||||
}
|
||||
return $this->cursor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of the first column for the first row fetched from the result set
|
||||
*/
|
||||
public function fetchOne()
|
||||
{
|
||||
throw new ProgrammingError('Statusdat/Query::fetchOne() is not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of results
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
$q = clone $this;
|
||||
$q->limit(null, null);
|
||||
return count($q->fetchAll());
|
||||
}
|
||||
}
|
@ -1,415 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat\Query;
|
||||
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
class Expression implements IQueryPart
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const ENC_NUMERIC = 0;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const ENC_SET = 0;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const ENC_STRING = 0;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $expression;
|
||||
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
private $field = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $basedata = array();
|
||||
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
private $function = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $value = "";
|
||||
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
private $operator = null;
|
||||
|
||||
/**
|
||||
* Optional query information
|
||||
*
|
||||
* @var null
|
||||
*/
|
||||
private $query = null;
|
||||
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
private $name = null;
|
||||
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
public $CB = null;
|
||||
|
||||
/**
|
||||
* @param $token
|
||||
* @throws IcingaException
|
||||
*/
|
||||
private function getOperatorType($token)
|
||||
{
|
||||
switch (strtoupper($token)) {
|
||||
case ">":
|
||||
$this->CB = "isGreater";
|
||||
break;
|
||||
case "<":
|
||||
$this->CB = "isLess";
|
||||
break;
|
||||
case ">=":
|
||||
$this->CB = "isGreaterEq";
|
||||
break;
|
||||
case "<=":
|
||||
$this->CB = "isLessEq";
|
||||
break;
|
||||
case "=":
|
||||
$this->CB = "isEqual";
|
||||
break;
|
||||
case "LIKE":
|
||||
$this->CB = "isLike";
|
||||
break;
|
||||
case "NOT_LIKE":
|
||||
$this->CB = "isNotLike";
|
||||
break;
|
||||
case "!=":
|
||||
$this->CB = "isNotEqual";
|
||||
break;
|
||||
case "IN":
|
||||
$this->CB = "isIn";
|
||||
break;
|
||||
case "NOT_IN":
|
||||
$this->CB = "isNotIn";
|
||||
break;
|
||||
default:
|
||||
throw new IcingaException(
|
||||
'Unknown operator %s in expression %s !',
|
||||
$token,
|
||||
$this->expression
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $tokens
|
||||
* @return mixed
|
||||
*/
|
||||
private function extractAggregationFunction(&$tokens)
|
||||
{
|
||||
$token = $tokens[0];
|
||||
$value = array();
|
||||
if (preg_match("/COUNT\{(.*)\}/", $token, $value) == false) {
|
||||
return $token;
|
||||
}
|
||||
$this->function = "count";
|
||||
$tokens[0] = $value[1];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $values
|
||||
*/
|
||||
private function parseExpression(&$values)
|
||||
{
|
||||
$tokenized = preg_split("/ +/", trim($this->expression), 3);
|
||||
$this->extractAggregationFunction($tokenized);
|
||||
if (count($tokenized) != 3) {
|
||||
echo(
|
||||
"Currently statusdat query expressions must be in "
|
||||
. "the format FIELD OPERATOR ? or FIELD OPERATOR :value_name"
|
||||
);
|
||||
}
|
||||
|
||||
$this->fields = explode(".", trim($tokenized[0]));
|
||||
$this->field = $this->fields[count($this->fields) - 1];
|
||||
|
||||
$this->getOperatorType(trim($tokenized[1]));
|
||||
$tokenized[2] = trim($tokenized[2]);
|
||||
|
||||
if ($tokenized[2][0] === ":") {
|
||||
$this->name = substr($tokenized, 1);
|
||||
$this->value = $values[$this->name];
|
||||
} else {
|
||||
if ($tokenized[2] === "?") {
|
||||
$this->value = array_shift($values);
|
||||
} else {
|
||||
$this->value = trim($tokenized[2]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $expression
|
||||
* @param $values
|
||||
* @return $this
|
||||
*/
|
||||
public function fromString($expression, &$values)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
$this->parseExpression($values);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $expression
|
||||
* @param array $values
|
||||
*/
|
||||
public function __construct($expression = null, &$values = array())
|
||||
{
|
||||
if ($expression) {
|
||||
if (!is_array($values)) {
|
||||
$values = array($values);
|
||||
}
|
||||
$this->fromString($expression, $values);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $base
|
||||
* @param array $idx
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function filter(array &$base, &$idx = array())
|
||||
{
|
||||
if (!$idx) {
|
||||
$idx = array_keys($base);
|
||||
}
|
||||
$this->basedata = $base;
|
||||
return array_filter($idx, array($this, "filterFn"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getField()
|
||||
{
|
||||
return $this->field;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $idx
|
||||
* @return bool
|
||||
*/
|
||||
protected function filterFn($idx)
|
||||
{
|
||||
$values = $this->getFieldValues($idx);
|
||||
|
||||
if ($values === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->CB == "isIn" || $this->CB == "isNotIn") {
|
||||
$cmpValues = is_array($this->value) ? $this->value : array($this->value);
|
||||
foreach ($cmpValues as $cmpValue) {
|
||||
$this->value = $cmpValue;
|
||||
foreach ($values as $value) {
|
||||
if ($this->CB == "isIn" && $this->isLike($value)) {
|
||||
$this->value = $cmpValues;
|
||||
return true;
|
||||
} elseif ($this->CB == "isNotIn" && $this->isNotLike($value)) {
|
||||
$this->value = $cmpValues;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->value = $cmpValues;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->function) {
|
||||
$values = call_user_func($this->function, $values);
|
||||
if (!is_array($values)) {
|
||||
$values = array($values);
|
||||
}
|
||||
}
|
||||
foreach ($values as $val) {
|
||||
|
||||
if (!is_string($val) && !is_numeric($val) && is_object($val)) {
|
||||
if (isset($val->service_description)) {
|
||||
$val = $val->service_description;
|
||||
} elseif (isset($val->host_name)) {
|
||||
$val = $val->host_name;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ($this->{$this->CB}($val)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $idx
|
||||
* @return array
|
||||
*/
|
||||
private function getFieldValues($idx)
|
||||
{
|
||||
$res = $this->basedata[$idx];
|
||||
|
||||
foreach ($this->fields as $field) {
|
||||
if (!is_array($res)) {
|
||||
if ($this->query) {
|
||||
$res = $this->query->get($res, $field);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($res->$field)) {
|
||||
$res = array();
|
||||
break;
|
||||
}
|
||||
$res = $res->$field;
|
||||
continue;
|
||||
}
|
||||
|
||||
// it can be that an element contains more than one value, like it
|
||||
// happens when using comments, in this case we have to create a new
|
||||
// array that contains the values/objects we're searching
|
||||
$swap = array();
|
||||
foreach ($res as $sub) {
|
||||
if ($this->query) {
|
||||
$swap[] = $this->query->get($sub, $field);
|
||||
continue;
|
||||
}
|
||||
if (!isset($sub->$field)) {
|
||||
continue;
|
||||
}
|
||||
if (!is_array($sub->$field)) {
|
||||
$swap[] = $sub->$field;
|
||||
} else {
|
||||
$swap = array_merge($swap, $sub->$field);
|
||||
}
|
||||
}
|
||||
$res = $swap;
|
||||
}
|
||||
if (!is_array($res)) {
|
||||
return array($res);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isGreater($value)
|
||||
{
|
||||
return $value > $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isLess($value)
|
||||
{
|
||||
return $value < $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isLike($value)
|
||||
{
|
||||
return preg_match("/^" . str_replace("%", ".*", $this->value) . "$/", $value) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isNotLike($value)
|
||||
{
|
||||
return !preg_match("/^" . str_replace("%", ".*", $this->value) . "$/", $value) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isEqual($value)
|
||||
{
|
||||
if (!is_numeric($value)) {
|
||||
return strtolower($value) == strtolower($this->value);
|
||||
}
|
||||
return $value == $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isNotEqual($value)
|
||||
{
|
||||
return $value != $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isGreaterEq($value)
|
||||
{
|
||||
return $value >= $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isLessEq($value)
|
||||
{
|
||||
return $value <= $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional information about the query this filter belongs to
|
||||
*
|
||||
* @param $query
|
||||
* @return mixed
|
||||
*/
|
||||
public function setQuery($query)
|
||||
{
|
||||
$this->query = $query;
|
||||
}
|
||||
}
|
@ -1,397 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat\Query;
|
||||
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
/**
|
||||
* Class Group
|
||||
* @package Icinga\Protocol\Statusdat\Query
|
||||
*/
|
||||
class Group implements IQueryPart
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const GROUP_BEGIN = "(";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const GROUP_END = ")";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const CONJUNCTION_AND = "AND ";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const CONJUNCTION_OR = "OR ";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const EXPRESSION = 0;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const EOF = -1;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const TYPE_AND = "AND";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const TYPE_OR = "OR";
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $items = array();
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $parsePos = 0;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $expression = "";
|
||||
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
private $expressionClass = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $type = "";
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $subExpressionStart = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $subExpressionLength = 0;
|
||||
|
||||
/**
|
||||
* Optional query to use
|
||||
*
|
||||
* @var Query
|
||||
*/
|
||||
private $query = null;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type ? $this->type : self::TYPE_AND;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IcingaException
|
||||
*/
|
||||
private function tokenize()
|
||||
{
|
||||
$token = 0;
|
||||
$subgroupCount = 0;
|
||||
while ($token != self::EOF) {
|
||||
|
||||
$token = $this->getNextToken();
|
||||
|
||||
if ($token === self::GROUP_BEGIN) {
|
||||
|
||||
/**
|
||||
* check if this is a nested group, if so then it's
|
||||
* considered part of the subexpression
|
||||
*/
|
||||
if ($subgroupCount == 0) {
|
||||
$this->startNewSubExpression();
|
||||
}
|
||||
$subgroupCount++;
|
||||
continue;
|
||||
}
|
||||
if ($token === self::GROUP_END) {
|
||||
if ($subgroupCount < 1) {
|
||||
throw new IcingaException(
|
||||
'Invalid Query: unexpected \')\' at pos %s',
|
||||
$this->parsePos
|
||||
);
|
||||
}
|
||||
$subgroupCount--;
|
||||
/*
|
||||
* check if this is a nested group, if so then it's
|
||||
* considered part of the subexpression
|
||||
*/
|
||||
if ($subgroupCount == 0) {
|
||||
$this->addSubgroupFromExpression();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($token === self::CONJUNCTION_AND && $subgroupCount == 0) {
|
||||
$this->startNewSubExpression();
|
||||
if ($this->type != self::TYPE_AND && $this->type != "") {
|
||||
$this->createImplicitGroup(self::TYPE_AND);
|
||||
break;
|
||||
} else {
|
||||
$this->type = self::TYPE_AND;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($token === self::CONJUNCTION_OR && $subgroupCount == 0) {
|
||||
$this->startNewSubExpression();
|
||||
if ($this->type != self::TYPE_OR && $this->type != "") {
|
||||
$this->createImplicitGroup(self::TYPE_OR);
|
||||
break;
|
||||
} else {
|
||||
|
||||
$this->type = self::TYPE_OR;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->subExpressionLength = $this->parsePos - $this->subExpressionStart;
|
||||
}
|
||||
if ($subgroupCount > 0) {
|
||||
throw new IcingaException('Unexpected end of query, are you missing a parenthesis?');
|
||||
}
|
||||
|
||||
$this->startNewSubExpression();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
*/
|
||||
private function createImplicitGroup($type)
|
||||
{
|
||||
$group = new Group();
|
||||
$group->setType($type);
|
||||
$group->addItem(array_pop($this->items));
|
||||
|
||||
$group->fromString(substr($this->expression, $this->parsePos), $this->value, $this->expressionClass);
|
||||
$this->items[] = $group;
|
||||
$this->parsePos = strlen($this->expression);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function startNewSubExpression()
|
||||
{
|
||||
if ($this->getCurrentSubExpression() != "") {
|
||||
if (!$this->expressionClass) {
|
||||
$this->items[] = new Expression($this->getCurrentSubExpression(), $this->value);
|
||||
} else {
|
||||
$this->items[] = new $this->expressionClass($this->getCurrentSubExpression(), $this->value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->subExpressionStart = $this->parsePos;
|
||||
$this->subExpressionLength = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getCurrentSubExpression()
|
||||
{
|
||||
|
||||
return substr($this->expression, $this->subExpressionStart, $this->subExpressionLength);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function addSubgroupFromExpression()
|
||||
{
|
||||
|
||||
if (!$this->expressionClass) {
|
||||
$this->items[] = new Group($this->getCurrentSubExpression(), $this->value);
|
||||
} else {
|
||||
$group = new Group();
|
||||
$group->fromString($this->getCurrentSubExpression(), $this->value, $this->expressionClass);
|
||||
$this->items[] = $group;
|
||||
}
|
||||
$this->subExpressionStart = $this->parsePos;
|
||||
$this->subExpressionLength = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isEOF()
|
||||
{
|
||||
if ($this->parsePos >= strlen($this->expression)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|string
|
||||
*/
|
||||
private function getNextToken()
|
||||
{
|
||||
if ($this->isEOF()) {
|
||||
return self::EOF;
|
||||
}
|
||||
|
||||
// skip whitespaces
|
||||
while ($this->expression[$this->parsePos] == " ") {
|
||||
$this->parsePos++;
|
||||
if ($this->isEOF()) {
|
||||
return self::EOF;
|
||||
}
|
||||
}
|
||||
if ($this->expression[$this->parsePos] == self::GROUP_BEGIN) {
|
||||
$this->parsePos++;
|
||||
return self::GROUP_BEGIN;
|
||||
}
|
||||
if ($this->expression[$this->parsePos] == self::GROUP_END) {
|
||||
$this->parsePos++;
|
||||
return self::GROUP_END;
|
||||
}
|
||||
if (substr_compare(
|
||||
$this->expression,
|
||||
self::CONJUNCTION_AND,
|
||||
$this->parsePos,
|
||||
strlen(self::CONJUNCTION_AND),
|
||||
true
|
||||
) === 0) {
|
||||
$this->parsePos += strlen(self::CONJUNCTION_AND);
|
||||
return self::CONJUNCTION_AND;
|
||||
}
|
||||
if (substr_compare(
|
||||
$this->expression,
|
||||
self::CONJUNCTION_OR,
|
||||
$this->parsePos,
|
||||
strlen(self::CONJUNCTION_OR),
|
||||
true
|
||||
) === 0) {
|
||||
$this->parsePos += strlen(self::CONJUNCTION_OR);
|
||||
return self::CONJUNCTION_OR;
|
||||
}
|
||||
$this->parsePos++;
|
||||
return self::EXPRESSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ex
|
||||
* @return $this
|
||||
*/
|
||||
public function addItem($ex)
|
||||
{
|
||||
$this->items[] = $ex;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $expression
|
||||
* @param array $value
|
||||
* @param null $expressionClass
|
||||
* @return $this
|
||||
*/
|
||||
public function fromString($expression, &$value = array(), $expressionClass = null)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
$this->value = & $value;
|
||||
$this->expressionClass = $expressionClass;
|
||||
|
||||
$this->tokenize();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $expression
|
||||
* @param array $value
|
||||
*/
|
||||
public function __construct($expression = null, &$value = array())
|
||||
{
|
||||
if ($expression) {
|
||||
$this->fromString($expression, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $base
|
||||
* @param null $idx
|
||||
* @return array|null
|
||||
*/
|
||||
public function filter(array &$base, &$idx = null)
|
||||
{
|
||||
if ($this->type == self::TYPE_OR) {
|
||||
$idx = array();
|
||||
foreach ($this->items as &$subFilter) {
|
||||
$baseKeys = array_keys($base);
|
||||
$subFilter->setQuery($this->query);
|
||||
$idx += $subFilter->filter($base, $baseKeys);
|
||||
}
|
||||
} else {
|
||||
if (!$idx) {
|
||||
$idx = array_keys($base);
|
||||
}
|
||||
foreach ($this->items as $subFilter) {
|
||||
$subFilter->setQuery($this->query);
|
||||
$idx = array_intersect($idx, $subFilter->filter($base, $idx));
|
||||
}
|
||||
}
|
||||
|
||||
return $idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional information about the query this filter belongs to
|
||||
*
|
||||
* @param $query
|
||||
* @return mixed
|
||||
*/
|
||||
public function setQuery($query)
|
||||
{
|
||||
$this->query = $query;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat\Query;
|
||||
|
||||
/**
|
||||
* Class IQueryPart
|
||||
* @package Icinga\Protocol\Statusdat\Query
|
||||
*/
|
||||
interface IQueryPart
|
||||
{
|
||||
/**
|
||||
* Create a new query part with an optional expression to be parse
|
||||
*
|
||||
* @param string $expression An optional expression string to use
|
||||
* @param array $value The values fot the optional expression
|
||||
*/
|
||||
public function __construct($expression = null, &$value = array());
|
||||
|
||||
/**
|
||||
* Filter the given resultset
|
||||
*
|
||||
* @param array $base The resultset to use for filtering
|
||||
* @param array $idx An optional array containing prefiltered indices
|
||||
*/
|
||||
public function filter(array &$base, &$idx = null);
|
||||
|
||||
/**
|
||||
* Add additional information about the query this filter belongs to
|
||||
*
|
||||
* @param $query
|
||||
* @return mixed
|
||||
*/
|
||||
public function setQuery($query);
|
||||
}
|
@ -1,330 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
|
||||
use Icinga\Util\File;
|
||||
use Icinga\Logger\Logger;
|
||||
use Icinga\Data\Selectable;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
|
||||
/**
|
||||
* Class Reader
|
||||
* @package Icinga\Protocol\Statusdat
|
||||
*/
|
||||
class Reader implements IReader, Selectable
|
||||
{
|
||||
/**
|
||||
* The default lifetime of the cache in milliseconds
|
||||
*/
|
||||
const DEFAULT_CACHE_LIFETIME = 30;
|
||||
|
||||
/**
|
||||
* The folder for the statusdat cache
|
||||
*/
|
||||
const STATUSDAT_DEFAULT_CACHE_PATH = '/tmp';
|
||||
|
||||
/**
|
||||
* The last state from the cache
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $lastState;
|
||||
|
||||
/**
|
||||
* True when this reader has already acquired the current runtime state (i.e. Status.dat)
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $hasRuntimeState = false;
|
||||
|
||||
/**
|
||||
* The representation of the object.cache file
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $objectCache ;
|
||||
|
||||
/**
|
||||
* The representation of the status.dat file
|
||||
* @var array
|
||||
*/
|
||||
private $statusCache;
|
||||
|
||||
/**
|
||||
* True when the icinga state differs from the cache
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $newState = false;
|
||||
|
||||
/**
|
||||
* The Parser object to use for parsing
|
||||
*
|
||||
* @var Parser
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
/**
|
||||
* Whether to disable the cache
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $noCache;
|
||||
|
||||
/**
|
||||
* Create a new Reader from the given configuraion
|
||||
*
|
||||
* @param Zend_Config $config The configuration to read the status.dat information from
|
||||
* @param Parser $parser The parser to use (for testing)
|
||||
* @param bool $noCache Whether to disable the cache
|
||||
*/
|
||||
public function __construct($config = \Zend_Config, $parser = null, $noCache = false)
|
||||
{
|
||||
$this->noCache = $noCache;
|
||||
if (isset($config->no_cache)) {
|
||||
$this->noCache = $config->no_cache;
|
||||
}
|
||||
$this->config = $config;
|
||||
$this->parser = $parser;
|
||||
|
||||
if (!$this->noCache) {
|
||||
$this->cache = $this->initializeCaches($config);
|
||||
if ($this->fromCache()) {
|
||||
$this->createHostServiceConnections();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->lastState) {
|
||||
$this->parseObjectsCacheFile();
|
||||
}
|
||||
if (!$this->hasRuntimeState) {
|
||||
|
||||
}
|
||||
$this->parseStatusDatFile();
|
||||
if (!$noCache && $this->newState) {
|
||||
$this->statusCache->save($this->parser->getRuntimeState(), 'object' . md5($this->config->object_file));
|
||||
}
|
||||
$this->createHostServiceConnections();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the internal caches if enabled
|
||||
*
|
||||
* @throws ConfigurationError
|
||||
*/
|
||||
private function initializeCaches()
|
||||
{
|
||||
$defaultCachePath = self::STATUSDAT_DEFAULT_CACHE_PATH;
|
||||
$cachePath = $this->config->get('cache_path', $defaultCachePath);
|
||||
$maxCacheLifetime = intval($this->config->get('cache_path', self::DEFAULT_CACHE_LIFETIME));
|
||||
$cachingEnabled = true;
|
||||
if (!is_writeable($cachePath)) {
|
||||
Logger::warning(
|
||||
'Can\'t cache Status.dat backend; make sure cachepath %s is writable by the web user. '
|
||||
. 'Caching is now disabled',
|
||||
$cachePath
|
||||
);
|
||||
$cachePath = null;
|
||||
}
|
||||
$backendOptions = array(
|
||||
'cache_dir' => $cachePath
|
||||
);
|
||||
// the object cache might exist for months and is still valid
|
||||
$this->objectCache = $this->initCache($this->config->object_file, $backendOptions, null, $cachingEnabled);
|
||||
$this->statusCache = $this->initCache(
|
||||
$this->config->status_file,
|
||||
$backendOptions,
|
||||
$maxCacheLifetime,
|
||||
$cachingEnabled
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the Cache backend in Zend
|
||||
*
|
||||
* @param String $file The file to use as the cache master file
|
||||
* @param Zend_Config $backend The backend configuration to use
|
||||
* @param integer $lifetime The lifetime of the cache
|
||||
*
|
||||
* @return \Zend_Cache_Core|\Zend_Cache_Frontend
|
||||
*/
|
||||
private function initCache($file, $backendConfig, $lifetime)
|
||||
{
|
||||
$frontendOptions = array(
|
||||
'lifetime' => $lifetime,
|
||||
'automatic_serialization' => true,
|
||||
'master_files' => array($file)
|
||||
);
|
||||
return \Zend_Cache::factory('Core', 'File', $frontendOptions, $backendConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current cache state
|
||||
*
|
||||
* @return bool True if the state is the same as the icinga state
|
||||
*/
|
||||
private function fromCache()
|
||||
{
|
||||
if (!$this->readObjectsCache()) {
|
||||
$this->newState = true;
|
||||
return false;
|
||||
}
|
||||
if (!$this->readStatusCache()) {
|
||||
$this->newState = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the object.cache file from the Zend_Cache backend
|
||||
*
|
||||
* @return bool True if the file could be loaded from cache
|
||||
*/
|
||||
private function readObjectsCache()
|
||||
{
|
||||
$this->lastState = $this->objectCache->load('object' . md5($this->config->object_file));
|
||||
if ($this->lastState == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the status.dat file from the Zend_Cache backend
|
||||
*
|
||||
* @return bool True if the file could be loaded from cache
|
||||
*/
|
||||
private function readStatusCache()
|
||||
{
|
||||
if (!isset($this->stateCache)) {
|
||||
return true;
|
||||
}
|
||||
$statusInfo = $this->stateCache->load('state' . md5($this->config->status_file));
|
||||
if ($statusInfo == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->hasRuntimeState = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the status.dat and objects.cache and connect all services to hosts
|
||||
*
|
||||
*/
|
||||
private function createHostServiceConnections()
|
||||
{
|
||||
if (!isset($this->lastState["service"])) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->lastState["host"] as &$host) {
|
||||
$host->host = $host;
|
||||
}
|
||||
foreach ($this->lastState["service"] as &$service) {
|
||||
$service->service = &$service; // allow easier querying
|
||||
$host = &$this->lastState["host"][$service->host_name];
|
||||
if (!isset($host->services)) {
|
||||
$host->services = array();
|
||||
}
|
||||
$host->services[$service->service_description] = & $service;
|
||||
$service->host = & $host;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the object.cache file and update the current state
|
||||
*
|
||||
* @throws ConfigurationError If the object.cache couldn't be read
|
||||
*/
|
||||
private function parseObjectsCacheFile()
|
||||
{
|
||||
if (!is_readable($this->config->object_file)) {
|
||||
throw new ConfigurationError(
|
||||
'Can\'t read object-file "%s", check your configuration',
|
||||
$this->config->object_file
|
||||
);
|
||||
}
|
||||
if (!$this->parser) {
|
||||
$this->parser = new Parser(new File($this->config->object_file, 'r'));
|
||||
}
|
||||
$this->parser->parseObjectsFile();
|
||||
$this->lastState = $this->parser->getRuntimeState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the status.dat file and update the current state
|
||||
*
|
||||
* @throws ConfigurationError If the status.dat couldn't be read
|
||||
*/
|
||||
private function parseStatusDatFile()
|
||||
{
|
||||
if (!is_readable($this->config->status_file)) {
|
||||
throw new ConfigurationError(
|
||||
'Can\'t read status-file %s, check your configuration',
|
||||
$this->config->status_file
|
||||
);
|
||||
}
|
||||
if (!$this->parser) {
|
||||
$this->parser = new Parser(new File($this->config->status_file, 'r'), $this->lastState);
|
||||
}
|
||||
$this->parser->parseRuntimeState(new File($this->config->status_file, 'r'));
|
||||
$this->lastState = $this->parser->getRuntimeState();
|
||||
if (!$this->noCache) {
|
||||
$this->statusCache->save(array("true" => true), "state" . md5($this->config->object_file));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Query
|
||||
*
|
||||
* @return Query The query to operate on
|
||||
*/
|
||||
public function select()
|
||||
{
|
||||
return new Query($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the internal state of the status.dat
|
||||
*
|
||||
* @return mixed The internal status.dat representation
|
||||
*/
|
||||
public function getState()
|
||||
{
|
||||
return $this->lastState;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the object with the given name and type
|
||||
*
|
||||
* @param String $type The type of the object to return (service, host, servicegroup...)
|
||||
* @param String $name The name of the object
|
||||
*
|
||||
* @return ObjectContainer An object container wrapping the result or null if the object doesn't exist
|
||||
*/
|
||||
public function getObjectByName($type, $name)
|
||||
{
|
||||
if (isset($this->lastState[$type]) && isset($this->lastState[$type][$name])) {
|
||||
return new ObjectContainer($this->lastState[$type][$name], $this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array containing all names of monitoring objects with the given type
|
||||
*
|
||||
* @param String $type The type of object to get the names for
|
||||
* @return array An array of names or null if the type does not exist
|
||||
*/
|
||||
public function getObjectNames($type)
|
||||
{
|
||||
return isset($this->lastState[$type]) ? array_keys($this->lastState[$type]) : null;
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
|
||||
/**
|
||||
* Container class containing the runtime state of an object
|
||||
*
|
||||
* This class contains the state of the object as a string and parses it
|
||||
* on the fly as soon as values should be retrieved. This reduces memory usage,
|
||||
* as most runtime information is never received and only lives for a very short time.
|
||||
*
|
||||
*/
|
||||
class RuntimeStateContainer extends \stdClass
|
||||
{
|
||||
/**
|
||||
* The state string
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $runtimeState = "";
|
||||
|
||||
/**
|
||||
* Create a new runtime state container from the givven string
|
||||
*
|
||||
* @param string $str
|
||||
*/
|
||||
public function __construct($str = "")
|
||||
{
|
||||
$this->runtimeState = $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the argument exists
|
||||
*
|
||||
* @param String $attr The argument to retrieve
|
||||
* @return bool True if it exists, otherwise false
|
||||
*/
|
||||
public function __isset($attr)
|
||||
{
|
||||
try {
|
||||
$this->__get($attr);
|
||||
return true;
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the given attribute
|
||||
*
|
||||
* If the container string is not yet parsed, this will happen here
|
||||
*
|
||||
* @param String $attr The attribute to retrieve
|
||||
* @return mixed The value of the attribute
|
||||
* @throws \InvalidArgumentException When the attribute does not exist
|
||||
*/
|
||||
public function __get($attr)
|
||||
{
|
||||
$start = strpos($this->runtimeState, $attr . "=");
|
||||
if ($start === false) {
|
||||
throw new \InvalidArgumentException("Unknown property $attr");
|
||||
}
|
||||
|
||||
$start += strlen($attr . "=");
|
||||
$len = strpos($this->runtimeState, "\n", $start) - $start;
|
||||
$this->$attr = trim(substr($this->runtimeState, $start, $len));
|
||||
|
||||
return $this->$attr;
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat\View;
|
||||
|
||||
/**
|
||||
* Interface for statusdat classes that provide a specific view on the dataset
|
||||
*
|
||||
* Views define special get and exists operations for fields that are not directly available
|
||||
* in a resultset, but exist under another name or can be accessed by loading an additional object
|
||||
* during runtime.
|
||||
*
|
||||
* @see Icinga\Backend\DataView\ObjectRemappingView For an implementation of mapping field names
|
||||
* to storage specific names, e.g. service_state being status.current_state in status.dat views.
|
||||
*
|
||||
* @see Icinga\Backend\MonitoringObjectList For the typical usage of this class. It is not wrapped
|
||||
* around the monitoring object, so we don't use __get() or __set() and always have to give the
|
||||
* item we'd like to access.
|
||||
*/
|
||||
interface AccessorStrategy
|
||||
{
|
||||
/**
|
||||
* Returns a field for the item, or throws an Exception if the field doesn't exist
|
||||
*
|
||||
* @param $item The item to access
|
||||
* @param $field The field of the item that should be accessed
|
||||
* @return string The content of the field
|
||||
*
|
||||
* @throws \InvalidArgumentException when the field does not exist
|
||||
*/
|
||||
public function get(&$item, $field);
|
||||
|
||||
/**
|
||||
* Returns true if the field exists on the specific item, otherwise false
|
||||
*
|
||||
* @param $item The item to access
|
||||
* @param $field The field to check on the $item
|
||||
* @return bool True when the field exists, otherwise false
|
||||
*/
|
||||
public function exists(&$item, $field);
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Protocol\Statusdat\View;
|
||||
|
||||
use Iterator;
|
||||
use Countable;
|
||||
use ArrayAccess;
|
||||
use Exception;
|
||||
use Icinga\Exception\IcingaException;
|
||||
|
||||
/**
|
||||
* Wrapper around an array of monitoring objects that can be enhanced with an optional
|
||||
* object that extends AccessorStrategy. This will act as a dataview and provide
|
||||
* normalized access to the underlying data (mapping properties, retrieving additional data)
|
||||
*
|
||||
* If not Accessor is set, this class just behaves like a normal Iterator and returns
|
||||
* the underlying objects.
|
||||
*
|
||||
* If the dataset contains arrays instead of objects, they will be cast to objects.
|
||||
*
|
||||
*/
|
||||
class MonitoringObjectList implements Iterator, Countable, ArrayAccess
|
||||
{
|
||||
private $dataSet = array();
|
||||
private $position = 0;
|
||||
private $dataView = null;
|
||||
|
||||
public function __construct(array &$dataset, AccessorStrategy $dataView = null)
|
||||
{
|
||||
$this->dataSet = $dataset;
|
||||
$this->position = 0;
|
||||
$this->dataView = $dataView;
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
return count($this->dataSet);
|
||||
}
|
||||
|
||||
public function setPosition($pos)
|
||||
{
|
||||
$this->position = $pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Return the current element
|
||||
* @link http://php.net/manual/en/iterator.current.php
|
||||
* @return mixed Can return any type.
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
if ($this->dataView) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
return $this->dataSet[$this->position];
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Move forward to next element
|
||||
* @link http://php.net/manual/en/iterator.next.php
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->position++;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Return the key of the current element
|
||||
* @link http://php.net/manual/en/iterator.key.php
|
||||
* @return mixed scalar on success, or null on failure.
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Checks if current position is valid
|
||||
* @link http://php.net/manual/en/iterator.valid.php
|
||||
* @return boolean The return value will be casted to boolean and then evaluated.
|
||||
* Returns true on success or false on failure.
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->position < count($this->dataSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Rewind the Iterator to the first element
|
||||
* @link http://php.net/manual/en/iterator.rewind.php
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->position = 0;
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
{
|
||||
return $this->dataView->exists($this->dataSet[$this->position], $name);
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
return $this->dataView->get($this->dataSet[$this->position], $name);
|
||||
}
|
||||
|
||||
public function __set($name, $value)
|
||||
{
|
||||
throw new IcingaException('Setting is currently not available for objects');
|
||||
}
|
||||
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return count($this->dataSet) < $offset;
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
$res = new MonitoringObjectList($this->dataSet, $this->dataView);
|
||||
$res->position = $offset;
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
// non mutable
|
||||
}
|
||||
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
// non mutable
|
||||
}
|
||||
}
|
@ -25,20 +25,16 @@ namespace Icinga\Test {
|
||||
use RuntimeException;
|
||||
use Mockery;
|
||||
use Zend_Config;
|
||||
use Zend_Controller_Request_Abstract;
|
||||
use Zend_Controller_Request_HttpTestCase;
|
||||
use PHPUnit_Framework_TestCase;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Util\DateTimeFactory;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Data\Db\DbConnection;
|
||||
use Icinga\User\Preferences;
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Class BaseTestCase
|
||||
*/
|
||||
class BaseTestCase extends PHPUnit_Framework_TestCase implements DbTest, FormTest
|
||||
class BaseTestCase extends PHPUnit_Framework_TestCase implements DbTest
|
||||
{
|
||||
/**
|
||||
* Path to application/
|
||||
@ -82,13 +78,6 @@ namespace Icinga\Test {
|
||||
*/
|
||||
public static $moduleDir;
|
||||
|
||||
/**
|
||||
* Store request for form tests
|
||||
*
|
||||
* @var Zend_Controller_Request_HttpTestCase
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* Resource configuration for different database types
|
||||
*
|
||||
@ -151,28 +140,54 @@ namespace Icinga\Test {
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$requestMock = Mockery::mock('Icinga\Web\Request');
|
||||
$requestMock->shouldReceive('getPathInfo')->andReturn('')
|
||||
->shouldReceive('getBaseUrl')->andReturn('/')
|
||||
->shouldReceive('getQuery')->andReturn(array());
|
||||
$this->setupIcingaMock($requestMock);
|
||||
$this->setupIcingaMock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup mock object for the application's bootstrap
|
||||
*
|
||||
* @param Zend_Controller_Request_Abstract $request The request to be returned by
|
||||
* Icinga::app()->getFrontController()->getRequest()
|
||||
* @return Mockery\Mock
|
||||
*/
|
||||
protected function setupIcingaMock(Zend_Controller_Request_Abstract $request)
|
||||
protected function setupIcingaMock()
|
||||
{
|
||||
$requestMock = Mockery::mock('Icinga\Web\Request')->shouldDeferMissing();
|
||||
$requestMock->shouldReceive('getPathInfo')->andReturn('')->byDefault()
|
||||
->shouldReceive('getBaseUrl')->andReturn('/')->byDefault()
|
||||
->shouldReceive('getQuery')->andReturn(array())->byDefault()
|
||||
->shouldReceive('getParam')->with(Mockery::type('string'), Mockery::type('string'))
|
||||
->andReturnUsing(function ($name, $default) { return $default; })->byDefault();
|
||||
|
||||
$responseMock = Mockery::mock('Icinga\Web\Response')->shouldDeferMissing();
|
||||
|
||||
// Can't express this as demeter chains. See: https://github.com/padraic/mockery/issues/59
|
||||
$bootstrapMock = Mockery::mock('Icinga\Application\ApplicationBootstrap')->shouldDeferMissing();
|
||||
$bootstrapMock->shouldReceive('getFrontController->getRequest')->andReturnUsing(
|
||||
function () use ($request) { return $request; }
|
||||
)->shouldReceive('getApplicationDir')->andReturn(self::$appDir);
|
||||
$bootstrapMock->shouldReceive('getFrontController')->andReturn($bootstrapMock)
|
||||
->shouldReceive('getApplicationDir')->andReturn(self::$appDir)
|
||||
->shouldReceive('getRequest')->andReturn($requestMock)
|
||||
->shouldReceive('getResponse')->andReturn($responseMock);
|
||||
|
||||
Icinga::setApp($bootstrapMock, true);
|
||||
return $bootstrapMock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the currently active request mock object
|
||||
*
|
||||
* @return Icinga\Web\Request
|
||||
*/
|
||||
public function getRequestMock()
|
||||
{
|
||||
return Icinga::app()->getFrontController()->getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the currently active response mock object
|
||||
*
|
||||
* @return Icinga\Web\Response
|
||||
*/
|
||||
public function getResponseMock()
|
||||
{
|
||||
return Icinga::app()->getFrontController()->getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -298,58 +313,6 @@ namespace Icinga\Test {
|
||||
$adapter->exec('DROP TABLE ' . $table . ';');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a form
|
||||
*
|
||||
* If the form has CSRF protection enabled, creates the form's token element and adds the generated token to the
|
||||
* request data
|
||||
*
|
||||
* @param string $formClass Qualified class name of the form to create. Note that the class has to be
|
||||
* defined as no attempt is made to require the class before instantiating.
|
||||
* @param array $requestData Request data for the form
|
||||
*
|
||||
* @return Form
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function createForm($formClass, array $requestData = array())
|
||||
{
|
||||
$form = new $formClass;
|
||||
// If the form has CSRF protection enabled, add the token to the request data, else all calls to
|
||||
// isSubmittedAndValid will fail
|
||||
$form->setSessionId('1234');
|
||||
$form->initCsrfToken();
|
||||
$token = $form->getValue($form->getTokenElementName());
|
||||
if ($token !== null) {
|
||||
$requestData[$form->getTokenElementName()] = $token;
|
||||
}
|
||||
$request = $this->getRequest();
|
||||
$request->setMethod('POST');
|
||||
$request->setPost($requestData);
|
||||
$form->setRequest($request);
|
||||
$form->setUserPreferences(
|
||||
new Preferences(
|
||||
array()
|
||||
)
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve test case request object
|
||||
*
|
||||
* This is a mock methods borrowed from Zend Controller Test Case to handle form tests properly (#6106)
|
||||
*
|
||||
* @return Zend_Controller_Request_HttpTestCase
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
if (null === $this->request) {
|
||||
require_once 'Zend/Controller/Request/HttpTestCase.php';
|
||||
$this->request = new Zend_Controller_Request_HttpTestCase;
|
||||
}
|
||||
return $this->request;
|
||||
}
|
||||
}
|
||||
|
||||
BaseTestCase::setupTimezone();
|
||||
|
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Test;
|
||||
|
||||
use Icinga\Web\Form;
|
||||
|
||||
/**
|
||||
* Interface to test form objects
|
||||
*/
|
||||
interface FormTest
|
||||
{
|
||||
/**
|
||||
* Instantiate a new form object
|
||||
*
|
||||
* @param string $formClass Form class to instantiate
|
||||
* @param array $requestData Request data for the form
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
public function createForm($formClass, array $requestData = array());
|
||||
}
|
@ -7,7 +7,6 @@ namespace Icinga;
|
||||
use DateTimeZone;
|
||||
use InvalidArgumentException;
|
||||
use Icinga\User\Preferences;
|
||||
use Icinga\User\Message;
|
||||
|
||||
/**
|
||||
* This class represents an authorized user
|
||||
@ -98,13 +97,6 @@ class User
|
||||
*/
|
||||
protected $preferences;
|
||||
|
||||
/**
|
||||
* Queued notifications for this user.
|
||||
*
|
||||
* @var array()
|
||||
*/
|
||||
protected $messages;
|
||||
|
||||
/**
|
||||
* Creates a user object given the provided information
|
||||
*
|
||||
@ -187,9 +179,9 @@ class User
|
||||
}
|
||||
|
||||
/**
|
||||
* Return permission information for this user
|
||||
* Get the user's permissions
|
||||
*
|
||||
* @return array
|
||||
* @return array
|
||||
*/
|
||||
public function getPermissions()
|
||||
{
|
||||
@ -197,13 +189,19 @@ class User
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for permissions
|
||||
* Set the user's permissions
|
||||
*
|
||||
* @param array $permissions
|
||||
* @param array $permissions
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPermissions(array $permissions)
|
||||
{
|
||||
$this->permissions = $permissions;
|
||||
natcasesort($permissions);
|
||||
if (! empty($permissions)) {
|
||||
$this->permissions = array_combine($permissions, $permissions);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -382,38 +380,6 @@ class User
|
||||
return new DateTimeZone($tz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a message that can be accessed from future requests, to this user.
|
||||
*
|
||||
* This function does NOT automatically write to the session, messages will not be persisted until you do.
|
||||
*
|
||||
* @param Message $msg The message
|
||||
*/
|
||||
public function addMessage(Message $msg)
|
||||
{
|
||||
$this->messages[] = $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all currently pending messages
|
||||
*
|
||||
* @return array The messages
|
||||
*/
|
||||
public function getMessages()
|
||||
{
|
||||
return isset($this->messages) ? $this->messages : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all messages from this user
|
||||
*
|
||||
* This function does NOT automatically write the session, messages will not be persisted until you do.
|
||||
*/
|
||||
public function clearMessages()
|
||||
{
|
||||
$this->messages = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set additional remote user information
|
||||
*
|
||||
@ -442,6 +408,33 @@ class User
|
||||
*/
|
||||
public function isRemoteUser()
|
||||
{
|
||||
return (count($this->remoteUserInformation)) ? true : false;
|
||||
return ! empty($this->remoteUserInformation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user has a given permission
|
||||
*
|
||||
* @param string $permission
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can($permission)
|
||||
{
|
||||
if (isset($this->permissions['*']) || isset($this->permissions[$permission])) {
|
||||
return true;
|
||||
}
|
||||
foreach ($this->permissions as $permitted) {
|
||||
$wildcard = strpos($permitted, '*');
|
||||
if ($wildcard !== false) {
|
||||
if (substr($permission, 0, $wildcard) === substr($permitted, 0, $wildcard)) {
|
||||
return true;
|
||||
} else {
|
||||
if ($permission === $permitted) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\User;
|
||||
|
||||
use Zend_Log;
|
||||
|
||||
/**
|
||||
* Class Message
|
||||
*
|
||||
* A Message with an additional logging level to indicate the type.
|
||||
*
|
||||
* @package Icinga\User
|
||||
*/
|
||||
class Message
|
||||
{
|
||||
/**
|
||||
* The content of this message
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $message;
|
||||
|
||||
/**
|
||||
* The logging-level of this message
|
||||
*/
|
||||
private $level;
|
||||
|
||||
/**
|
||||
* Create a new Message
|
||||
*
|
||||
* @param string $message The message content
|
||||
* @param $level The status of the message
|
||||
* * Zend_Log::INFO
|
||||
* * Zend_Log::ERR
|
||||
*/
|
||||
public function __construct($message, $level = Zend_Log::INFO)
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMessage()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The
|
||||
*/
|
||||
public function getLevel()
|
||||
{
|
||||
return $this->level;
|
||||
}
|
||||
}
|
@ -79,19 +79,38 @@ class Preferences implements Countable
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a preference and return $default if the preference is not set
|
||||
* Retrieve a preference section
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
* @return array|null
|
||||
*/
|
||||
public function get($name, $default = null)
|
||||
public function get($name)
|
||||
{
|
||||
if (array_key_exists($name, $this->preferences)) {
|
||||
return $this->preferences[$name];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a value from a specific section
|
||||
*
|
||||
* @param string $section
|
||||
* @param string $name
|
||||
* @param null $default
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getValue($section, $name, $default = null)
|
||||
{
|
||||
if (array_key_exists($section, $this->preferences)
|
||||
&& array_key_exists($name, $this->preferences[$section])
|
||||
) {
|
||||
return $this->preferences[$section][$name];
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
|
@ -76,4 +76,18 @@ class DateTimeFactory implements ConfigAwareFactory
|
||||
{
|
||||
return new DateTime($time, $timeZone !== null ? $timeZone : self::$timeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a variable is a Unix timestamp
|
||||
*
|
||||
* @param mixed $timestamp
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isUnixTimestamp($timestamp)
|
||||
{
|
||||
return (is_int($timestamp) || ctype_digit($timestamp))
|
||||
&& ($timestamp <= PHP_INT_MAX)
|
||||
&& ($timestamp >= ~PHP_INT_MAX);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user