Merge branch 'master' into feature/deduplicate-puppet-code-6842

Conflicts:
	packages/rpm/etc/icingaweb2/resources.ini
This commit is contained in:
Alexander Klimov 2014-10-20 13:12:31 +02:00
commit 570b31fe05
351 changed files with 14561 additions and 16562 deletions

View File

@ -14,7 +14,6 @@ use Icinga\Exception\AuthenticationException;
use Icinga\Exception\NotReadableError; use Icinga\Exception\NotReadableError;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
use Icinga\User; use Icinga\User;
use Icinga\Web\Session;
use Icinga\Web\Url; use Icinga\Web\Url;
/** /**
@ -36,7 +35,6 @@ class AuthenticationController extends ActionController
{ {
$auth = $this->Auth(); $auth = $this->Auth();
$this->view->form = $form = new LoginForm(); $this->view->form = $form = new LoginForm();
$form->setRequest($this->_request);
$this->view->title = $this->translate('Icingaweb Login'); $this->view->title = $this->translate('Icingaweb Login');
try { try {
@ -55,27 +53,17 @@ class AuthenticationController extends ActionController
$config = Config::app('authentication'); $config = Config::app('authentication');
} catch (NotReadableError $e) { } catch (NotReadableError $e) {
throw new ConfigurationError( throw new ConfigurationError(
$this->translate( $this->translate('Could not read your authentiction.ini, no authentication methods are available.'),
'Could not read your authentiction.ini, no authentication methods are available.' 0,
) $e
); );
} }
$chain = new AuthChain($config); $chain = new AuthChain($config);
if ($this->getRequest()->isGet()) { $request = $this->getRequest();
$user = new User(''); if ($request->isPost() && $this->view->form->isValid($request->getPost())) {
foreach ($chain as $backend) { $user = new User($this->view->form->getValue('username'));
if ($backend instanceof AutoLoginBackend) { $password = $this->view->form->getValue('password');
$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');
$backendsTried = 0; $backendsTried = 0;
$backendsWithError = 0; $backendsWithError = 0;
@ -121,14 +109,27 @@ class AuthenticationController extends ActionController
); );
} }
if ($backendsWithError) { if ($backendsWithError) {
$form->addNote( $this->view->form->getElement('username')->addError(
$this->translate( $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.' . ' 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) { } catch (Exception $e) {
$this->view->errorInfo = $e->getMessage(); $this->view->errorInfo = $e->getMessage();
@ -141,14 +142,16 @@ class AuthenticationController extends ActionController
public function logoutAction() public function logoutAction()
{ {
$auth = $this->Auth(); $auth = $this->Auth();
if (! $auth->isAuthenticated()) {
$this->redirectToLogin();
}
$isRemoteUser = $auth->getUser()->isRemoteUser(); $isRemoteUser = $auth->getUser()->isRemoteUser();
$auth->removeAuthorization(); $auth->removeAuthorization();
if ($isRemoteUser === true) { if ($isRemoteUser === true) {
$this->_helper->layout->setLayout('login'); $this->_helper->layout->setLayout('login');
$this->_response->setHttpResponseCode(401); $this->_response->setHttpResponseCode(401);
} else { } else {
$this->rerenderLayout()->redirectToLogin(); $this->redirectToLogin();
} }
} }
} }

View File

@ -2,38 +2,25 @@
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Web\Controller\BaseConfigController; use Icinga\Web\Controller\ActionController;
use Icinga\Web\Widget\Tab;
use Icinga\Web\Widget\AlertMessageBox;
use Icinga\Web\Notification; use Icinga\Web\Notification;
use Icinga\Application\Modules\Module; use Icinga\Application\Modules\Module;
use Icinga\Web\Url;
use Icinga\Web\Widget; use Icinga\Web\Widget;
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
use Icinga\Application\Config as IcingaConfig; 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\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 * 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() public function init()
{ {
$this->view->tabs = Widget::create('tabs')->add('index', array( $this->view->tabs = Widget::create('tabs')->add('index', array(
@ -45,9 +32,6 @@ class ConfigController extends BaseConfigController
))->add('resources', array( ))->add('resources', array(
'title' => 'Resources', 'title' => 'Resources',
'url' => 'config/resource' 'url' => 'config/resource'
))->add('logging', array(
'title' => 'Logging',
'url' => 'config/logging'
)); ));
} }
@ -61,42 +45,12 @@ class ConfigController extends BaseConfigController
*/ */
public function indexAction() 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'); $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 { try {
$manager->enableModule($module); $manager->enableModule($module);
$manager->loadModule($module); $manager->loadModule($module);
Notification::success('Module "' . $module . '" enabled'); Notification::success(sprintf($this->translate('Module "%s" enabled'), $module));
$this->rerenderLayout()->reloadCss()->redirectNow('config/modules'); $this->rerenderLayout()->reloadCss()->redirectNow('config/modules');
} catch (Exception $e) { } catch (Exception $e) {
$this->view->exceptionMesssage = $e->getMessage(); $this->view->exceptionMesssage = $e->getMessage();
@ -161,7 +115,7 @@ class ConfigController extends BaseConfigController
$manager = Icinga::app()->getModuleManager(); $manager = Icinga::app()->getModuleManager();
try { try {
$manager->disableModule($module); $manager->disableModule($module);
Notification::success('Module "' . $module . '" disabled'); Notification::success(sprintf($this->translate('Module "%s" disabled'), $module));
$this->rerenderLayout()->reloadCss()->redirectNow('config/modules'); $this->rerenderLayout()->reloadCss()->redirectNow('config/modules');
} catch (Exception $e) { } catch (Exception $e) {
$this->view->exceptionMessage = $e->getMessage(); $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() 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'); $this->view->tabs->activate('authentication');
$this->render('authentication/reorder');
$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;
} }
/** /**
@ -213,316 +144,151 @@ class ConfigController extends BaseConfigController
*/ */
public function createauthenticationbackendAction() 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->form = $form;
$this->view->tabs->activate('authentication');
$this->render('authentication/create'); $this->render('authentication/create');
} }
/** /**
* Form for editing backends * Action for editing authentication backends
*
* Mostly the same like the createAuthenticationBackendAction, but with additional checks for backend existence
* and form population
*/ */
public function editauthenticationbackendAction() 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->form = $form;
$this->view->tabs->activate('authentication');
$this->render('authentication/modify'); $this->render('authentication/modify');
} }
/** /**
* Action for removing a backend from the authentication list. * Action for removing a backend from the authentication list
*
* Redirects to the overview after removal is finished
*/ */
public function removeauthenticationbackendAction() 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(); try {
$authBackend = $this->getParam('auth_backend'); $configForm->remove($authBackend);
if (!isset($configArray[$authBackend])) { } catch (InvalidArgumentException $e) {
Notification::error('Can\'t perform removal: Unknown Authentication Backend Provided'); Notification::error($e->getMessage());
$this->render('authentication/remove'); return;
return; }
}
$form = new ConfirmRemovalForm(); if ($configForm->save()) {
$form->setRequest($this->getRequest()); Notification::success(sprintf(
$form->setRemoveTarget('auth_backend', $authBackend); t('Authentication backend "%s" has been successfully removed'),
$authBackend
if ($form->isSubmittedAndValid()) { ));
unset($configArray[$authBackend]); } else {
if ($this->writeAuthenticationFile($configArray)) { return false;
Notification::success('Authentication Backend "' . $authBackend . '" Removed'); }
$this->redirectNow("config/authentication");
} }
return; ));
} $form->setRedirectUrl('config/authentication');
$form->handleRequest();
$this->view->form = $form; $this->view->form = $form;
$this->view->name = $authBackend; $this->view->tabs->activate('authentication');
$this->render('authentication/remove'); $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->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() public function createresourceAction()
{ {
$this->view->resourceTypes = $this->resourceTypes; $form = new ResourceConfigForm();
$resources = IcingaConfig::app('resources', true); $form->setIniConfig(IcingaConfig::app('resources'));
$form = new ResourceForm(); $form->setRedirectUrl('config/resource');
$form->setRequest($this->_request); $form->handleRequest();
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");
}
}
}
$this->view->messageBox = new AlertMessageBox(true);
$this->view->messageBox->addForm($form);
$this->view->form = $form; $this->view->form = $form;
$this->render('resource/create'); $this->render('resource/create');
} }
/**
* Display a form to edit a existing resource
*/
public function editresourceAction() 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->form = $form;
$this->view->name = $name;
$this->render('resource/modify'); $this->render('resource/modify');
} }
/**
* Display a confirmation form to remove a resource
*/
public function removeresourceAction() 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(); try {
$name = $this->getParam('resource'); $configForm->remove($resource);
if (!isset($resources[$name])) { } catch (InvalidArgumentException $e) {
$this->addSuccessMessage('Can\'t remove: Unknown resource provided'); Notification::error($e->getMessage());
$this->render('resource/remove'); return;
return; }
}
$form = new ConfirmRemovalForm(); if ($configForm->save()) {
$form->setRequest($this->getRequest()); Notification::success(sprintf(t('Resource "%s" has been successfully removed'), $resource));
$form->setRemoveTarget('resource', $name); } else {
return false;
}
}
));
$form->setRedirectUrl('config/resource');
$form->handleRequest();
// Check if selected resource is currently used for authentication // 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) { foreach ($authConfig as $backendName => $config) {
if (array_key_exists('resource', $config) && $config['resource'] === $name) { if (array_key_exists('resource', $config) && $config['resource'] === $resource) {
$this->addErrorMessage( $form->addError(sprintf(
'Warning: The resource "' . $name . '" is currently used for user authentication by "' . $backendName . '". ' . $this->translate(
' Deleting it could eventally make login impossible.' '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
if ($form->isSubmittedAndValid()) { ));
unset($resources[$name]);
if ($this->writeConfigFile($resources, 'resources')) {
$this->addSuccessMessage('Resource "' . $name . '" removed.');
$this->redirectNow('config/resource');
} }
return;
} }
$this->view->name = $name;
$this->view->form = $form; $this->view->form = $form;
$this->render('resource/remove'); $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;
}
}
} }

View File

@ -82,25 +82,29 @@ class DashboardController extends ActionController
)->activate('addurl'); )->activate('addurl');
$form = new AddUrlForm(); $form = new AddUrlForm();
$form->setRequest($this->getRequest()); $request = $this->getRequest();
$form->setAction(Url::fromRequest()->setParams(array())->getAbsoluteUrl()); if ($request->isPost()) {
$this->view->form = $form; 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()) { $configFile = IcingaConfig::app('dashboard/dashboard')->getConfigFile();
$dashboard = $this->getDashboard(); if ($this->writeConfiguration(new Zend_Config($dashboard->toArray()), $configFile)) {
$dashboard->setComponentUrl( $this->redirectNow(Url::fromPath('dashboard', array('pane' => $form->getValue('pane'))));
$form->getValue('pane'), } else {
$form->getValue('component'), $this->render('showConfiguration');
ltrim($form->getValue('url'), '/') return;
); }
$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');
} }
} else {
$form->create()->setDefault('url', htmlspecialchars_decode($request->getParam('url', '')));
} }
$this->view->form = $form;
} }
/** /**
@ -160,9 +164,9 @@ class DashboardController extends ActionController
$writer->write(); $writer->write();
} catch (Exception $e) { } catch (Exception $e) {
Logger::error(new ConfiguationError("Cannot write dashboard to $target", 0, $e)); Logger::error(new ConfiguationError("Cannot write dashboard to $target", 0, $e));
$this->view->iniConfigurationString = $writer->render(); $this->view->configString = $writer->render();
$this->view->exceptionMessage = $e->getMessage(); $this->view->errorMessage = $e->getMessage();
$this->view->file = $target; $this->view->filePath = $target;
return false; return false;
} }

View File

@ -3,11 +3,12 @@
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Web\Controller\BasePreferenceController; use Icinga\Web\Controller\BasePreferenceController;
use Icinga\Web\Widget\Tab;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Form\Preference\GeneralForm; use Icinga\Web\Widget\Tab;
use Icinga\Web\Notification; use Icinga\Application\Config;
use Icinga\Form\PreferenceForm;
use Icinga\Exception\ConfigurationError;
use Icinga\User\Preferences\PreferencesStore;
/** /**
* Application wide preference controller for user preferences * 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() public function indexAction()
{ {
$form = new GeneralForm(); $storeConfig = Config::app()->preferences;
$this->getTabs()->activate('general'); if ($storeConfig === null) {
$form->setConfiguration(IcingaConfig::app()) throw new ConfigurationError(t('You need to configure how to store preferences first.'));
->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()));
}
} }
$user = $this->getRequest()->getUser();
$form = new PreferenceForm();
$form->setPreferences($user->getPreferences());
$form->setStore(PreferencesStore::create($storeConfig, $user));
$form->handleRequest();
$this->view->form = $form; $this->view->form = $form;
$this->getTabs()->activate('general');
} }
} }

View File

@ -13,36 +13,45 @@ use Icinga\Web\Url;
class LoginForm extends Form 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->setName('form_login');
$this->addElement('text', 'username', array( $this->setSubmitLabel(t('Login'));
'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->addElement('password', 'password', array( /**
'label' => t('Password'), * @see Form::createElements()
'placeholder' => t('...and your password'), */
'required' => true public function createElements(array $formData)
)); {
// TODO: We need a place to intercept filled forms before rendering $this->addElement(
if ($this->getRequest()->getPost('username') !== null) { 'text',
$this->getElement('password')->setAttrib('class', 'autofocus'); 'username',
} else { array(
$this->getElement('username')->setAttrib('class', 'autofocus'); 'required' => true,
} 'label' => t('Username'),
$this->setAction((string) $url); 'placeholder' => t('Please enter your username...'),
$this->setSubmitLabel('Login'); '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')
)
);
} }
} }

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -5,123 +5,116 @@
namespace Icinga\Form\Config\Authentication; namespace Icinga\Form\Config\Authentication;
use Exception; use Exception;
use Zend_Config; use Icinga\Web\Form;
use Icinga\Web\Request;
use Icinga\Data\ResourceFactory; use Icinga\Data\ResourceFactory;
use Icinga\Authentication\DbConnection;
use Icinga\Authentication\Backend\DbUserBackend; use Icinga\Authentication\Backend\DbUserBackend;
/** /**
* Form class for adding/modifying database authentication backends * 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) { $this->setName('form_config_authbackend_db');
$res = ResourceFactory::getResourceConfigs('db')->toArray(); }
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 { * @see Form::createElements()
return $this->resources; */
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'); $element = $form->getElement('resource');
$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()
)
);
$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 { try {
$dbUserBackend = new DbUserBackend(ResourceFactory::create( $dbUserBackend = new DbUserBackend(ResourceFactory::create($element->getValue()));
$this->getValue('backend_' . $this->filterName($this->getBackendName()) . '_resource')
));
if ($dbUserBackend->count() < 1) { 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; return false;
} }
} catch (Exception $e) { } 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 false;
} }
return true; return true;
} }
} }

View File

@ -5,166 +5,134 @@
namespace Icinga\Form\Config\Authentication; namespace Icinga\Form\Config\Authentication;
use Exception; use Exception;
use Icinga\Application\Platform;
use Zend_Config;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Web\Request;
use Icinga\Data\ResourceFactory; use Icinga\Data\ResourceFactory;
use Icinga\Authentication\Backend\LdapUserBackend; 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) { $this->setName('form_config_authbackend_ldap');
$res = ResourceFactory::getResourceConfigs('ldap')->toArray();
foreach (array_keys($res) as $key) {
$res[$key] = $key;
}
return $res;
} else {
return $this->resources;
}
} }
/** /**
* 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'); $this->resources = $resources;
$name = $this->filterName($this->getBackendName()); return $this;
$backend = $this->getBackend(); }
/**
* @see Form::createElements()
*/
public function createElements(array $formData)
{
$this->addElement( $this->addElement(
'text', 'text',
'backend_' . $name . '_name', 'name',
array( array(
'required' => true, 'required' => true,
'allowEmpty' => false,
'label' => t('Backend Name'), 'label' => t('Backend Name'),
'helptext' => t('The name of this authentication backend'), 'description' => t('The name of this authentication backend')
'value' => $this->getBackendName()
) )
); );
$this->addElement( $this->addElement(
'select', 'select',
'backend_' . $name . '_resource', 'resource',
array( array(
'required' => true, 'required' => true,
'allowEmpty' => false,
'label' => t('LDAP Resource'), 'label' => t('LDAP Resource'),
'helptext' => t('The resource to use for authenticating with this provider'), 'description' => t('The resource to use for authenticating with this provider'),
'value' => $this->getBackend()->get('resource'), 'multiOptions' => false === empty($this->resources)
'multiOptions' => $this->getResources() ? array_combine($this->resources, $this->resources)
: array()
) )
); );
$this->addElement( $this->addElement(
'text', 'text',
'backend_' . $name . '_user_class', 'user_class',
array( array(
'required' => true, 'required' => true,
'label' => t('LDAP User Object Class'), 'label' => t('LDAP User Object Class'),
'helptext' => t('The object class used for storing users on the ldap server'), 'description' => t('The object class used for storing users on the ldap server'),
'value' => $backend->get('user_class', 'inetOrgPerson') 'value' => 'inetOrgPerson'
) )
); );
$this->addElement( $this->addElement(
'text', '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( array(
'required' => true, 'required' => true,
'label' => t('LDAP User Name Attribute'), 'value' => 'ldap'
'helptext' => t('The attribute name used for storing the user name on the ldap server'),
'value' => $backend->get('user_name_attribute', 'uid')
) )
); );
$this->addElement( return $this;
'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 ldap authentication backend configuration for this form * Validate that the selected resource is a valid ldap authentication backend
* *
* @return array * @see Form::onSuccess()
*
* @see BaseBackendForm::getConfig()
*/ */
public function getConfig() public function onSuccess(Request $request)
{ {
$prefix = 'backend_' . $this->filterName($this->getBackendName()) . '_'; if (false === $this->isValidAuthenticationBackend($this)) {
$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.'));
return false; 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 { try {
$cfg = $this->getConfig(); $ldapUserBackend = new LdapUserBackend(
$backendName = 'backend_' . $this->filterName($this->getBackendName()) . '_name'; ResourceFactory::create($element->getValue()),
$backendConfig = new Zend_Config($cfg[$this->getValue($backendName)]); $form->getElement('user_class')->getValue(),
$backend = ResourceFactory::create($backendConfig->resource); $form->getElement('user_name_attribute')->getValue()
$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->assertAuthenticationPossible();
} catch (Exception $e) {
$element->addError(sprintf(t('Connection validation failed: %s'), $e->getMessage()));
return false; return false;
} }

View File

@ -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;
}
}

View 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());
}
}

View File

@ -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;
}
}

View File

@ -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'
)
);
}
}

View 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;
}
}

View 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'));
}
}

View 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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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());
}
}

View File

@ -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);
}
}

View 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;
}
}

View 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'));
}
}

View File

@ -5,12 +5,8 @@
namespace Icinga\Form\Dashboard; namespace Icinga\Form\Dashboard;
use Icinga\Application\Config as IcingaConfig; use Icinga\Application\Config as IcingaConfig;
use Icinga\Web\Form;
use Icinga\Web\Widget\Dashboard; use Icinga\Web\Widget\Dashboard;
use Zend_Form_Element_Text; use Icinga\Web\Form;
use Zend_Form_Element_Submit;
use Zend_Form_Element_Hidden;
use Zend_Form_Element_Select;
/** /**
* Form to add an url a dashboard pane * Form to add an url a dashboard pane
@ -18,124 +14,103 @@ use Zend_Form_Element_Select;
class AddUrlForm extends Form class AddUrlForm extends Form
{ {
/** /**
* Add a selection box for different panes to the form * Initialize this form
*
* @param Dashboard $dashboard The dashboard to retrieve the panes from
*/ */
private function addPaneSelectionBox(Dashboard $dashboard) public function init()
{ {
$selectPane = new Zend_Form_Element_Select( $this->setName('form_dashboard_addurl');
'pane', $this->setSubmitLabel(t('Add To Dashboard'));
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'));
} }
/** /**
* 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( $this->addElement(
'text', 'text',
'url', 'url',
array( array(
'label' => 'Url', 'required' => true,
'required' => true, 'label' => t('Url'),
'value' => htmlspecialchars_decode($this->getRequest()->getParam('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 $paneSelectionValues = $this->getDashboardPaneSelectionValues();
($this->getRequest()->getPost('create_new_pane', '0') && // or when a new pane should be created (+ button) if (empty($paneSelectionValues) ||
!$this->getRequest()->getPost('use_existing_dashboard', '0')) // and the user didn't click the 'use ((isset($formData['create_new_pane']) && $formData['create_new_pane'] != false) &&
// existing' button (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 { } 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( $this->addElement(
'text', 'text',
'component', 'component',
array( 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();
} }
} }

View File

@ -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();
}
}

View File

@ -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
);
}
}

View 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();
}
}
}

View File

@ -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 #: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:182
msgid "The password to use for authentication" 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 #: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:270
msgid "The password to use for querying the ldap server" msgid "The password to use for querying the ldap server"

View File

@ -4,7 +4,6 @@
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
use Icinga\Util\DateTimeFactory; use Icinga\Util\DateTimeFactory;
use Icinga\Web\Form\Validator\DateTimeValidator;
/** /**
* Helper to format date and time. Utilizes DateTimeFactory to ensure time zone awareness * 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) public function format($timestamp, $format)
{ {
$dt = DateTimeFactory::create(); $dt = DateTimeFactory::create();
if (DateTimeValidator::isUnixTimestamp($timestamp)) { if (DateTimeFactory::isUnixTimestamp($timestamp)) {
$dt->setTimestamp($timestamp); $dt->setTimestamp($timestamp);
} else { } else {
return $timestamp; return $timestamp;

View File

@ -2,18 +2,30 @@
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// {{{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 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 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 * @param array $attribs Attributes for the element tag
* *
* @return string The element XHTML * @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) public function formDateTime($name, $value = null, $attribs = null)
{ {
$info = $this->_getInfo($name, $value, $attribs); $info = $this->_getInfo($name, $value, $attribs);
extract($info); // name, value, attribs, options, listsep, disable extract($info); // name, id, value, attribs, options, listsep, disable
// Is it disabled? /** @var string $id */
/** @var bool $disable */
$disabled = ''; $disabled = '';
if ($disabled) { if ($disable) {
$disabled = ' disabled="disabled"'; $disabled = ' disabled="disabled"';
} }
if ($value instanceof DateTime) {
$jspicker = (isset($attribs['jspicker']) && $attribs['jspicker'] === true) ? true : false; // If value was valid, it's a DateTime object
$value = $this->formatDate($value, $attribs['local']);
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 = '';
} }
$min = '';
// Build the element if (! empty($attribs['min'])) {
$xhtml = '<div class="datetime' . (($jspicker === true) ? ' input-group' : ''). '">'; $min = sprintf(' min="%s"', $this->formatDate($attribs['min'], $attribs['local']));
$xhtml .= '<input type="text" name="' . $name . '"'
. ' id="' . $name . '"'
. $value
. $disabled
. $this->_htmlAttribs($attribs);
if ($jspicker === true) {
$xhtml .= 'data-icinga-component="app/datetime"';
} }
unset($attribs['min']); // Unset min to not render it again in $this->_htmlAttribs($attribs)
$xhtml .= $this->getClosingBracket(); $max = '';
if (! empty($attribs['max'])) {
if ($jspicker === true) { $max = sprintf(' max="%s"', $this->formatDate($attribs['max'], $attribs['local']));
$xhtml .= '<span class="input-group-addon">'
. '<a href="#">'
. '<i class="icinga-icon-reschedule"></i>'
. '</a>'
. '</span>';
} }
unset($attribs['max']); // Unset max to not render it again in $this->_htmlAttribs($attribs)
$xhtml .= '</div>'; $type = $attribs['local'] === true ? 'datetime-local' : 'datetime';
unset($attribs['local']); // Unset local to not render it again in $this->_htmlAttribs($attribs)
return $xhtml; $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;
} }
} }

View File

@ -2,29 +2,79 @@
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// {{{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. * @return string
* @param string $value The default value. */
* @param array $attribs Attributes which should be added to the input tag. 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) public function formNumber($name, $value = null, $attribs = null)
{ {
return '<input type="number"' $info = $this->_getInfo($name, $value, $attribs);
. ' name="' . $this->view->escape($name) . '"' extract($info); // name, id, value, attribs, options, listsep, disable
. ' value="' . $this->view->escape($value) . '"' /** @var string $id */
. ' id="' . $this->view->escape($name) . '"' /** @var bool $disable */
. $this->_htmlAttribs($attribs) $disabled = '';
. $this->getClosingBracket(); 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;
} }
} }

View File

@ -64,6 +64,9 @@ class Zend_View_Helper_Util extends Zend_View_Helper_Abstract
return date('H:i d.m.Y', $timestamp); return date('H:i d.m.Y', $timestamp);
} }
/**
* @deprecated Not used. This is monitoring module stuff.
*/
public static function getHostStateClassName($state) public static function getHostStateClassName($state)
{ {
$class = 'unknown'; $class = 'unknown';
@ -82,6 +85,9 @@ class Zend_View_Helper_Util extends Zend_View_Helper_Abstract
return $class; return $class;
} }
/**
* @deprecated Crap. This is monitoring module stuff.
*/
public static function getHostStateName($state) public static function getHostStateName($state)
{ {
$states = array( $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)); return sprintf('OUT OF BOUNDS (%s)', var_export($state, 1));
} }
/**
* @deprecated Crap. This is monitoring module stuff.
*/
public static function getServiceStateName($state) public static function getServiceStateName($state)
{ {
if ($state === null) { $state = 3; } // really? if ($state === null) { $state = 3; } // really?

View File

@ -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>

View File

@ -1,15 +1,10 @@
<h4> <div class="controls">
<i class="icinga-icon-create"></i> <?= $this->tabs->showOnlyCloseButton() ?>
Create New Authentication Backend </div>
</h4> <h4><?= $this->translate('Create New Authentication Backend'); ?></h4>
<?php if (isset($this->messageBox)): ?>
<?= $this->messageBox->render() ?>
<?php endif ?>
<p> <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> </p>
<?= $form; ?>
<?= $this->form ?>

View File

@ -1,18 +1,5 @@
<h4> <div class="controls">
<i class="icinga-icon-edit"></i> <?= $this->tabs->showOnlyCloseButton() ?>
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> </div>
<?php endif; ?> <h4><?= $this->translate('Edit Backend'); ?></h4>
<?= $form; ?>
<?= $this->form ?>

View File

@ -1,10 +1,5 @@
<h4> <div class="controls">
<i class="icinga-icon-remove"></i> <?= $this->tabs->showOnlyCloseButton() ?>
Remove Backend "<?= $this->escape($this->name); ?>" </div>
</h4> <h4><?= $this->translate('Remove Backend'); ?></h4>
<?= $form; ?>
<?php if (isset($this->messageBox)): ?>
<?= $this->messageBox->render() ?>
<?php endif ?>
<?= $this->form ?>

View File

@ -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>

View File

@ -1,6 +1,6 @@
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $this->tabs ?>
<h1>Installed Modules</h1> <h1><?= $this->translate('Installed Modules') ?></h1>
<?= $this->paginationControl($modules) ?> <?= $this->paginationControl($modules) ?>
</div> </div>
@ -11,9 +11,9 @@
<tr> <tr>
<td> <td>
<?php if ($module->enabled): ?> <?php if ($module->enabled): ?>
<?= $this->icon('success.png', 'Module is enabled') ?> <?= $this->icon('success.png', $this->translate('Module is enabled')) ?>
<?php else: ?> <?php else: ?>
<?= $this->icon('remove.png', 'Module is disabled') ?> <?= $this->icon('remove.png', $this->translate('Module is disabled')) ?>
<? endif ?> <? endif ?>
<a href="<?= $this->url( <a href="<?= $this->url(
'config/module/', 'config/module/',

View File

@ -1,30 +1,32 @@
<div class="controls"> <div class="controls">
<?= $this->tabs ?> <?= $tabs; ?>
</div> </div>
<div class="content" data-base-target="_next"> <div class="content" data-base-target="_next">
<?php <p>
<a href="<?= $this->href('/config/createresource'); ?>">
if (isset($this->messageBox)) { <?= $this->icon('create.png'); ?> <?= $this->translate('Create A New Resource'); ?>
// TODO: Get rid of messageBoxes in favour of notifications </a>
echo $this->messageBox->render(); </p>
} <table class="action">
<thead>
?> <th><?= $this->translate('Resource'); ?></th>
<p><a href="<?= $this->href('/config/createresource') ?>"><?= $this->icon('create.png'); ?> Create A New Resource</a></p> <th style="width: 5em"><?= $this->translate('Remove'); ?></th>
</thead>
<table class="action"> <tbody>
<thead>
<th>Resource</th>
<th style="width: 5em">Remove</th>
</thead>
<tbody>
<?php foreach ($this->resources as $name => $resource): ?> <?php foreach ($this->resources as $name => $resource): ?>
<tr> <tr>
<td><a href="<?= $this->href('config/editresource', array('resource' => $name)) ?>"><?= $this->icon('edit.png') ?> <?= $this->escape($name); ?></td> <td>
<td style="text-align: center"><a href="<?= $this->href('config/removeresource', array('resource' => $name)) ?>"><?= $this->icon('remove.png'); ?></a></td> <a href="<?= $this->href('config/editresource', array('resource' => $name)); ?>">
</tr> <?= $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; ?> <?php endforeach; ?>
</table> </tbody>
</table>
</div> </div>

View File

@ -1,14 +1,6 @@
<h4> <div class="controls">
<i class="icinga-icon-create"></i> <?= $this->tabs->showOnlyCloseButton() ?>
Create New Resource </div>
</h4> <h4><?= $this->translate('Create A New Resource'); ?></h4>
<p><?= $this->translate('Resources are entities that provide data to Icinga Web 2.'); ?></p>
<?php if (isset($this->messageBox)): ?> <?= $form; ?>
<?= $this->messageBox->render() ?>
<?php endif ?>
<p>
Resources are entities that provide data to Icingaweb.
</p>
<?= $this->form ?>

View File

@ -1,18 +1,5 @@
<h4> <div class="controls">
<i class="icinga-icon-edit"></i> <?= $this->tabs->showOnlyCloseButton() ?>
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> </div>
<?php endif ?> <h4><?= $this->translate('Edit Existing Resource'); ?></h4>
<?= $form; ?>
<?= $this->form ?>

View File

@ -1,10 +1,5 @@
<h4> <div class="controls">
<i class="icinga-icon-remove"></i> <?= $this->tabs->showOnlyCloseButton() ?>
Remove Resource "<?= $this->escape($this->name); ?>" </div>
</h4> <h4><?= $this->translate('Remove Existing Resource'); ?></h4>
<?= $form; ?>
<?php if (isset($this->messageBox)): ?>
<?= $this->messageBox->render() ?>
<?php endif ?>
<?= $this->form ?>

View File

@ -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>

View File

@ -11,7 +11,4 @@
<hr /> <hr />
<pre><?= $this->escape($stackTrace) ?></pre> <pre><?= $this->escape($stackTrace) ?></pre>
<?php endif ?> <?php endif ?>
<?php if (isset($this->messageBox)) : ?>
<?= $this->messageBox->render(); ?>
<? endif ?>
</div> </div>

View 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>

View File

@ -1,7 +1,7 @@
<div class="controls"> <div class="controls">
<?= $this->tabs->render($this); ?> <?= $tabs; ?>
</div> </div>
<div class="content"> <div class="content">
<?= $this->form ?> <?= $form; ?>
</div> </div>

View 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>

View File

@ -18,6 +18,10 @@ backend = ldap
resource = internal_ldap resource = internal_ldap
user_class = @ldap_user_objectclass@ user_class = @ldap_user_objectclass@
user_name_attribute = @ldap_attribute_username@ 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_db_authentication]
@internal_auth_disabled@ @internal_auth_disabled@

View File

@ -26,12 +26,12 @@
%define revision 1 %define revision 1
%define configdir %{_sysconfdir}/icingaweb %define configdir %{_sysconfdir}/%{name}
%define sharedir %{_datadir}/icingaweb %define sharedir %{_datadir}/%{name}
%define prefixdir %{_datadir}/icingaweb %define prefixdir %{_datadir}/%{name}
%define logdir %{sharedir}/log
%define usermodparam -a -G %define usermodparam -a -G
%define logdir %{_localstatedir}/log/icingaweb %define logdir %{_localstatedir}/log/%{name}
%define docdir %{sharedir}/log
%if "%{_vendor}" == "suse" %if "%{_vendor}" == "suse"
%define phpname php5 %define phpname php5
@ -172,25 +172,26 @@ install -D -m0644 packages/rpm/etc/httpd/conf.d/icingaweb.conf %{buildroot}/%{ap
# install public, library, modules # install public, library, modules
%{__mkdir} -p %{buildroot}/%{sharedir} %{__mkdir} -p %{buildroot}/%{sharedir}
%{__mkdir} -p %{buildroot}/%{logdir} %{__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}/dashboard
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/icingaweb/modules %{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/modules
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/icingaweb/modules/monitoring %{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring
%{__mkdir} -p %{buildroot}/%{_sysconfdir}/icingaweb/enabledModules %{__mkdir} -p %{buildroot}/%{_sysconfdir}/%{name}/enabledModules
%{__cp} -r application library modules public %{buildroot}/%{sharedir}/ %{__cp} -r application doc library modules public %{buildroot}/%{sharedir}/
## config ## config
# authentication is db only # 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 # 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) # 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/%{name}/modules/monitoring/backends.ini %{buildroot}/%{_sysconfdir}/%{name}/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/instances.ini %{buildroot}/%{_sysconfdir}/%{name}/modules/monitoring/instances.ini
# enable the monitoring module by default # 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 ## config
# install icingacli # install icingacli
@ -228,6 +229,8 @@ fi
%config(noreplace) %attr(-,%{apacheuser},%{apachegroup}) %{configdir} %config(noreplace) %attr(-,%{apacheuser},%{apachegroup}) %{configdir}
# logs # logs
%attr(2775,%{apacheuser},%{apachegroup}) %dir %{logdir} %attr(2775,%{apacheuser},%{apachegroup}) %dir %{logdir}
# shipped docs
%attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/doc
%files -n php-Icinga %files -n php-Icinga
%attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/application %attr(755,%{apacheuser},%{apachegroup}) %{sharedir}/application

View File

@ -4,10 +4,10 @@
namespace Icinga\Application; namespace Icinga\Application;
use ErrorException;
use Exception; use Exception;
use Zend_Config; use Zend_Config;
use Icinga\Application\Modules\Manager as ModuleManager; use Icinga\Application\Modules\Manager as ModuleManager;
use Icinga\Application\Config;
use Icinga\Data\ResourceFactory; use Icinga\Data\ResourceFactory;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
use Icinga\Exception\NotReadableError; use Icinga\Exception\NotReadableError;
@ -348,11 +348,7 @@ abstract class ApplicationBootstrap
Logger::create( Logger::create(
new Zend_Config( new Zend_Config(
array( array(
'enable' => true, 'log' => 'syslog'
'level' => Logger::$ERROR,
'type' => 'syslog',
'facility' => 'LOG_USER',
'application' => 'icingaweb'
) )
) )
); );
@ -383,9 +379,20 @@ abstract class ApplicationBootstrap
*/ */
protected function setupErrorHandling() protected function setupErrorHandling()
{ {
error_reporting(E_ALL | E_NOTICE); error_reporting(E_ALL | E_STRICT);
ini_set('display_startup_errors', 1); ini_set('display_startup_errors', 1);
ini_set('display_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; return $this;
} }

View File

@ -51,10 +51,9 @@ class Cli extends ApplicationBootstrap
Logger::create( Logger::create(
new Zend_Config( new Zend_Config(
array( array(
'enable' => true, 'level' => Logger::INFO,
'level' => Logger::$INFO, 'log' => 'file',
'type' => 'file', 'file' => 'php://stderr'
'target' => 'php://stderr'
) )
) )
); );

View File

@ -7,7 +7,6 @@ namespace Icinga\Application;
use Zend_Config; use Zend_Config;
use Zend_Config_Ini; use Zend_Config_Ini;
use Icinga\Exception\NotReadableError; use Icinga\Exception\NotReadableError;
use Icinga\Exception\ProgrammingError;
/** /**
* Global registry of application and module configuration. * Global registry of application and module configuration.
@ -22,11 +21,11 @@ class Config extends Zend_Config
public static $configDir; 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 * @var string
*/ */
private $configFile; protected $configFile;
/** /**
* Application config instances per file * Application config instances per file
@ -42,30 +41,28 @@ class Config extends Zend_Config
*/ */
protected static $modules = array(); 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 * @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); $config = new static(array(), true);
$filepath = realpath($filename); $filepath = realpath($file);
if ($filepath === false) { if ($filepath === false) {
$this->configFile = $filename; $config->setConfigFile($file);
} elseif (is_readable($filepath)) { } elseif (is_readable($filepath)) {
$this->configFile = $filepath; $config->setConfigFile($filepath);
$this->merge(new Zend_Config_Ini($filepath)); $config->merge(new Zend_Config_Ini($filepath));
} else { } else {
throw new NotReadableError( throw new NotReadableError('Cannot read config file "%s". Permission denied', $filepath);
'Cannot read config file "%s". Permission denied',
$filename
);
} }
return $config;
} }
/** /**
@ -80,7 +77,7 @@ class Config extends Zend_Config
public static function app($configname = 'config', $fromDisk = false) public static function app($configname = 'config', $fromDisk = false)
{ {
if (!isset(self::$app[$configname]) || $fromDisk) { 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]; return self::$app[$configname];
} }
@ -113,7 +110,7 @@ class Config extends Zend_Config
} }
$moduleConfigs = self::$modules[$modulename]; $moduleConfigs = self::$modules[$modulename];
if (!isset($moduleConfigs[$configname]) || $fromDisk) { if (!isset($moduleConfigs[$configname]) || $fromDisk) {
$moduleConfigs[$configname] = new Config( $moduleConfigs[$configname] = Config::fromIni(
self::resolvePath('modules/' . $modulename . '/' . $configname . '.ini') 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() public function getConfigFile()
{ {
return $this->configFile; 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 * Prepend configuration base dir if input is relative
* *

View File

@ -918,10 +918,21 @@ class Module
* Translate a string with the global mt() * Translate a string with the global mt()
* *
* @param $string * @param $string
* @param null $context
*
* @return mixed|string * @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);
} }
} }

View File

@ -278,7 +278,8 @@ class Web extends ApplicationBootstrap
if ($this->user !== null && $this->user->getPreferences() !== null) { if ($this->user !== null && $this->user->getPreferences() !== null) {
$detect = new TimezoneDetect(); $detect = new TimezoneDetect();
$userTimezone = $this->user->getPreferences()->get('app.timezone', $detect->getTimezoneName()); $userTimezone = $this->user->getPreferences()
->getValue('icingaweb', 'timezone', $detect->getTimezoneName());
} }
try { try {
@ -302,7 +303,7 @@ class Web extends ApplicationBootstrap
{ {
parent::setupInternationalization(); parent::setupInternationalization();
if ($this->user !== null && $this->user->getPreferences() !== null 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 { try {
Translator::setupLocale($locale); Translator::setupLocale($locale);

View File

@ -5,23 +5,85 @@
use Icinga\Util\Translator; use Icinga\Util\Translator;
if (extension_loaded('gettext')) { 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 { } else {
function t($messageId)
/**
* (non-PHPDoc)
* @see Translator::translate() For the function documentation.
*/
function t($messageId, $context = null)
{ {
return $messageId; return $messageId;
} }
function mt($domain, $messageId) /**
* (non-PHPDoc)
* @see Translator::translate() For the function documentation.
*/
function mt($domain, $messageId, $context = null)
{ {
return $messageId; 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;
}
} }

View File

@ -52,12 +52,8 @@ class AdmissionLoader
return $permissions; return $permissions;
} }
foreach ($config as $section) { foreach ($config as $section) {
if ($this->match($section, $username, $groups)) { if ($this->match($section, $username, $groups) && isset($section->permissions)) {
foreach ($section as $key => $value) { $permissions += String::trimSplit($section->permissions);
if (strpos($key, 'permission') === 0) {
$permissions = array_merge($permissions, String::trimSplit($value));
}
}
} }
} }
return $permissions; return $permissions;
@ -79,12 +75,12 @@ class AdmissionLoader
} catch (NotReadableError $e) { } catch (NotReadableError $e) {
return $restrictions; return $restrictions;
} }
foreach ($config as $section) { foreach ($config as $name => $section) {
if ($this->match($section, $username, $groups)) { if ($this->match($section, $username, $groups)) {
if (!array_key_exists($section->name, $restrictions)) { if (!array_key_exists($section->name, $restrictions)) {
$restrictions[$section->name] = array(); $restrictions[$section->name] = array();
} }
$restrictions[$section->name][] = $section->restriction; $restrictions[$section->name][$name] = $section->restriction;
} }
} }
return $restrictions; return $restrictions;

View File

@ -4,6 +4,7 @@
namespace Icinga\Authentication\Backend; namespace Icinga\Authentication\Backend;
use Icinga\Logger\Logger;
use Icinga\User; use Icinga\User;
use Icinga\Authentication\UserBackend; use Icinga\Authentication\UserBackend;
use Icinga\Protocol\Ldap\Connection; use Icinga\Protocol\Ldap\Connection;
@ -23,11 +24,14 @@ class LdapUserBackend extends UserBackend
protected $userNameAttribute; protected $userNameAttribute;
public function __construct(Connection $conn, $userClass, $userNameAttribute) protected $groupOptions;
public function __construct(Connection $conn, $userClass, $userNameAttribute, $groupOptions = null)
{ {
$this->conn = $conn; $this->conn = $conn;
$this->userClass = $userClass; $this->userClass = $userClass;
$this->userNameAttribute = $userNameAttribute; $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 * Test whether the given user exists
* *
@ -127,10 +168,15 @@ class LdapUserBackend extends UserBackend
return false; return false;
} }
try { try {
return $this->conn->testCredentials( $userDn = $this->conn->fetchDN($this->createQuery($user->getUsername()));
$this->conn->fetchDN($this->createQuery($user->getUsername())), $authenticated = $this->conn->testCredentials(
$userDn,
$password $password
); );
if ($authenticated) {
$user->setGroups($this->getGroups($userDn));
}
return $authenticated;
} catch (LdapException $e) { } catch (LdapException $e) {
// Error during authentication of this specific user // Error during authentication of this specific user
throw new AuthenticationException( throw new AuthenticationException(
@ -160,4 +206,3 @@ class LdapUserBackend extends UserBackend
); );
} }
} }

View File

@ -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() public function authenticateFromSession()
{ {
$this->user = Session::getSession()->get('user'); $this->user = Session::getSession()->get('user');
if ($this->user !== null && $this->user->isRemoteUser() === true) { if ($this->user !== null && $this->user->isRemoteUser() === true) {
list($originUsername, $field) = $this->user->getRemoteUserInformation(); 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(); $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 * @return bool
*/ */
public function isAuthenticated($ignoreSession = false) public function isAuthenticated($ignoreSession = false)
{ {
if ($this->user === null && !$ignoreSession) { if ($this->user === null && ! $ignoreSession) {
$this->authenticateFromSession(); $this->authenticateFromSession();
} }
return is_object($this->user); return is_object($this->user);
@ -145,25 +147,16 @@ class Manager
/** /**
* Whether an authenticated user has a given permission * 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 * @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) public function hasPermission($permission)
{ {
if (! $this->isAuthenticated()) { if (! $this->isAuthenticated()) {
return false; return false;
} }
foreach ($this->user->getPermissions() as $p) { return $this->user->can($permission);
if ($p === $permission) {
return true;
}
}
return false;
} }
/** /**

View File

@ -93,26 +93,44 @@ abstract class UserBackend implements Countable
$backend = new DbUserBackend($resource); $backend = new DbUserBackend($resource);
break; break;
case 'msldap': 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( $backend = new LdapUserBackend(
$resource, $resource,
$backendConfig->get('user_class', 'user'), $backendConfig->get('user_class', 'user'),
$backendConfig->get('user_name_attribute', 'sAMAccountName') $backendConfig->get('user_name_attribute', 'sAMAccountName'),
$groupOptions
); );
break; break;
case 'ldap': case 'ldap':
if (($userClass = $backendConfig->user_class) === null) { if ($backendConfig->user_class === null) {
throw new ConfigurationError( throw new ConfigurationError(
'Authentication configuration for backend "%s" is missing the user_class directive', 'Authentication configuration for backend "%s" is missing the user_class directive',
$name $name
); );
} }
if (($userNameAttribute = $backendConfig->user_name_attribute) === null) { if ($backendConfig->user_name_attribute === null) {
throw new ConfigurationError( throw new ConfigurationError(
'Authentication configuration for backend "%s" is missing the user_name_attribute directive', 'Authentication configuration for backend "%s" is missing the user_name_attribute directive',
$name $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; break;
default: default:
throw new ConfigurationError( throw new ConfigurationError(

View File

@ -108,6 +108,18 @@ class Params
return $this->standalone; 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() * @see Params::get()
*/ */

View File

@ -59,6 +59,13 @@ class DbQuery extends SimpleQuery
*/ */
protected $count; protected $count;
/**
* GROUP BY clauses
*
* @var string|array
*/
protected $group;
protected function init() protected function init()
{ {
$this->db = $this->ds->getDbAdapter(); $this->db = $this->ds->getDbAdapter();
@ -89,17 +96,21 @@ class DbQuery extends SimpleQuery
public function getSelectQuery() public function getSelectQuery()
{ {
$select = $this->dbSelect(); $select = $this->dbSelect();
// Add order fields to select for postgres distinct queries (#6351) // Add order fields to select for postgres distinct queries (#6351)
if ($this->hasOrder() if ($this->hasOrder()
&& $this->getDatasource()->getDbType() === 'pgsql' && $this->getDatasource()->getDbType() === 'pgsql'
&& $select->getPart(Zend_Db_Select::DISTINCT) === true) { && $select->getPart(Zend_Db_Select::DISTINCT) === true) {
foreach ($this->getOrder() as $fieldAndDirection) { foreach ($this->getOrder() as $fieldAndDirection) {
list($alias, $field) = explode('.', $fieldAndDirection[0]); if (array_search($fieldAndDirection[0], $this->columns) === false) {
$this->columns[$field] = $fieldAndDirection[0]; $this->columns[] = $fieldAndDirection[0];
}
} }
} }
if ($this->group) {
$select->group($this->group);
}
$select->columns($this->columns); $select->columns($this->columns);
$this->applyFilterSql($select); $this->applyFilterSql($select);
@ -117,7 +128,7 @@ class DbQuery extends SimpleQuery
return $select; return $select;
} }
protected function applyFilterSql($query) public function applyFilterSql($query)
{ {
$where = $this->renderFilter($this->filter); $where = $this->renderFilter($this->filter);
if ($where !== '') { if ($where !== '') {
@ -223,7 +234,7 @@ class DbQuery extends SimpleQuery
*/ */
public function isTimestamp($field) public function isTimestamp($field)
{ {
return $this; return false;
} }
public function whereToSql($col, $sign, $expression) public function whereToSql($col, $sign, $expression)
@ -253,6 +264,7 @@ class DbQuery extends SimpleQuery
$this->applyFilterSql($count); $this->applyFilterSql($count);
if ($this->useSubqueryCount) { if ($this->useSubqueryCount) {
$count->columns($this->columns);
$columns = array('cnt' => 'COUNT(*)'); $columns = array('cnt' => 'COUNT(*)');
return $this->db->select()->from($count, $columns); return $this->db->select()->from($count, $columns);
} }
@ -300,4 +312,17 @@ class DbQuery extends SimpleQuery
{ {
return (string) $this->getSelectQuery(); return (string) $this->getSelectQuery();
} }
/**
* Add a GROUP BY clause
*
* @param string|array $group
*
* @return $this
*/
public function group($group)
{
$this->group = $group;
return $this;
}
} }

View File

@ -12,6 +12,8 @@ class FilterExpression extends Filter
public function __construct($column, $sign, $expression) public function __construct($column, $sign, $expression)
{ {
$column = trim($column);
$expression = is_array($expression) ? array_map('trim', $expression) : trim($expression);
$this->column = $column; $this->column = $column;
$this->sign = $sign; $this->sign = $sign;
$this->expression = $expression; $this->expression = $expression;

View File

@ -10,7 +10,6 @@ use Icinga\Util\ConfigAwareFactory;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
use Icinga\Data\Db\DbConnection; use Icinga\Data\Db\DbConnection;
use Icinga\Protocol\Livestatus\Connection as LivestatusConnection; use Icinga\Protocol\Livestatus\Connection as LivestatusConnection;
use Icinga\Protocol\Statusdat\Reader as StatusdatReader;
use Icinga\Protocol\Ldap\Connection as LdapConnection; use Icinga\Protocol\Ldap\Connection as LdapConnection;
use Icinga\Protocol\File\FileReader; use Icinga\Protocol\File\FileReader;
@ -102,7 +101,7 @@ class ResourceFactory implements ConfigAwareFactory
* *
* @param Zend_Config $config The configuration for the created resource. * @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'. * the given resource. The returned class depends on the configuration property 'type'.
* @throws ConfigurationError When an unsupported type is given * @throws ConfigurationError When an unsupported type is given
*/ */
@ -115,9 +114,6 @@ class ResourceFactory implements ConfigAwareFactory
case 'ldap': case 'ldap':
$resource = new LdapConnection($config); $resource = new LdapConnection($config);
break; break;
case 'statusdat':
$resource = new StatusdatReader($config);
break;
case 'livestatus': case 'livestatus':
$resource = new LivestatusConnection($config->socket); $resource = new LivestatusConnection($config->socket);
break; break;
@ -137,7 +133,7 @@ class ResourceFactory implements ConfigAwareFactory
* Create a resource from name * Create a resource from name
* *
* @param string $resourceName * @param string $resourceName
* @return DbConnection|LdapConnection|LivestatusConnection|StatusdatReader * @return DbConnection|LdapConnection|LivestatusConnection
*/ */
public static function create($resourceName) public static function create($resourceName)
{ {

View 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 {}

View 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
{
}

View File

@ -7,58 +7,109 @@ namespace Icinga\Logger;
use Exception; use Exception;
use Zend_Config; use Zend_Config;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
use Icinga\Logger\Writer\FileWriter;
use Icinga\Logger\Writer\SyslogWriter;
/** /**
* Singleton logger * Logger
*/ */
class 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 * This logger's instance
* *
* @var Logger * @var static
*/ */
protected static $instance; protected static $instance;
/** /**
* The log writer to use * Log writer
* *
* @var \Icinga\Logger\LogWriter * @var \Icinga\Logger\LogWriter
*/ */
protected $writer; protected $writer;
/** /**
* The configured type * Maximum level to emit
*
* @string Type (syslog, file)
*/
protected $type = 'none';
/**
* The maximum severity to emit
* *
* @var int * @var int
*/ */
protected $verbosity; protected $level;
/**
* The supported severities
*/
public static $ERROR = 0;
public static $WARNING = 1;
public static $INFO = 2;
public static $DEBUG = 3;
/** /**
* Create a new logger object * 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) 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); $this->writer = $this->createWriter($config);
} }
} }
@ -67,14 +118,17 @@ class Logger
* Create a new logger object * Create a new logger object
* *
* @param Zend_Config $config * @param Zend_Config $config
*
* @return static
*/ */
public static function create(Zend_Config $config) public static function create(Zend_Config $config)
{ {
static::$instance = new static($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 * @param Zend_Config $config The configuration to initialize the writer with
* *
@ -83,28 +137,26 @@ class Logger
*/ */
protected function createWriter(Zend_Config $config) protected function createWriter(Zend_Config $config)
{ {
$class = 'Icinga\\Logger\\Writer\\' . ucfirst(strtolower($config->type)) . 'Writer'; $class = 'Icinga\\Logger\\Writer\\' . ucfirst(strtolower($config->log)) . 'Writer';
if (!class_exists($class)) { if (! class_exists($class)) {
throw new ConfigurationError( throw new ConfigurationError(
'Cannot find log writer of type "%s"', 'Cannot find log writer of type "%s"',
$config->type $config->log
); );
} }
$this->type = $config->type;
return new $class($config); return new $class($config);
} }
/** /**
* Write a message to the log * Log a message
* *
* @param string $message The message to write * @param int $level The logging level
* @param int $severity The severity to use * @param string $message The log message
*/ */
public function log($message, $severity) public function log($level, $message)
{ {
if ($this->writer !== null && $this->verbosity >= $severity) { if ($this->writer !== null && $this->level >= $level) {
$this->writer->log($severity, $message); $this->writer->log($level, $message);
} }
} }
@ -162,7 +214,7 @@ class Logger
public static function error() public static function error()
{ {
if (static::$instance !== null && func_num_args() > 0) { 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() public static function warning()
{ {
if (static::$instance !== null && func_num_args() > 0) { 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() public static function info()
{ {
if (static::$instance !== null && func_num_args() > 0) { 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() public static function debug()
{ {
if (static::$instance !== null && func_num_args() > 0) { 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; return $this->writer;
} }
/**
* Is the logger writing to Syslog?
*
* @return bool
*/
public static function writesToSyslog() 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() public static function writesToFile()
{ {
return static::$instance && static::$instance->type === 'file'; return static::$instance && static::$instance instanceof FileWriter;
} }
/** /**
* Get this' instance * Get this' instance
* *
* @return Logger * @return static
*/ */
public static function getInstance() public static function getInstance()
{ {

View File

@ -5,38 +5,43 @@
namespace Icinga\Logger\Writer; namespace Icinga\Logger\Writer;
use Exception; use Exception;
use Icinga\Exception\IcingaException;
use Zend_Config; use Zend_Config;
use Icinga\Util\File; use Icinga\Exception\ConfigurationError;
use Icinga\Logger\Logger; use Icinga\Logger\Logger;
use Icinga\Logger\LogWriter; 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 class FileWriter extends LogWriter
{ {
/** /**
* The path to the file * Path to the file
* *
* @var string * @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) 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( throw new ConfigurationError(
'Log path "%s" does not exist', 'Log path "%s" does not exist',
dirname($this->path) dirname($this->file)
); );
} }
@ -45,70 +50,32 @@ class FileWriter extends LogWriter
} catch (Exception $e) { } catch (Exception $e) {
throw new ConfigurationError( throw new ConfigurationError(
'Cannot write to log file "%s" (%s)', 'Cannot write to log file "%s" (%s)',
$this->path, $this->file,
$e->getMessage() $e->getMessage()
); );
} }
} }
/** /**
* Log a message with the given severity * Log a message
* *
* @param int $severity The severity to use * @param int $level The logging level
* @param string $message The message to log * @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 * @param string $message
*
* @return string The string representation of the severity
*
* @throws IcingaException In case the given severity is unknown
*/ */
protected function getSeverityString($severity) protected function write($message)
{ {
switch ($severity) { $file = new File($this->file, 'a');
case Logger::$ERROR: $file->fwrite($message);
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->fflush(); $file->fflush();
} }
/**
* @return string
*/
public function getPath()
{
return $this->path;
}
} }

View File

@ -4,27 +4,24 @@
namespace Icinga\Logger\Writer; namespace Icinga\Logger\Writer;
use Exception;
use Zend_Config; use Zend_Config;
use Icinga\Logger\Logger; use Icinga\Logger\Logger;
use Icinga\Logger\LogWriter; 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 class SyslogWriter extends LogWriter
{ {
/** /**
* The facility where to write messages to * Syslog facility
* *
* @var string * @var int
*/ */
protected $facility; protected $facility;
/** /**
* The prefix to prepend to each message * Prefix to prepend to each message
* *
* @var string * @var string
*/ */
@ -35,79 +32,42 @@ class SyslogWriter extends LogWriter
* *
* @var array * @var array
*/ */
protected $facilities = array( public static $facilities = array(
'LOG_USER' => LOG_USER '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) public function __construct(Zend_Config $config)
{ {
if (!array_key_exists($config->facility, $this->facilities)) { $this->ident = $config->get('application', 'icingaweb');
throw new ConfigurationError( $this->facility = static::$facilities['user'];
'Cannot create syslog writer with unknown facility "%s"',
$config->facility
);
}
$this->ident = $config->application;
$this->facility = $this->facilities[$config->facility];
} }
/** /**
* Log a message with the given severity * Log a message
* *
* @param int $severity The severity to use * @param int $level The logging level
* @param string $message The message to log * @param string $message The log message
*
* @throws Exception In case the given severity cannot be mapped to a valid syslog priority
*/ */
public function log($severity, $message) public function log($level, $message)
{ {
$priorities = array( openlog($this->ident, LOG_PID, $this->facility);
Logger::$ERROR => LOG_ERR, syslog(static::$severityMap[$level], $message);
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();
} }
} }

View File

@ -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)
);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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
{
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -4,7 +4,7 @@
namespace Icinga\Protocol\File; namespace Icinga\Protocol\File;
use FilterIterator; use Icinga\Util\EnumeratingFilterIterator;
use Icinga\Util\File; 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 * 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 * A PCRE string with the fields to extract from the file's lines as named subpatterns

View File

@ -6,7 +6,6 @@ namespace Icinga\Protocol\File;
use Icinga\Data\Selectable; use Icinga\Data\Selectable;
use Countable; use Countable;
use Icinga\Util\Enumerate;
use Zend_Config; use Zend_Config;
/** /**
@ -53,9 +52,7 @@ class FileReader implements Selectable, Countable
*/ */
public function iterate() public function iterate()
{ {
return new Enumerate( return new FileIterator($this->filename, $this->fields);
new FileIterator($this->filename, $this->fields)
);
} }
/** /**

View File

@ -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
{
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 '';
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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 &gt;= 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 &gt;= 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 &gt;= 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 &gt;= 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 &gt;= 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
}
}

View File

@ -25,20 +25,16 @@ namespace Icinga\Test {
use RuntimeException; use RuntimeException;
use Mockery; use Mockery;
use Zend_Config; use Zend_Config;
use Zend_Controller_Request_Abstract;
use Zend_Controller_Request_HttpTestCase;
use PHPUnit_Framework_TestCase; use PHPUnit_Framework_TestCase;
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
use Icinga\Util\DateTimeFactory; use Icinga\Util\DateTimeFactory;
use Icinga\Data\ResourceFactory; use Icinga\Data\ResourceFactory;
use Icinga\Data\Db\DbConnection; use Icinga\Data\Db\DbConnection;
use Icinga\User\Preferences;
use Icinga\Web\Form;
/** /**
* Class BaseTestCase * Class BaseTestCase
*/ */
class BaseTestCase extends PHPUnit_Framework_TestCase implements DbTest, FormTest class BaseTestCase extends PHPUnit_Framework_TestCase implements DbTest
{ {
/** /**
* Path to application/ * Path to application/
@ -82,13 +78,6 @@ namespace Icinga\Test {
*/ */
public static $moduleDir; public static $moduleDir;
/**
* Store request for form tests
*
* @var Zend_Controller_Request_HttpTestCase
*/
private $request;
/** /**
* Resource configuration for different database types * Resource configuration for different database types
* *
@ -151,28 +140,54 @@ namespace Icinga\Test {
public function setUp() public function setUp()
{ {
parent::setUp(); parent::setUp();
$this->setupIcingaMock();
$requestMock = Mockery::mock('Icinga\Web\Request');
$requestMock->shouldReceive('getPathInfo')->andReturn('')
->shouldReceive('getBaseUrl')->andReturn('/')
->shouldReceive('getQuery')->andReturn(array());
$this->setupIcingaMock($requestMock);
} }
/** /**
* Setup mock object for the application's bootstrap * Setup mock object for the application's bootstrap
* *
* @param Zend_Controller_Request_Abstract $request The request to be returned by * @return Mockery\Mock
* Icinga::app()->getFrontController()->getRequest()
*/ */
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 = Mockery::mock('Icinga\Application\ApplicationBootstrap')->shouldDeferMissing();
$bootstrapMock->shouldReceive('getFrontController->getRequest')->andReturnUsing( $bootstrapMock->shouldReceive('getFrontController')->andReturn($bootstrapMock)
function () use ($request) { return $request; } ->shouldReceive('getApplicationDir')->andReturn(self::$appDir)
)->shouldReceive('getApplicationDir')->andReturn(self::$appDir); ->shouldReceive('getRequest')->andReturn($requestMock)
->shouldReceive('getResponse')->andReturn($responseMock);
Icinga::setApp($bootstrapMock, true); 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 . ';'); $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(); BaseTestCase::setupTimezone();

View File

@ -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());
}

View File

@ -7,7 +7,6 @@ namespace Icinga;
use DateTimeZone; use DateTimeZone;
use InvalidArgumentException; use InvalidArgumentException;
use Icinga\User\Preferences; use Icinga\User\Preferences;
use Icinga\User\Message;
/** /**
* This class represents an authorized user * This class represents an authorized user
@ -98,13 +97,6 @@ class User
*/ */
protected $preferences; protected $preferences;
/**
* Queued notifications for this user.
*
* @var array()
*/
protected $messages;
/** /**
* Creates a user object given the provided information * 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() 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) 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); 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 * Set additional remote user information
* *
@ -442,6 +408,33 @@ class User
*/ */
public function isRemoteUser() 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;
} }
} }

View File

@ -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;
}
}

View File

@ -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 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)) { if (array_key_exists($name, $this->preferences)) {
return $this->preferences[$name]; 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; return $default;
} }

View File

@ -76,4 +76,18 @@ class DateTimeFactory implements ConfigAwareFactory
{ {
return new DateTime($time, $timeZone !== null ? $timeZone : self::$timeZone); 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