mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-04-08 17:15:08 +02:00
parent
5b14d8fed3
commit
2d86e6ba3b
@ -12,7 +12,7 @@ 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\ResourceForm;
|
||||
use Icinga\Form\Config\ResourceConfigForm;
|
||||
use Icinga\Form\ConfirmRemovalForm;
|
||||
use Icinga\Config\PreservingIniWriter;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
@ -210,14 +210,12 @@ class ConfigController extends BaseConfigController
|
||||
}
|
||||
|
||||
/**
|
||||
* Display all available resources and a link to create a new one
|
||||
* Display all available resources and a link to create a new one and to remove existing ones
|
||||
*/
|
||||
public function resourceAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$this->view->tabs->activate('resources');
|
||||
|
||||
$this->view->resources = IcingaConfig::app('resources', true)->toArray();
|
||||
$this->view->tabs->activate('resources');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -225,26 +223,12 @@ class ConfigController extends BaseConfigController
|
||||
*/
|
||||
public function createresourceAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
|
||||
$form = new ResourceForm();
|
||||
$request = $this->getRequest();
|
||||
if ($request->isPost() && $form->isValid($request->getPost())) {
|
||||
list($name, $config) = $form->getResourceConfig();
|
||||
$resources = IcingaConfig::app('resources')->toArray();
|
||||
if (array_key_exists($name, $resources)) {
|
||||
$this->addErrorMessage(sprintf($this->translate('Resource name "%s" already in use.'), $name));
|
||||
} else {
|
||||
$resources[$name] = $config;
|
||||
if ($this->writeConfigFile($resources, 'resources')) {
|
||||
$this->addSuccessMessage(sprintf($this->translate('Resource "%s" successfully created.'), $name));
|
||||
$this->redirectNow('config/resource');
|
||||
}
|
||||
}
|
||||
}
|
||||
$form = new ResourceConfigForm();
|
||||
$form->setConfig(IcingaConfig::app('resources'));
|
||||
$form->setRedirectUrl('config/resource');
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->messageBox->addForm($form);
|
||||
$this->render('resource/create');
|
||||
}
|
||||
|
||||
@ -253,39 +237,12 @@ class ConfigController extends BaseConfigController
|
||||
*/
|
||||
public function editresourceAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
|
||||
// Fetch the resource to be edited
|
||||
$resources = IcingaConfig::app('resources')->toArray();
|
||||
$name = $this->getParam('resource');
|
||||
if (false === array_key_exists($name, $resources)) {
|
||||
$this->addErrorMessage(sprintf($this->translate('Cannot edit "%s". Resource not found.'), $name));
|
||||
$this->redirectNow('config/configurationerror');
|
||||
}
|
||||
|
||||
$form = new ResourceForm();
|
||||
$request = $this->getRequest();
|
||||
if ($request->isPost()) {
|
||||
if ($form->isValid($request->getPost())) {
|
||||
list($newName, $config) = $form->getResourceConfig();
|
||||
|
||||
if ($newName !== $name) {
|
||||
// Resource name has changed
|
||||
unset($resources[$name]); // We can safely use unset as all values are part of the form
|
||||
}
|
||||
|
||||
$resources[$newName] = $config;
|
||||
if ($this->writeConfigFile($resources, 'resources')) {
|
||||
$this->addSuccessMessage(sprintf($this->translate('Resource "%s" successfully edited.'), $name));
|
||||
$this->redirectNow('config/resource');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$form->setResourceConfig($name, $resources[$name]);
|
||||
}
|
||||
$form = new ResourceConfigForm();
|
||||
$form->setConfig(IcingaConfig::app('resources'));
|
||||
$form->setRedirectUrl('config/resource');
|
||||
$form->handleRequest();
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->messageBox->addForm($form);
|
||||
$this->render('resource/modify');
|
||||
}
|
||||
|
||||
@ -294,45 +251,46 @@ class ConfigController extends BaseConfigController
|
||||
*/
|
||||
public function removeresourceAction()
|
||||
{
|
||||
$this->view->messageBox = new AlertMessageBox(true);
|
||||
$form = new ConfirmRemovalForm(array(
|
||||
'onSuccess' => function ($request) {
|
||||
$configForm = new ResourceConfigForm();
|
||||
$configForm->setConfig(IcingaConfig::app('resources'));
|
||||
$resource = $request->getQuery('resource');
|
||||
|
||||
// Fetch the resource to be removed
|
||||
$resources = IcingaConfig::app('resources')->toArray();
|
||||
$name = $this->getParam('resource');
|
||||
if (false === array_key_exists($name, $resources)) {
|
||||
$this->addErrorMessage(sprintf($this->translate('Cannot remove "%s". Resource not found.'), $name));
|
||||
$this->redirectNow('config/configurationerror');
|
||||
}
|
||||
try {
|
||||
$configForm->remove($resource);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Notification::error($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if ($configForm->save()) {
|
||||
Notification::success(sprintf(t('Resource "%s" has been successfully removed'), $resource));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
));
|
||||
$form->setRedirectUrl('config/resource');
|
||||
$form->handleRequest();
|
||||
|
||||
// Check if selected resource is currently used for authentication
|
||||
$resource = $this->getRequest()->getQuery('resource');
|
||||
$authConfig = IcingaConfig::app('authentication')->toArray();
|
||||
foreach ($authConfig as $backendName => $config) {
|
||||
if (array_key_exists('resource', $config) && $config['resource'] === $name) {
|
||||
$this->addWarningMessage(
|
||||
sprintf(
|
||||
$this->translate(
|
||||
'The resource "%s" is currently in use by the authentication backend "%s". ' .
|
||||
'Removing the resource can result in noone being able to log in any longer.'
|
||||
),
|
||||
$name,
|
||||
$backendName
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$form = new ConfirmRemovalForm();
|
||||
$request = $this->getRequest();
|
||||
if ($request->isPost() && $form->isValid($request->getPost())) {
|
||||
unset($resources[$name]);
|
||||
if ($this->writeConfigFile($resources, 'resources')) {
|
||||
$this->addSuccessMessage(sprintf($this->translate('Resource "%s" successfully removed.'), $name));
|
||||
$this->redirectNow('config/resource');
|
||||
if (array_key_exists('resource', $config) && $config['resource'] === $resource) {
|
||||
$form->addError(sprintf(
|
||||
$this->translate(
|
||||
'The resource "%s" is currently in use by the authentication backend "%s". ' .
|
||||
'Removing the resource can result in noone being able to log in any longer.'
|
||||
),
|
||||
$resource,
|
||||
$backendName
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$this->view->form = $form;
|
||||
$this->view->messageBox->addForm($form);
|
||||
$this->render('resource/remove');
|
||||
}
|
||||
|
||||
|
136
application/forms/Config/Resource/DbResourceForm.php
Normal file
136
application/forms/Config/Resource/DbResourceForm.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?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\Web\Form\Decorator\HelpText;
|
||||
use Icinga\Web\Form\Decorator\ElementWrapper;
|
||||
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)
|
||||
{
|
||||
return array(
|
||||
$this->createElement(
|
||||
'select',
|
||||
'db',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Type'),
|
||||
'helptext' => t('The type of SQL database'),
|
||||
'multiOptions' => array(
|
||||
'mysql' => 'MySQL',
|
||||
'pgsql' => 'PostgreSQL'
|
||||
//'oracle' => 'Oracle'
|
||||
)
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'host',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Host'),
|
||||
'helptext' => t('The hostname of the database'),
|
||||
'value' => 'localhost'
|
||||
)
|
||||
),
|
||||
new Number(
|
||||
array(
|
||||
'required' => true,
|
||||
'name' => 'port',
|
||||
'label' => t('Port'),
|
||||
'helptext' => t('The port to use'),
|
||||
'value' => 3306,
|
||||
'decorators' => array( // The order is important!
|
||||
'ViewHelper',
|
||||
'Errors',
|
||||
new ElementWrapper(),
|
||||
new HelpText()
|
||||
)
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'dbname',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Name'),
|
||||
'helptext' => t('The name of the database to use')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'username',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Username'),
|
||||
'helptext' => t('The user name to use for authentication')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'password',
|
||||
'password',
|
||||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Password'),
|
||||
'helptext' => t('The password to use for authentication')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the current configuration points to a valid resource
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
if (false === $this->isValidResource($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the resource configuration by trying to connect with it
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public function isValidResource(Form $form)
|
||||
{
|
||||
try {
|
||||
$resource = ResourceFactory::createResource(new Zend_Config($form->getValues()));
|
||||
$resource->getConnection()->getConnection();
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
50
application/forms/Config/Resource/FileResourceForm.php
Normal file
50
application/forms/Config/Resource/FileResourceForm.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\Resource;
|
||||
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Form\Validator\ReadablePathValidator;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying file resources
|
||||
*/
|
||||
class FileResourceForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource_file');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
return array(
|
||||
$this->createElement(
|
||||
'text',
|
||||
'filename',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'helptext' => t('The filename to fetch information from'),
|
||||
'validators' => array(new ReadablePathValidator())
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'fields',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Pattern'),
|
||||
'helptext' => t('The regular expression by which to identify columns')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
122
application/forms/Config/Resource/LdapResourceForm.php
Normal file
122
application/forms/Config/Resource/LdapResourceForm.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?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\Web\Form\Decorator\HelpText;
|
||||
use Icinga\Web\Form\Decorator\ElementWrapper;
|
||||
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)
|
||||
{
|
||||
return array(
|
||||
$this->createElement(
|
||||
'text',
|
||||
'hostname',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Host'),
|
||||
'helptext' => t('The hostname or address of the LDAP server to use for authentication'),
|
||||
'value' => 'localhost'
|
||||
)
|
||||
),
|
||||
new Number(
|
||||
array(
|
||||
'required' => true,
|
||||
'name' => 'port',
|
||||
'label' => t('Port'),
|
||||
'helptext' => t('The port of the LDAP server to use for authentication'),
|
||||
'value' => 389,
|
||||
'decorators' => array( // The order is important!
|
||||
'ViewHelper',
|
||||
'Errors',
|
||||
new ElementWrapper(),
|
||||
new HelpText()
|
||||
)
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'root_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Root DN'),
|
||||
'helptext' => t('The path where users can be found on the ldap server')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'bind_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Bind DN'),
|
||||
'helptext' => t('The user dn to use for querying the ldap server')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'password',
|
||||
'bind_pw',
|
||||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Bind Password'),
|
||||
'helptext' => t('The password to use for querying the ldap server')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the current configuration points to a valid resource
|
||||
*
|
||||
* @see Form::onSuccess()
|
||||
*/
|
||||
public function onSuccess(Request $request)
|
||||
{
|
||||
if (false === $this->isValidResource($this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the resource configuration by trying to connect with it
|
||||
*
|
||||
* @param Form $form The form to fetch the configuration values from
|
||||
*
|
||||
* @return bool Whether validation succeeded or not
|
||||
*/
|
||||
public function isValidResource(Form $form)
|
||||
{
|
||||
try {
|
||||
$resource = ResourceFactory::createResource(new Zend_Config($form->getValues()));
|
||||
$resource->connect();
|
||||
} catch (Exception $e) {
|
||||
$form->addError(t('Connectivity validation failed, connection to the given resource not possible.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
77
application/forms/Config/Resource/LivestatusResourceForm.php
Normal file
77
application/forms/Config/Resource/LivestatusResourceForm.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\Resource;
|
||||
|
||||
use Exception;
|
||||
use Zend_Config;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying livestatus resources
|
||||
*/
|
||||
class LivestatusResourceForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource_livestatus');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
return array(
|
||||
$this->createElement(
|
||||
'text',
|
||||
'socket',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Socket'),
|
||||
'helptext' => t('The path to your livestatus socket used for querying monitoring data'),
|
||||
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/rw/livestatus')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
54
application/forms/Config/Resource/StatusdatResourceForm.php
Normal file
54
application/forms/Config/Resource/StatusdatResourceForm.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config\Resource;
|
||||
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Web\Form\Validator\ReadablePathValidator;
|
||||
|
||||
/**
|
||||
* Form class for adding/modifying statusdat resources
|
||||
*/
|
||||
class StatusdatResourceForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource_statusdat');
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElements()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
return array(
|
||||
$this->createElement(
|
||||
'text',
|
||||
'status_file',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'helptext' => t('Location of your icinga status.dat file'),
|
||||
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/status.dat'),
|
||||
'validators' => array(new ReadablePathValidator())
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'object_file',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'helptext' => t('Location of your icinga objects.cache file'),
|
||||
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/objects.cache'),
|
||||
'validators' => array(new ReadablePathValidator())
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
258
application/forms/Config/ResourceConfigForm.php
Normal file
258
application/forms/Config/ResourceConfigForm.php
Normal file
@ -0,0 +1,258 @@
|
||||
<?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\Form\Config\Resource\StatusdatResourceForm;
|
||||
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 === 'statusdat') {
|
||||
return new StatusdatResourceForm();
|
||||
} 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'),
|
||||
'helptext' => 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'),
|
||||
'statusdat' => 'Status.dat',
|
||||
'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');
|
||||
}
|
||||
|
||||
$elements = array(
|
||||
$this->createElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'helptext' => t('The unique name of this resource')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'select',
|
||||
'type',
|
||||
array(
|
||||
'required' => true,
|
||||
'autosubmit' => true,
|
||||
'label' => t('Resource Type'),
|
||||
'helptext' => 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
|
||||
$elements[] = $this->getForceCreationCheckbox();
|
||||
}
|
||||
|
||||
return array_merge($elements, $this->getResourceForm($resourceType)->createElements($formData));
|
||||
}
|
||||
}
|
@ -1,444 +0,0 @@
|
||||
<?php
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
// {{{ICINGA_LICENSE_HEADER}}}
|
||||
|
||||
namespace Icinga\Form\Config;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Application\Platform;
|
||||
use Zend_Config;
|
||||
use Icinga\Web\Form;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Data\ResourceFactory;
|
||||
use Icinga\Web\Form\Element\Number;
|
||||
use Icinga\Web\Form\Decorator\HelpText;
|
||||
use Icinga\Web\Form\Decorator\ElementWrapper;
|
||||
|
||||
class ResourceForm extends Form
|
||||
{
|
||||
/**
|
||||
* Initialize this form
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->setName('form_config_resource');
|
||||
$this->setSubmitLabel(t('Save Changes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Form::createElemeents()
|
||||
*/
|
||||
public function createElements(array $formData)
|
||||
{
|
||||
$elements = array();
|
||||
$elements[] = $this->createElement(
|
||||
'text',
|
||||
'name',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Resource Name'),
|
||||
'helptext' => t('The unique name of this resource')
|
||||
)
|
||||
);
|
||||
$elements[] = $this->createElement(
|
||||
'select',
|
||||
'type',
|
||||
array(
|
||||
'required' => true,
|
||||
'class' => 'autosubmit',
|
||||
'label' => t('Resource Type'),
|
||||
'helptext' => t('The type of resource'),
|
||||
'multiOptions' => array(
|
||||
'db' => t('SQL Database'),
|
||||
'ldap' => 'LDAP',
|
||||
'statusdat' => 'Status.dat',
|
||||
'livestatus' => 'Livestatus',
|
||||
'file' => t('File')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (isset($formData['force_creation']) && $formData['force_creation']) {
|
||||
// In case the resource name already exists and the checkbox was displayed before
|
||||
$elements[] = $this->getForceCreationCheckbox();
|
||||
}
|
||||
|
||||
if (false === isset($formData['type']) || $formData['type'] === 'db') {
|
||||
return array_merge($elements, $this->getDbElements());
|
||||
} elseif ($formData['type'] === 'statusdat') {
|
||||
return array_merge($elements, $this->getStatusdatElements());
|
||||
} elseif ($formData['type'] === 'livestatus') {
|
||||
return array_merge($elements, $this->getLivestatusElements());
|
||||
} elseif ($formData['type'] === 'ldap') {
|
||||
return array_merge($elements, $this->getLdapElements());
|
||||
} elseif ($formData['type'] === 'file') {
|
||||
return array_merge($elements, $this->getFileElements());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the given values are complete/valid and check whether it is possible to connect to the resource
|
||||
*
|
||||
* If connection validation fails, a checkbox is prepended to the form to allow users to skip it.
|
||||
*
|
||||
* @param array $data The data to validate
|
||||
*
|
||||
* @return bool Whether the validation succeeded or not
|
||||
*/
|
||||
public function isValid($data)
|
||||
{
|
||||
if (false === parent::isValid($data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
(false === isset($data['force_creation']) || false == $data['force_creation'])
|
||||
&& false === $this->isValidResource()
|
||||
) {
|
||||
$this->addElement($this->getForceCreationCheckbox());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether a connection can be established with the current resource configuration values
|
||||
*
|
||||
* @return bool Whether the connection validation was successful or not
|
||||
*/
|
||||
public function isValidResource()
|
||||
{
|
||||
list($name, $config) = $this->getResourceConfig();
|
||||
|
||||
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' && false === 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' && false === 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(new Zend_Config($config));
|
||||
$resource->getConnection()->getConnection();
|
||||
break;
|
||||
case 'statusdat':
|
||||
if (
|
||||
false === file_exists($config['object_file'])
|
||||
|| false === file_exists($config['status_file'])
|
||||
) {
|
||||
$this->addErrorMessage(
|
||||
t('Connectivity validation failed. At least one of the provided files does not exist.')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'livestatus':
|
||||
$resource = ResourceFactory::createResource(new Zend_Config($config));
|
||||
$resource->connect()->disconnect();
|
||||
break;
|
||||
case 'ldap':
|
||||
$resource = ResourceFactory::createResource(new Zend_Config($config));
|
||||
$resource->connect();
|
||||
break;
|
||||
case 'file':
|
||||
if (false === 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resource configuration values and its name
|
||||
*
|
||||
* The first value is the name and the second one the values as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getResourceConfig()
|
||||
{
|
||||
$values = $this->getValues();
|
||||
$name = $values['name'];
|
||||
unset($values['name']);
|
||||
return array($name, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the form with the given configuration values
|
||||
*
|
||||
* @param string $name The name of the resource
|
||||
* @param array $config The configuration values
|
||||
*/
|
||||
public function setResourceConfig($name, array $config)
|
||||
{
|
||||
$config['name'] = $name;
|
||||
$this->populate($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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'),
|
||||
'helptext' => t('Check this box to enforce changes without connectivity validation')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all required elements to define a resource of type "db"
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getDbElements()
|
||||
{
|
||||
return array(
|
||||
$this->createElement(
|
||||
'select',
|
||||
'db',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Type'),
|
||||
'helptext' => t('The type of SQL database'),
|
||||
'multiOptions' => array(
|
||||
'mysql' => 'MySQL',
|
||||
'pgsql' => 'PostgreSQL'
|
||||
//'oracle' => 'Oracle'
|
||||
)
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'host',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Host'),
|
||||
'helptext' => t('The hostname of the database'),
|
||||
'value' => 'localhost'
|
||||
)
|
||||
),
|
||||
new Number(
|
||||
array(
|
||||
'required' => true,
|
||||
'name' => 'port',
|
||||
'label' => t('Port'),
|
||||
'helptext' => t('The port to use'),
|
||||
'value' => 3306,
|
||||
'decorators' => array( // The order is important!
|
||||
'ViewHelper',
|
||||
'Errors',
|
||||
new ElementWrapper(),
|
||||
new HelpText()
|
||||
)
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'dbname',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Database Name'),
|
||||
'helptext' => t('The name of the database to use')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'username',
|
||||
array (
|
||||
'required' => true,
|
||||
'label' => t('Username'),
|
||||
'helptext' => t('The user name to use for authentication')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'password',
|
||||
'password',
|
||||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Password'),
|
||||
'helptext' => t('The password to use for authentication')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all required elements to define a resource of type "statusdat"
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getStatusdatElements()
|
||||
{
|
||||
return array(
|
||||
$this->createElement(
|
||||
'text',
|
||||
'status_file',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'helptext' => t('Location of your icinga status.dat file'),
|
||||
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/status.dat')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'object_file',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'helptext' => t('Location of your icinga objects.cache file'),
|
||||
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/objects.cache')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all required elements to define a resource of type "livestatus"
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getLivestatusElements()
|
||||
{
|
||||
return array(
|
||||
$this->createElement(
|
||||
'text',
|
||||
'socket',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Socket'),
|
||||
'helptext' => t('The path to your livestatus socket used for querying monitoring data'),
|
||||
'value' => realpath(Icinga::app()->getApplicationDir() . '/../var/rw/livestatus')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all required elements to define a resource of type "ldap"
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getLdapElements()
|
||||
{
|
||||
return array(
|
||||
$this->createElement(
|
||||
'text',
|
||||
'hostname',
|
||||
array(
|
||||
'required' => true,
|
||||
'allowEmpty' => false,
|
||||
'label' => t('Host'),
|
||||
'helptext' => t('The hostname or address of the LDAP server to use for authentication'),
|
||||
'value' => 'localhost'
|
||||
)
|
||||
),
|
||||
new Number(
|
||||
array(
|
||||
'required' => true,
|
||||
'name' => 'port',
|
||||
'label' => t('Port'),
|
||||
'helptext' => t('The port of the LDAP server to use for authentication'),
|
||||
'value' => 389,
|
||||
'decorators' => array( // The order is important!
|
||||
'ViewHelper',
|
||||
'Errors',
|
||||
new ElementWrapper(),
|
||||
new HelpText()
|
||||
)
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'root_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Root DN'),
|
||||
'helptext' => t('The path where users can be found on the ldap server')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'bind_dn',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Bind DN'),
|
||||
'helptext' => t('The user dn to use for querying the ldap server')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'password',
|
||||
'bind_pw',
|
||||
array(
|
||||
'required' => true,
|
||||
'renderPassword' => true,
|
||||
'label' => t('Bind Password'),
|
||||
'helptext' => t('The password to use for querying the ldap server')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all required elements to define a resource of type "file"
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getFileElements()
|
||||
{
|
||||
return array(
|
||||
$this->createElement(
|
||||
'text',
|
||||
'filename',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Filepath'),
|
||||
'helptext' => t('The filename to fetch information from')
|
||||
)
|
||||
),
|
||||
$this->createElement(
|
||||
'text',
|
||||
'fields',
|
||||
array(
|
||||
'required' => true,
|
||||
'label' => t('Pattern'),
|
||||
'helptext' => t('The regular expression by which to identify columns')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -2,10 +2,9 @@
|
||||
<?= $tabs; ?>
|
||||
</div>
|
||||
<div class="content" data-base-target="_next">
|
||||
<?= $messageBox; ?>
|
||||
<p>
|
||||
<a href="<?= $this->href('/config/createresource') ?>">
|
||||
<?= $this->icon('create.png'); ?> <?= $this->translate('Create a new resource'); ?>
|
||||
<a href="<?= $this->href('/config/createresource'); ?>">
|
||||
<?= $this->icon('create.png'); ?> <?= $this->translate('Create A New Resource'); ?>
|
||||
</a>
|
||||
</p>
|
||||
<table class="action">
|
||||
@ -17,12 +16,12 @@
|
||||
<?php foreach ($this->resources as $name => $resource): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?= $this->href('config/editresource', array('resource' => $name)) ?>">
|
||||
<?= $this->icon('edit.png') ?> <?= $this->escape($name); ?>
|
||||
<a href="<?= $this->href('config/editresource', array('resource' => $name)); ?>">
|
||||
<?= $this->icon('edit.png'); ?> <?= $this->escape($name); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td style="text-align: center">
|
||||
<a href="<?= $this->href('config/removeresource', array('resource' => $name)) ?>">
|
||||
<a href="<?= $this->href('config/removeresource', array('resource' => $name)); ?>">
|
||||
<?= $this->icon('remove.png'); ?>
|
||||
</a>
|
||||
</td>
|
||||
|
@ -1,4 +1,3 @@
|
||||
<?= $messageBox; ?>
|
||||
<h4><?= $this->translate('Create a new resource'); ?></h4>
|
||||
<p><?= $this->translate('Resources are entities that provide data to Icingaweb.'); ?></p>
|
||||
<h4><?= $this->translate('Create A New Resource'); ?></h4>
|
||||
<p><?= $this->translate('Resources are entities that provide data to Icinga Web 2.'); ?></p>
|
||||
<?= $form; ?>
|
@ -1,3 +1,2 @@
|
||||
<h4><?= $this->translate('Edit Existing Resource'); ?></h4>
|
||||
<?= $messageBox; ?>
|
||||
<?= $form; ?>
|
@ -1,3 +1,2 @@
|
||||
<h4><?= $this->translate('Remove Existing Resource'); ?></h4>
|
||||
<?= $messageBox; ?>
|
||||
<?= $form; ?>
|
Loading…
x
Reference in New Issue
Block a user