Merge branch 'master' of git.icinga.org:icingaweb2-module-director

This commit is contained in:
Stefan Scheungrab 2015-08-03 06:43:31 +02:00
commit 8054fd37f1
54 changed files with 2038 additions and 762 deletions

View File

@ -11,19 +11,13 @@ class Director_DatalistentryController extends ActionController
public function editAction()
{
$this->indexAction();
$this->indexAction(true);
}
public function indexAction($edit = false)
{
$request = $this->getRequest();
if ($request->getParam('edit')) {
$edit = true;
} else {
$edit = false;
}
$listId = $this->params->get('list_id');
$this->view->lastId = $listId;
@ -46,6 +40,7 @@ class Director_DatalistentryController extends ActionController
}
$form = $this->view->form = $this->loadForm('directorDatalistentry')
->setListId($listId)
->setSuccessUrl('director/datalistentry' . '?list_id=' . $listId)
->setDb($this->db());

View File

@ -0,0 +1,7 @@
<?php
use Icinga\Module\Director\Web\Controller\ObjectsController;
class Director_HosttemplatesController extends ObjectsController
{
}

View File

@ -0,0 +1,62 @@
<?php
use Icinga\Module\Director\Web\Controller\ActionController;
class Director_SchemaController extends ActionController
{
protected $schema;
public function init()
{
$this->schemas = array(
'mysql' => $this->translate('MySQL schema'),
'pgsql' => $this->translate('PostgreSQL schema'),
);
}
protected function tabs()
{
$tabs = $this->getTabs();
foreach ($this->schemas as $type => $title) {
$tabs->add($type, array(
'url' => 'director/schema/' . $type,
'label' => $title,
));
}
return $tabs;
}
public function mysqlAction()
{
$this->serveSchema('mysql');
}
public function pgsqlAction()
{
$this->serveSchema('pgsql');
}
protected function serveSchema($type)
{
$schema = file_get_contents(
sprintf(
'%s/schema/%s.sql',
$this->Module()->getBasedir(),
$type
)
);
if ($this->params->get('format') === 'sql') {
header('Content-type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $type . '.sql');
echo $schema;
exit;
// TODO: Shutdown
} else {
$this->tabs()->activate($type);
$this->view->title = $this->schemas[$type];
$this->view->schema = $schema;
$this->render('schema');
}
}
}

View File

@ -0,0 +1,7 @@
<?php
use Icinga\Module\Director\Web\Controller\ObjectsController;
class Director_ServicetemplatesController extends ObjectsController
{
}

View File

@ -1,6 +1,5 @@
<?php
use Icinga\Data\ResourceFactory;
use Icinga\Forms\ConfigForm;
use Icinga\Module\Director\Web\Controller\ActionController;
@ -8,42 +7,12 @@ class Director_SettingsController extends ActionController
{
public function indexAction()
{
$this->view->tabs = $this->Module()->getConfigTabs()->activate('config');
$this->view->tabs = $this->Module()
->getConfigTabs()
->activate('config');
$resource = $this->Config()->get('db', 'resource');
$form = new ConfigForm();
$form->setIniConfig($this->Config('config'));
$form->addElement('select', 'resource', array(
'required' => true,
'label' => $this->translate('DB Resource'),
'multiOptions' => array(null => $this->translate('- please choose -')) + $this->getResources(),
'value' => $resource
));
$form->setSubmitLabel($this->translate('Save'));
$form->setOnSuccess(function($form) {
/** @var $form ConfigForm */
$this->Config('config')->setSection('db', array(
'resource' => $form->getValue('resource')
));
$form->save();
});
$form->handleRequest();
$this->view->form = $form;
}
public function getResources()
{
$resources = array();
foreach (ResourceFactory::getResourceConfigs() as $name => $resource) {
if ($resource->type === 'db') {
$resources['ido'][$name] = $name;
}
}
return $resources;
$this->view->form = $this->loadForm('config')
->setModuleConfig($this->Config())
->handleRequest();
}
}

View File

@ -0,0 +1,152 @@
<?php
namespace Icinga\Module\Director\Forms;
use Exception;
use Icinga\Application\Config;
use Icinga\Data\ResourceFactory;
use Icinga\Module\Director\Web\Form\QuickForm;
class ConfigForm extends QuickForm
{
protected $config;
public function setup()
{
$resources = $this->enumResources();
$this->addElement('select', 'resource', array(
'required' => true,
'label' => $this->translate('DB Resource'),
'multiOptions' => $this->optionalEnum($resources),
'class' => 'autosubmit',
'value' => $this->config()->get('db', 'resource')
));
if (empty($resources)) {
$this->getElement('resource')->addError(
$this->translate('This has to be a MySQL or PostgreSQL database')
);
$hint = $this->translate('Please click %s to create new DB resources');
$link = $this->getView()->qlink(
$this->translate('here'),
'config/resource',
null,
array('data-base-target' => '_main')
);
$this->addHtmlHint(sprintf($hint, $link));
}
$this->setSubmitLabel($this->translate('Store configuration'));
}
protected function onSetup()
{
if ($this->hasBeenSubmitted()) {
// Do not hinder the form from being stored
return;
}
if ($this->hasBeenSent() && $this->isValidPartial($this->getRequest()->getPost())) {
$resourceName = $this->getValue('resource');
} else {
$resourceName = $this->config()->get('db', 'resource');
}
if ($resourceName) {
$resource = ResourceFactory::create($resourceName);
$db = $resource->getDbAdapter();
try {
$query = $db->select()->from('director_dbversion', 'COUNT(*)');
$db->fetchOne($query);
if (! $this->hasBeenSent()) {
$hint = $this->translate(
'Configuration looks good, you should be ready to %s'
. ' Icinga Director'
);
$link = $this->getView()->qlink(
$this->translate('start using'),
'director/welcome',
null,
array('data-base-target' => '_main')
);
$this->addHtmlHint(sprintf($hint, $link));
$this->moveSubmitToBottom();
}
} catch (Exception $e) {
$this->getElement('resource')
->addError('Could not fetch: ' . $e->getMessage())
->removeDecorator('description');
$hint = $this->translate(
'Please make sure that your database grants enough permissions'
. ' and that you deployed the correct %s.'
);
$link = $this->getView()->qlink(
$this->translate('database schema'),
'director/schema/' . $resource->getDbType(),
null,
array('data-base-target' => '_next')
);
$this->addHtmlHint(sprintf($hint, $link));
$this->moveSubmitToBottom();
}
}
}
public function setModuleConfig(Config $config)
{
$this->config = $config;
return $this;
}
public function onSuccess()
{
$config = $this->config();
$value = $this->getValue('resource');
$config->setSection('db', array('resource' => $value));
try {
$config->saveIni();
$this->redirectOnSuccess($this->translate('Configuration has been stored'));
} catch (Exception $e) {
$this->getElement('resource')->addError(
sprintf(
$this->translate('Unable to store the configuration to "%s"'),
$config->getConfigFile()
)
)->removeDecorator('description');
$this->addHtmlHint(
'<pre>' . $config . '</pre>'
);
}
}
protected function config()
{
if ($this->config === null) {
$this->config = Config::module('director');
}
return $this->config;
}
protected function enumResources()
{
$resources = array();
$allowed = array('mysql', 'pgsql');
foreach (ResourceFactory::getResourceConfigs() as $name => $resource) {
if ($resource->type === 'db' && in_array($resource->db, $allowed)) {
$resources[$name] = $name;
}
}
return $resources;
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Icinga\Module\Director\Forms;
use Icinga\Module\Director\Web\Form\QuickForm;
class CustomvarForm extends QuickForm
{
protected $submitLabel = false;
public function setup()
{
$this->removeCsrfToken();
$this->removeElement(self::ID);
$this->addElement('text', 'varname', array(
'label' => $this->translate('Variable name'),
'required' => true,
));
$this->addElement('text', 'varvalue', array(
'label' => $this->translate('Value'),
));
// $this->addHidden('format', 'string'); // expression, json?
}
}

View File

@ -7,22 +7,30 @@ use Icinga\Web\Hook;
class DirectorDatafieldForm extends DirectorObjectForm
{
protected $objectName = 'Data field';
public function setup()
{
$this->addHtmlHint(
$this->translate('Data fields allow you to customize input controls your custom variables.')
);
$this->addElement('text', 'varname', array(
'required' => true,
'label' => $this->translate('Field name'),
'description' => $this->translate('The unique name of the field')
'label' => $this->translate('Field name'),
'description' => $this->translate('The unique name of the field'),
'required' => true,
));
$this->addElement('text', 'caption', array(
'label' => $this->translate('Caption'),
'label' => $this->translate('Caption'),
'required' => true,
'description' => $this->translate('The caption which should be displayed')
));
$this->addElement('textarea', 'description', array(
'label' => $this->translate('Description'),
'description' => $this->translate('A description about the field')
'label' => $this->translate('Description'),
'description' => $this->translate('A description about the field'),
'rows' => '3',
));
$this->addElement('select', 'datatype', array(
@ -30,15 +38,23 @@ class DirectorDatafieldForm extends DirectorObjectForm
'description' => $this->translate('Field type'),
'required' => true,
'multiOptions' => $this->enumDataTypes(),
'class' => 'autosubmit'
'class' => 'autosubmit',
));
if ($class = $this->object()->datatype) {
$this->addSettings($class);
} elseif ($class = $this->getSentValue('datatype')) {
if ($class = $this->getSentValue('datatype')) {
if ($class && array_key_exists($class, $this->enumDataTypes())) {
$this->addSettings($class);
}
} elseif ($class = $this->object()->datatype) {
$this->addSettings($class);
}
$this->addSettings();
foreach ($this->object()->getSettings() as $key => $val) {
if ($el = $this->getElement($key)) {
$el->setValue($val);
}
}
}
@ -53,8 +69,31 @@ class DirectorDatafieldForm extends DirectorObjectForm
}
}
protected function clearOutdatedSettings()
{
$names = array();
$object = $this->object();
$global = array('varname', 'description', 'caption', 'datatype');
foreach ($this->getElements() as $el) {
if ($el->getIgnore()) continue;
$name = $el->getName();
if (in_array($name, $global)) continue;
$names[$name] = $name;
}
foreach ($object->getSettings() as $setting => $value) {
if (! array_key_exists($setting, $names)) {
unset($object->$setting);
}
}
}
public function onSuccess()
{
$this->clearOutdatedSettings();
if ($class = $this->getValue('datatype')) {
if (array_key_exists($class, $this->enumDataTypes())) {
$this->addHidden('format', $class::getFormat());
@ -64,21 +103,6 @@ class DirectorDatafieldForm extends DirectorObjectForm
parent::onSuccess();
}
public function loadObject($id)
{
parent::loadObject($id);
$this->addSettings();
foreach ($this->object()->getSettings() as $key => $val) {
if ($el = $this->getElement($key)) {
$el->setValue($val);
}
}
$this->moveSubmitToBottom();
return $this;
}
protected function enumDataTypes()
{
$hooks = Hook::all('Director\\DataType');

View File

@ -3,22 +3,21 @@
namespace Icinga\Module\Director\Forms;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
use Icinga\Authentication\Manager as Auth;
use Icinga\Authentication\Auth;
class DirectorDatalistForm extends DirectorObjectForm
{
public function setup()
{
$this->addElement('text', 'list_name', array(
'label' => $this->translate('List name')
'label' => $this->translate('List name'),
'required' => true,
));
$this->addElement('hidden', 'owner');
}
public function onSuccess()
{
$this->addHidden('owner', self::username());
$this->object()->owner = self::username();
parent::onSuccess();
}

View File

@ -6,6 +6,8 @@ use Icinga\Module\Director\Web\Form\DirectorObjectForm;
class DirectorDatalistEntryForm extends DirectorObjectForm
{
protected $listId;
public function setup()
{
$this->addElement('text', 'entry_name', array(
@ -18,9 +20,17 @@ class DirectorDatalistEntryForm extends DirectorObjectForm
'label' => 'Type',
'multiOptions' => array('string' => $this->translate('String'))
));
}
$this->addElement('hidden', 'list_id', array(
'value' => $this->getRequest()->getParam('list_id'),
));
public function onSuccess()
{
$this->object()->list_id = $this->listId;
parent::onSuccess();
}
public function setListId($id)
{
$this->listId = $id;
return $this;
}
}

View File

@ -8,10 +8,10 @@ class IcingaCommandArgumentForm extends DirectorObjectForm
{
public function setup()
{
$this->addElement('select', 'command_id', array(
'label' => $this->translate('Check command'),
'description' => $this->translate('Check command definition')
'label' => $this->translate('Check command'),
'description' => $this->translate('Check command definition'),
'multiOptions' => $this->optionalEnum($this->db->enumCommands())
));
$this->addElement('text', 'argument_name', array(
@ -26,7 +26,6 @@ class IcingaCommandArgumentForm extends DirectorObjectForm
));
$this->addHidden('value_format', 'string'); // expression, json?
}

View File

@ -8,7 +8,8 @@ class IcingaEndpointForm extends DirectorObjectForm
{
public function setup()
{
$isTemplate = isset($_POST['object_type']) && $_POST['object_type'] === 'template';
$isTemplate = $this->getSentValue('object_type') === 'template';
$this->addElement('select', 'object_type', array(
'label' => $this->translate('Object type'),
'description' => $this->translate('Whether this should be a template'),
@ -48,15 +49,7 @@ class IcingaEndpointForm extends DirectorObjectForm
'description' => $this->translate('The log duration time.')
));
$this->addElement('select', 'zone_id', array(
'label' => $this->translate('Cluster Zone'),
'description' => $this->translate('Check this host in this specific Icinga cluster zone'),
'required' => true
));
$this->addElement('text', 'imports', array(
'label' => $this->translate('Imports'),
'description' => $this->translate('The inherited endpoint template names')
));
$this->addZoneElement()
->addImportsElement();
}
}

View File

@ -9,21 +9,21 @@ class IcingaHostFieldForm extends DirectorObjectForm
public function setup()
{
$this->addElement('select', 'host_id', array(
'label' => 'Host Tpl',
'description' => 'Host Template',
'multiOptions' => $this->optionalEnum($this->getDb()->enumHostTemplates())
'label' => 'Host Tpl',
'description' => 'Host Template',
'multiOptions' => $this->optionalEnum($this->db->enumHostTemplates())
));
$this->addElement('select', 'datafield_id', array(
'label' => 'Field',
'description' => 'Field to assign',
'multiOptions' => $this->optionalEnum($this->getDb()->enumDatafields())
'label' => 'Field',
'description' => 'Field to assign',
'multiOptions' => $this->optionalEnum($this->db->enumDatafields())
));
$this->optionalBoolean(
'is_required',
$this->translate('Required'),
$this->translate('Whether this filed is required or not.')
$this->translate('Whether this field should be required or not')
);
}
}

View File

@ -9,32 +9,12 @@ class IcingaHostForm extends DirectorObjectForm
{
public function setup()
{
$isTemplate = isset($_POST['object_type']) && $_POST['object_type'] === 'template';
$this->addElement('select', 'object_type', array(
'label' => $this->translate('Object type'),
'description' => $this->translate('Whether this should be a template'),
'multiOptions' => array(
null => '- please choose -',
'object' => 'Host object',
'template' => 'Host template',
),
'class' => 'autosubmit'
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Hostname'),
'required' => true,
'description' => $this->translate('Icinga object name for this host')
));
if ($isTemplate) {
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Host template name'),
'required' => true,
'description' => $this->translate('Name for the Icinga host template you are going to create')
));
} else {
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Hostname'),
'required' => true,
'description' => $this->translate('Hostname for the Icinga host you are going to create')
));
}
$this->addElement('text', 'address', array(
'label' => $this->translate('Host address'),
'description' => $this->translate('Host address. Usually an IPv4 address, but may be any kind of address your check plugin is able to deal with')
@ -45,95 +25,31 @@ class IcingaHostForm extends DirectorObjectForm
'description' => $this->translate('Usually your hosts main IPv6 address')
));
$this->addElement('select', 'check_command_id', array(
'label' => $this->translate('Check command'),
'description' => $this->translate('Check command definition')
));
$this->optionalBoolean(
'enable_notifications',
$this->translate('Send notifications'),
$this->translate('Whether to send notifications for this host')
);
$this->optionalBoolean(
'enable_active_checks',
$this->translate('Execute active checks'),
$this->translate('Whether to actively check this host')
);
$this->optionalBoolean(
'enable_passive_checks',
$this->translate('Accept passive checks'),
$this->translate('Whether to accept passive check results for this host')
);
$this->optionalBoolean(
'enable_event_handler',
$this->translate('Enable event handler'),
$this->translate('Whether to enable event handlers this host')
);
$this->optionalBoolean(
'enable_perfdata',
$this->translate('Process performance data'),
$this->translate('Whether to process performance data provided by this host')
);
$this->optionalBoolean(
'volatile',
$this->translate('Volatile'),
$this->translate('Whether this check is volatile.')
);
$this->addImportsElement();
/*
$this->addElement('text', 'groups', array(
'label' => $this->translate('Hostgroups'),
'description' => $this->translate('One or more comma separated hostgroup names')
));
*/
$this->addElement('text', 'imports', array(
'label' => $this->translate('Imports'),
'description' => $this->translate('The inherited host template names')
));
if ($this->isTemplate()) {
$this->addElement('text', 'address', array(
'label' => $this->translate('Host address'),
'description' => $this->translate('Host address. Usually an IPv4 address, but may be any kind of address your check plugin is able to deal with')
));
$this->addElement('select', 'zone_id', array(
'label' => $this->translate('Cluster Zone'),
'description' => $this->translate('Check this host in this specific Icinga cluster zone')
));
}
$this->addElement('text', 'address6', array(
'label' => $this->translate('IPv6 address'),
'description' => $this->translate('Usually your hosts main IPv6 address')
));
public function loadObject($id)
{
parent::loadObject($id);
$this->addFields();
$this->moveSubmitToBottom();
}
public function addFields()
{
$fields = $this->getObject()->getFields($this);
$vars = $this->getObject()->vars();
foreach ($fields as $field) {
$datatype = new $field->datatype;
$datafield = DirectorDatafield::load($field->datafield_id, $this->getDb());
$datatype->setSettings($datafield->getSettings());
$varname = $datafield->varname;
$el = $datatype->getFormElement('var_' . $varname, $this);
$el->setLabel($field->caption);
$el->setDescription($field->description);
if (isset($vars->$varname)) {
$el->setValue($vars->{$varname}->getValue());
}
if ($field->is_required === 'y')
{
$el->setRequired(true);
}
$this->addElement($el);
$this->addCheckExecutionElements();
} else {
$this->getElement('imports')->setRequired();
}
$this->addZoneElement();
}
}

View File

@ -8,39 +8,15 @@ class IcingaHostGroupForm extends DirectorObjectForm
{
public function setup()
{
$isTemplate = isset($_POST['object_type']) && $_POST['object_type'] === 'template';
$this->addElement('select', 'object_type', array(
'label' => $this->translate('Object type'),
'description' => $this->translate('Whether this should be a template'),
'multiOptions' => array(
null => '- please choose -',
'object' => 'Hostgroup object',
'template' => 'Hostgroup template',
)
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Hostgroup'),
'required' => true,
'description' => $this->translate('Icinga object name for this hostgroup')
));
if ($isTemplate) {
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Hostgroup template name'),
'required' => true,
'description' => $this->translate('Hostgroup for the Icinga hostgroup template you are going to create')
));
} else {
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Hostgroup'),
'required' => true,
'description' => $this->translate('Hostgroup for the Icinga hostgroup you are going to create')
));
}
$this->addElement('text', 'display_name', array(
'label' => $this->translate('Display Name'),
'description' => $this->translate('The name which should displayed.')
));
$this->addElement('text', 'imports', array(
'label' => $this->translate('Imports'),
'description' => $this->translate('The inherited hostgroup template names')
));
}
}

View File

@ -12,23 +12,24 @@ class IcingaHostVarForm extends DirectorObjectForm
public function setup()
{
$this->addElement('select', 'host_id', array(
'label' => $this->translate('Host'),
'description' => $this->translate('The name of the host'),
'required' => true
'label' => $this->translate('Host'),
'description' => $this->translate('The name of the host'),
'multiOptions' => $this->optionalEnum($this->db->enumHosts()),
'required' => true
));
$this->addElement('text', 'varname', array(
'label' => $this->translate('Name'),
'label' => $this->translate('Name'),
'description' => $this->translate('host var name')
));
$this->addElement('textarea', 'varvalue', array(
'label' => $this->translate('Value'),
'label' => $this->translate('Value'),
'description' => $this->translate('host var value')
));
$this->addElement('text', 'format', array(
'label' => $this->translate('Format'),
'label' => $this->translate('Format'),
'description' => $this->translate('value format')
));
}

View File

@ -9,21 +9,20 @@ class IcingaServiceFieldForm extends DirectorObjectForm
public function setup()
{
$this->addElement('select', 'service_id', array(
'label' => 'Service Tpl',
'description' => 'Service Template',
'multiOptions' => $this->optionalEnum($this->getDb()->enumServiceTemplates())
'label' => 'Service template',
'multiOptions' => $this->optionalEnum($this->db->enumServiceTemplates())
));
$this->addElement('select', 'datafield_id', array(
'label' => 'Field',
'description' => 'Field to assign',
'multiOptions' => $this->optionalEnum($this->getDb()->enumDatafields())
'label' => 'Field',
'description' => 'Field to assign',
'multiOptions' => $this->optionalEnum($this->db->enumDatafields())
));
$this->optionalBoolean(
'is_required',
$this->translate('Required'),
$this->translate('Whether this filed is required or not.')
$this->translate('Whether this field should be required or not')
);
}
}

View File

@ -8,86 +8,23 @@ class IcingaServiceForm extends DirectorObjectForm
{
public function setup()
{
$isTemplate = isset($_POST['object_type']) && $_POST['object_type'] === 'template';
$this->addElement('select', 'object_type', array(
'label' => $this->translate('Object type'),
'description' => $this->translate('Whether this should be a template'),
'multiOptions' => array(
null => '- please choose -',
'object' => 'Service object',
'template' => 'Service template',
),
'class' => 'autosubmit'
));
if ($isTemplate) {
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Service template name'),
'required' => true,
'description' => $this->translate('Name for the Icinga service template you are going to create')
));
} else {
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Servicename'),
'required' => true,
'description' => $this->translate('Servicename for the Icinga service you are going to create')
));
}
$this->addElement('select', 'check_command_id', array(
'label' => $this->translate('Check command'),
'description' => $this->translate('Check command definition')
));
$this->optionalBoolean(
'enable_notifications',
$this->translate('Send notifications'),
$this->translate('Whether to send notifications for this service')
);
$this->optionalBoolean(
'enable_active_checks',
$this->translate('Execute active checks'),
$this->translate('Whether to actively check this service')
);
$this->optionalBoolean(
'enable_passive_checks',
$this->translate('Accept passive checks'),
$this->translate('Whether to accept passive check results for this service')
);
$this->optionalBoolean(
'enable_event_handler',
$this->translate('Enable event handler'),
$this->translate('Whether to enable event handlers this service')
);
$this->optionalBoolean(
'enable_perfdata',
$this->translate('Process performance data'),
$this->translate('Whether to process performance data provided by this service')
);
$this->optionalBoolean(
'volatile',
$this->translate('Volatile'),
$this->translate('Whether this check is volatile.')
);
$this->addElement('select', 'zone_id', array(
'label' => $this->translate('Cluster Zone'),
'description' => $this->translate('Check this host in this specific Icinga cluster zone')
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Name'),
'required' => true,
'description' => $this->translate('Name for the Icinga object you are going to create')
));
/*
$this->addElement('text', 'groups', array(
'label' => $this->translate('Servicegroups'),
'description' => $this->translate('One or more comma separated servicegroup names')
));
*/
$this->addElement('text', 'imports', array(
'label' => $this->translate('Imports'),
'description' => $this->translate('The inherited service template names')
));
$this->addImportsElement();
if ($this->isTemplate()) {
$this->addCheckExecutionElements();
}
}
}

View File

@ -8,39 +8,15 @@ class IcingaServiceGroupForm extends DirectorObjectForm
{
public function setup()
{
$isTemplate = isset($_POST['object_type']) && $_POST['object_type'] === 'template';
$this->addElement('select', 'object_type', array(
'label' => $this->translate('Object type'),
'description' => $this->translate('Whether this should be a template'),
'multiOptions' => array(
null => '- please choose -',
'object' => 'Servicegroup object',
'template' => 'Servicegroup template',
)
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Servicegroup'),
'required' => true,
'description' => $this->translate('Icinga object name for this servicegroup')
));
if ($isTemplate) {
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Servicegroup template name'),
'required' => true,
'description' => $this->translate('Servicegroup for the Icinga servicegroup template you are going to create')
));
} else {
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Servicegroup'),
'required' => true,
'description' => $this->translate('Servicegroup for the Icinga servicegroup you are going to create')
));
}
$this->addElement('text', 'display_name', array(
'label' => $this->translate('Display Name'),
'description' => $this->translate('The name which should displayed.')
));
$this->addElement('text', 'imports', array(
'label' => $this->translate('Imports'),
'description' => $this->translate('The inherited servicegroup template names')
));
}
}

View File

@ -12,23 +12,24 @@ class IcingaServiceVarForm extends DirectorObjectForm
public function setup()
{
$this->addElement('select', 'service_id', array(
'label' => $this->translate('Service'),
'description' => $this->translate('The name of the service'),
'required' => true
'label' => $this->translate('Service'),
'description' => $this->translate('The name of the service'),
'multiOptions' => $this->optionalEnum($this->db->enumServices()),
'required' => true
));
$this->addElement('text', 'varname', array(
'label' => $this->translate('Name'),
'label' => $this->translate('Name'),
'description' => $this->translate('service var name')
));
$this->addElement('textarea', 'varvalue', array(
'label' => $this->translate('Value'),
'label' => $this->translate('Value'),
'description' => $this->translate('service var value')
));
$this->addElement('text', 'format', array(
'label' => $this->translate('Format'),
'label' => $this->translate('Format'),
'description' => $this->translate('value format')
));
}

View File

@ -43,15 +43,7 @@ class IcingaTimePeriodForm extends DirectorObjectForm
'description' => $this->translate('the update method'),
));
$this->addElement('select', 'zone_id', array(
'label' => $this->translate('Cluster Zone'),
'description' => $this->translate('Check this host in this specific Icinga cluster zone'),
'required' => true
));
$this->addElement('text', 'imports', array(
'label' => $this->translate('Imports'),
'description' => $this->translate('The inherited timperiods template names')
));
$this->addZoneElement();
$this->addImportsElement();
}
}

View File

@ -49,20 +49,11 @@ class IcingaUserForm extends DirectorObjectForm
$this->translate('Whether to send notifications for this user')
);
$this->addElement('select', 'zone_id', array(
'label' => $this->translate('Cluster Zone'),
'description' => $this->translate('Check this user in this specific Icinga cluster zone')
));
$this->addElement('text', 'groups', array(
'label' => $this->translate('Usergroups'),
'description' => $this->translate('One or more comma separated usergroup names')
));
$this->addElement('text', 'imports', array(
'label' => $this->translate('Imports'),
'description' => $this->translate('The inherited user template names')
));
$this->addImportsElement();
}
}

View File

@ -8,44 +8,15 @@ class IcingaUserGroupForm extends DirectorObjectForm
{
public function setup()
{
$isTemplate = isset($_POST['object_type']) && $_POST['object_type'] === 'template';
$this->addElement('select', 'object_type', array(
'label' => $this->translate('Object type'),
'description' => $this->translate('Whether this should be a template'),
'multiOptions' => array(
null => '- please choose -',
'object' => 'Usergroup object',
'template' => 'Usergroup template',
)
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Usergroup'),
'required' => true,
'description' => $this->translate('Icinga object name for this usergroup')
));
if ($isTemplate) {
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Usergroup template name'),
'required' => true,
'description' => $this->translate('Usergroup for the Icinga usergroup template you are going to create')
));
} else {
$this->addElement('text', 'object_name', array(
'label' => $this->translate('Usergroup'),
'required' => true,
'description' => $this->translate('Usergroup for the Icinga usergroup you are going to create')
));
}
$this->addElement('text', 'display_name', array(
'label' => $this->translate('Display Name'),
'description' => $this->translate('The name which should displayed.')
));
$this->addElement('select', 'zone_id', array(
'label' => $this->translate('Cluster Zone'),
'description' => $this->translate('Check this usergroup in this specific Icinga cluster zone')
));
$this->addElement('text', 'imports', array(
'label' => $this->translate('Imports'),
'description' => $this->translate('The inherited usergroup template names')
));
}
}

View File

@ -10,7 +10,7 @@ class IcingaZoneForm extends DirectorObjectForm
{
$this->addElement('select', 'object_type', array(
'label' => $this->translate('Object type'),
'description' => $this->translate('Whether this should be a template'),
'description' => $this->translate('Whether this should be a template'),
'multiOptions' => $this->optionalEnum(array(
'object' => $this->translate('Zone object'),
'template' => $this->translate('Zone template'),
@ -24,22 +24,23 @@ class IcingaZoneForm extends DirectorObjectForm
));
$this->addElement('select', 'is_global', array(
'label' => 'Global zone',
'description' => 'Whether this zone should be available everywhere',
'label' => 'Global zone',
'description' => 'Whether this zone should be available everywhere',
'multiOptions' => array(
'n' => $this->translate('No'),
'y' => $this->translate('Yes'),
),
'required' => true,
'required' => true,
));
$this->addElement('select', 'parent_zone_id', array(
'label' => $this->translate('Parent Zone'),
'description' => $this->translate('Chose an (optional) parent zone')
'label' => $this->translate('Parent Zone'),
'description' => $this->translate('Chose an (optional) parent zone'),
'multiOptions' => $this->optionalEnum($this->db->enumZones())
));
$this->addElement('text', 'imports', array(
'label' => $this->translate('Imports'),
'label' => $this->translate('Imports'),
'description' => $this->translate('The inherited zone template names')
));
}

View File

@ -13,9 +13,11 @@ class DatafieldTable extends QuickTable
public function getColumns()
{
return array(
'id' => 'f.id',
'varname' => 'f.varname',
'datatype' => 'f.datatype',
'id' => 'f.id',
'varname' => 'f.varname',
'caption' => 'f.caption',
'description' => 'f.description',
'datatype' => 'f.datatype',
);
}
@ -28,8 +30,8 @@ class DatafieldTable extends QuickTable
{
$view = $this->view();
return array(
'varname' => $view->translate('Field name'),
'datatype' => $view->translate('Data type'),
'caption' => $view->translate('Label'),
'varname' => $view->translate('Field name'),
);
}
@ -40,7 +42,7 @@ class DatafieldTable extends QuickTable
$query = $db->select()->from(
array('f' => 'director_datafield'),
array()
)->order('varname ASC');
)->order('caption ASC');
return $query;
}

View File

@ -0,0 +1,13 @@
<?php
namespace Icinga\Module\Director\Tables;
use Icinga\Module\Director\Tables\IcingaHostTable;
class IcingaHostTemplateTable extends IcingaHostTable
{
public function getBaseQuery()
{
return $this->getUnfilteredQuery()->where('h.object_type = ?', 'template');
}
}

View File

@ -33,7 +33,7 @@ class IcingaServiceTable extends QuickTable
);
}
public function getBaseQuery()
public function getUnfilteredQuery()
{
$db = $this->connection()->getConnection();
$query = $db->select()->from(
@ -47,4 +47,9 @@ class IcingaServiceTable extends QuickTable
return $query;
}
public function getBaseQuery()
{
return $this->getUnfilteredQuery()->where('s.object_type = ?', 'object');
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Icinga\Module\Director\Tables;
use Icinga\Module\Director\Tables\IcingaServiceTable;
class IcingaServiceTemplateTable extends IcingaServiceTable
{
public function getBaseQuery()
{
return $this->getUnfilteredQuery()->where('s.object_type = ?', 'template');
}
}

View File

@ -0,0 +1,65 @@
<?php
use Icinga\Web\Url;
function dumpTree($tree, $self, $level = 0)
{
$hasChildren = ! empty($tree->children);
if ($level === 0) {
$class = 'root';
} else {
$class = 'host';
}
if ($hasChildren) {
$collapsed = '';
} else {
$collapsed = ' class="collapsed"';
}
$html = '<li' . $collapsed . '>';
if ($hasChildren) {
ksort($tree->children);
$html .= '<span class="handle"> </span>';
}
if ($level === 0) {
$html .= '<a name="Templates" class="root">' . $self->escape($tree->name) . '</a>';
} else {
$html .= $self->qlink(
$tree->name,
'director/host',
array('name' => $tree->name),
array('class' => $class)
);
}
if ($hasChildren) {
$html .= '<ul>';
foreach ($tree->children as $child) {
$html .= dumpTree($child, $self, $level + 1);
}
$html .= '</ul>';
}
$html .= "</li>\n";
return $html;
}
?>
<div class="controls">
<?= $this->tabs ?>
<h1><?= $this->translate('Host template tree') ?></h1>
</div>
<div class="content">
<ul class="tree" data-base-target="_next">
<?= dumpTree(
(object) array(
'name' => 'Templates',
'children' => $this->tree
),
$this
) ?>
</ul>
</div>

View File

@ -0,0 +1,10 @@
<div class="controls">
<?= $tabs ?>
<h1><?= $this->escape($title) ?></h1>
<a href="<?= $this->url()->with('format', 'sql') ?>" target="_blank"><?= $this->icon('download') ?>Download</a>
</div>
<div class="content">
<pre><?= $this->escape($schema) ?></pre>
</div>

View File

@ -2,6 +2,6 @@
<?= $this->tabs ?>
</div>
<div class="content" data-base-target="_next">
<?= $form; ?>
<div class="content">
<?= $form ?>
</div>

View File

@ -15,6 +15,8 @@ foreach ($new as $key => $value) {
if ($value === null) continue;
if (is_array($value)) $value = implode(', ', $value);
echo ' <tr><th>' . $this->escape($key) . '</th><td>';
echo $this->escape($value);
echo "</td></tr>\n";

View File

@ -17,12 +17,19 @@ foreach ($old as $key => $value) {
$modified = array_key_exists($key, $new);
if ($value === null && ! $modified) continue;
if (is_array($value)) $value = implode(', ', $value);
if (is_object($value)) $value = json_encode($value);
echo ' <tr><th>' . $this->escape($key) . '</th><td>';
if ($modified) {
$newval = $new->$key;
if (is_array($newval)) $newval = implode(', ', $newval);
if (is_object($newval)) $newval = json_encode($newval);
printf(
'<span class="old">%s</span> <span class="new">%s</span>',
$this->escape($value),
$this->escape($new->$key)
$this->escape($newval)
);
} else {
echo $this->escape($value);

View File

@ -7,5 +7,25 @@
<?php if ($this->errorMessage): ?>
<p class="error"><?= $this->errorMessage ?></p>
<?php endif ?>
Nothing to see here yet. We will point you to the most common tasks later on.
<?php
$actions = array(
array('cloud', $this->translate('Monitoring Nodes'), 'director/commands'),
array('host', $this->translate('Host objecs'), 'director/hosts'),
array('services', $this->translate('Monitored Services'), 'director/services'),
array('users', $this->translate('Users / Contacts'), 'director/users'),
array('chat', $this->translate('Alarms and notifications'), 'director/notificatios'),
array('database', $this->translate('Sync / Import'), 'director/list/importsource'),
array('wrench', $this->translate('Configuration'), 'director/list/generatedconfig'),
);
?>
<ul class="main-actions">
<?php foreach ($actions as $a): ?>
<li>
<a href="<?= $this->url($a[2]) ?>">
<?= $this->icon($a[0]) ?>
<?= $this->escape($a[1]) ?>
</a>
</li>
<?php endforeach ?>
</ul>
</div>

View File

@ -1,7 +1,20 @@
<?php
// Sample permission:
$this->providePermission('director/templates', 'Allow to modify templates');
$this->providePermission('director/hosts/read', $this->translate('Allow to configure hosts'));
$this->providePermission('director/hosts/write', $this->translate('Allow to configure hosts'));
$this->providePermission('director/templates/read', $this->translate('Allow to see template details'));
$this->providePermission('director/templates/write', $this->translate('Allow to configure templates'));
$this->provideRestriction(
'director/hosttemplates/filter',
$this->translate('Allow to use only host templates matching this filter')
);
$this->provideRestriction(
'director/dbresources/use',
$this->translate('Allow to use only these db resources (comma separated list)')
);
$this->provideConfigTab('config', array(
'title' => 'Configuration',
@ -12,9 +25,10 @@ $section = $this->menuSection(
$this->translate('Icinga Director')
)->setIcon('cubes');
$section->add($this->translate('Overview'))->setUrl('director/welcome')->setPriority(20);
$section->add($this->translate('Global'))->setUrl('director/commands');
$section->add($this->translate('Hosts'))->setUrl('director/hosts');
$section->add($this->translate('Fields'))->setUrl('director/field/host');
$section->add($this->translate('Fields'))->setUrl('director/field/host')->setPriority(903);
$section->add($this->translate('Services'))->setUrl('director/services');
$section->add($this->translate('Users'))->setUrl('director/users');
$section->add($this->translate('Import / Sync'))

View File

@ -45,12 +45,17 @@ abstract class CustomVariable implements IcingaConfigRenderer
}
// TODO: implement delete()
public function hasBeenDeleted()
{
return $this->deleted;
}
public function delete()
{
$this->deleted = true;
return $this;
}
// TODO: abstract
public function getDbValue()
{

View File

@ -89,7 +89,12 @@ class CustomVariables implements Iterator, Countable, IcingaConfigRenderer
protected function refreshIndex()
{
$this->idx = array_keys($this->vars);
$this->idx = array();
foreach ($this->vars as $name => $var) {
if (! $var->hasBeenDeleted()) {
$this->idx[] = $name;
}
}
}
public static function loadForStoredObject(IcingaObject $object)
@ -169,10 +174,18 @@ class CustomVariables implements Iterator, Countable, IcingaConfigRenderer
public function setUnmodified()
{
$this->modified = false;
$this->storedVars = $this->vars;
$this->storedVars = array();
foreach ($this->vars as $key => $var) {
$this->storedVars[$key] = clone($var);
}
return $this;
}
public function getOriginalVars()
{
return $this->storedVars;
}
public function toConfigString()
{
$out = '';
@ -223,10 +236,11 @@ class CustomVariables implements Iterator, Countable, IcingaConfigRenderer
public function __unset($key)
{
if (! array_key_exists($key, $this->vars)) {
throw new Exception('Trying to unset invalid key');
return;
}
unset($this->vars[$key]);
$this->vars[$key]->delete();
$this->modified = true;
$this->refreshIndex();
}

View File

@ -2,9 +2,11 @@
namespace Icinga\Module\Director\DataType;
use Exception;
use Icinga\Data\Db\DbConnection;
use Icinga\Module\Director\Web\Form\QuickForm;
use Icinga\Module\Director\Web\Hook\DataTypeHook;
use Icinga\Data\Db\DbConnection;
use Icinga\Module\Director\Util;
class DataTypeSqlQuery extends DataTypeHook
{
@ -16,11 +18,22 @@ class DataTypeSqlQuery extends DataTypeHook
public function getFormElement($name, QuickForm $form)
{
try {
$data = $this->fetchData();
$error = false;
} catch (Exception $e) {
$data = array();
$error = sprintf($form->translate('Unable to fetch data: %s'), $e->getMessage());
}
$element = $form->createElement('select', $name, array(
'multiOptions' => array(null => '- please choose -') +
$this->fetchData(),
'multiOptions' => $form->optionalEnum($data),
));
if ($error) {
$element->addError($error);
}
return $element;
}
@ -36,17 +49,13 @@ class DataTypeSqlQuery extends DataTypeHook
public static function addSettingsFormFields(QuickForm $form)
{
$db = $form->getDb();
$form->addElement('text', 'resource', array(
'label' => 'Resource name',
'required' => true,
));
Util::addDbResourceFormElement($form, 'resource');
$form->addElement('textarea', 'query', array(
'label' => 'DB Query',
'description' => 'This query should return exactly two columns, value and label',
'required' => true,
'rows' => 10,
));
return $form;

View File

@ -85,50 +85,51 @@ class Db extends DbConnection
return $db->fetchOne($query);
}
public function fetchHostTemplateTree()
public function fetchTemplateTree($type)
{
$db = $this->db();
$query = $db->select()->from(
array('ph' => 'icinga_host'),
array('p' => 'icinga_' . $type),
array(
'host' => 'h.object_name',
'parent' => 'ph.object_name'
'name' => 'o.object_name',
'parent' => 'p.object_name'
)
)->join(
array('hi' => 'icinga_host_inheritance'),
'ph.id = hi.parent_host_id',
array('i' => 'icinga_' . $type . '_inheritance'),
'p.id = i.parent_' . $type . '_id',
array()
)->join(
array('h' => 'icinga_host'),
'h.id = hi.host_id',
array('o' => 'icinga_' . $type),
'o.id = i.' . $type . '_id',
array()
)->where("h.object_type = 'template'")
->order('ph.object_name')
->order('h.object_name');
)->where("o.object_type = 'template'")
->order('p.object_name')
->order('o.object_name');
$relations = $db->fetchAll($query);
$children = array();
$hosts = array();
$objects = array();
foreach ($relations as $rel) {
foreach (array('host', 'parent') as $col) {
if (! array_key_exists($rel->$col, $hosts)) {
$hosts[$rel->$col] = (object) array(
foreach (array('name', 'parent') as $col) {
if (! array_key_exists($rel->$col, $objects)) {
$objects[$rel->$col] = (object) array(
'name' => $rel->$col,
'children' => array()
);
}
}
}
foreach ($relations as $rel) {
$hosts[$rel->parent]->children[$rel->host] = $hosts[$rel->host];
$children[$rel->host] = $rel->parent;
$objects[$rel->parent]->children[$rel->name] = $objects[$rel->name];
$children[$rel->name] = $rel->parent;
}
foreach ($children as $name => $host) {
unset($hosts[$name]);
foreach ($children as $name => $object) {
unset($objects[$name]);
}
return $hosts;
return $objects;
}
public function fetchLatestImportedRows($source, $columns = null)

View File

@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Import;
use Icinga\Module\Director\Util;
use Icinga\Module\Director\Web\Form\QuickForm;
use Icinga\Module\Director\Web\Hook\ImportSourceHook;
use Icinga\Data\Db\DbConnection;
@ -23,13 +24,11 @@ class ImportSourceSql extends ImportSourceHook
public static function addSettingsFormFields(QuickForm $form)
{
$form->addElement('text', 'resource', array(
'label' => 'Resource name',
'required' => true,
));
Util::addDbResourceFormElement($form, 'resource');
$form->addElement('textarea', 'query', array(
'label' => 'DB Query',
'required' => true,
'rows' => 15,
));
return $form;
}

View File

@ -5,7 +5,7 @@ namespace Icinga\Module\Director\Objects;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Util;
use Icinga\Authentication\Manager as Auth;
use Icinga\Authentication\Auth;
class DirectorActivityLog extends DbObject
{
@ -39,6 +39,59 @@ class DirectorActivityLog extends DbObject
}
}
protected static function prepareNewObjectProperties(DbObject $object)
{
$props = $object->getProperties();
if ($object->supportsCustomVars()) {
// $props->vars = $object->vars()->toJson();
}
if ($object->supportsGroups()) {
$props['groups'] = $object->groups()->listGroupNames();
}
if ($object->supportsCustomVars()) {
$props['vars'] = $object->getVars();
}
return json_encode($props);
}
protected static function prepareModifiedProperties(DbObject $object)
{
$props = $object->getModifiedProperties();
if ($object->supportsCustomVars()) {
$mod = array();
foreach ($object->vars() as $name => $var) {
if ($var->hasBeenModified()) {
$mod[$name] = $var->getValue();
}
}
if (! empty($mod)) {
$props['vars'] = (object) $mod;
}
}
if ($object->supportsGroups()) {
// $props['groups'] = $object->groups()->listGroupNames();
}
return json_encode($props);
}
protected static function prepareOriginalProperties(DbObject $object)
{
$props = $object->getModifiedProperties();
if ($object->supportsCustomVars()) {
$props['vars'] = (object) array();
foreach ($object->vars()->getOriginalVars() as $name => $var) {
$props['vars']->$name = $var->getValue();
}
}
if ($object->supportsGroups()) {
// $props['groups'] = $object->groups()->listGroupNames();
}
return json_encode($props);
}
public static function logCreation(DbObject $object, Db $db)
{
$data = array(
@ -46,7 +99,7 @@ class DirectorActivityLog extends DbObject
'action_name' => 'create',
'author' => self::username(),
'object_type' => $object->getTableName(),
'new_properties' => json_encode($object->getProperties()),
'new_properties' => self::prepareNewObjectProperties($object),
'change_time' => date('Y-m-d H:i:s'), // TODO -> postgres!
'parent_checksum' => $db->getLastActivityChecksum()
);
@ -63,8 +116,8 @@ class DirectorActivityLog extends DbObject
'action_name' => 'modify',
'author' => self::username(),
'object_type' => $object->getTableName(),
'old_properties' => json_encode($object->getOriginalProperties()),
'new_properties' => json_encode($object->getModifiedProperties()),
'old_properties' => self::prepareOriginalProperties($object),
'new_properties' => self::prepareModifiedProperties($object),
'change_time' => date('Y-m-d H:i:s'), // TODO -> postgres!
'parent_checksum' => $db->getLastActivityChecksum()
);

View File

@ -23,7 +23,6 @@ class DirectorDatafield extends DbObject
protected $settings = array();
public function set($key, $value)
{
if ($this->hasProperty($key)) {
@ -33,6 +32,7 @@ class DirectorDatafield extends DbObject
if (! array_key_exists($key, $this->settings) || $value !== $this->settings[$key]) {
$this->hasBeenModified = true;
}
$this->settings[$key] = $value;
return $this;
}
@ -50,6 +50,20 @@ class DirectorDatafield extends DbObject
return parent::get($key);
}
public function __unset($key)
{
if ($this->hasProperty($key)) {
return parent::__set($key, $value);
}
if (array_key_exists($key, $this->settings)) {
unset($this->settings[$key]);
$this->hasBeenModified = true;
}
return $this;
}
public function getSettings()
{
return $this->settings;
@ -100,7 +114,7 @@ class DirectorDatafield extends DbObject
}
foreach ($del as $key) {
$db->update(
$db->delete(
'director_datafield_setting',
$db->quoteInto($where, $key)
);

View File

@ -43,6 +43,8 @@ class IcingaHost extends IcingaObject
protected $supportsImports = true;
protected $supportsFields = true;
protected function renderCheck_command_id()
{
return $this->renderCommandProperty($this->check_command_id);
@ -82,22 +84,4 @@ class IcingaHost extends IcingaObject
{
return $this->renderBooleanProperty('volatile');
}
public function getFields(DirectorObjectForm $form)
{
$db = $this->getDb();
$query = $db->select()
->from(
array('df' => 'director_datafield')
)
->join(
array('hf' => 'icinga_host_field'),
'df.id = hf.datafield_id'
)
->where('hf.host_id = ?', (int) $this->id)
->order('df.caption ASC');
return $db->fetchAll($query);
}
}

View File

@ -23,6 +23,8 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
protected $supportsImports = false;
protected $supportsFields = false;
private $type;
private $vars;
@ -55,6 +57,11 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return $this->supportsImports;
}
public function supportsFields()
{
return $this->supportsFields;
}
public function hasBeenModified()
{
if ($this->supportsCustomVars() && $this->vars !== null && $this->vars()->hasBeenModified()) {
@ -132,37 +139,143 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return $this->importedObjects;
}
public function clearImportedObjects()
{
$this->importedObjects = null;
return $this;
}
public function getResolvedProperties()
{
$res = $this->resolveProperties();
return $res['_MERGED_'];
return $this->getResolved('Properties');
}
public function getInheritedProperties()
{
return $this->getInherited('Properties');
}
public function getOriginsProperties()
{
return $this->getOrigins('Properties');
}
public function resolveProperties()
{
$props = array();
$props['_MERGED_'] = (object) array();
return $this->resolve('Properties');
}
public function getResolvedFields()
{
return $this->getResolved('Fields');
}
public function getInheritedFields()
{
return $this->getInherited('Fields');
}
public function getOriginsFields()
{
return $this->getOrigins('Fields');
}
public function resolveFields()
{
return $this->resolve('Fields');
}
public function getResolvedVars()
{
return $this->getResolved('Vars');
}
public function getInheritedVars()
{
return $this->getInherited('Vars');
}
public function resolveVars()
{
return $this->resolve('Vars');
}
public function getOriginsVars()
{
return $this->getOrigins('Vars');
}
public function getVars()
{
$vars = (object) array();
foreach ($this->vars() as $key => $var) {
$vars->$key = $var->getValue();
}
return $vars;
}
protected function getResolved($what)
{
$func = 'resolve' . $what;
$res = $this->$func();
return $res['_MERGED_'];
}
protected function getInherited($what)
{
$func = 'resolve' . $what;
$res = $this->$func();
return $res['_INHERITED_'];
}
protected function getOrigins($what)
{
$func = 'resolve' . $what;
$res = $this->$func();
return $res['_ORIGINS_'];
}
protected function resolve($what)
{
$vals = array();
$vals['_MERGED_'] = (object) array();
$vals['_INHERITED_'] = (object) array();
$vals['_ORIGINS_'] = (object) array();
$objects = $this->importedObjects();
$objects[$this->object_name] = $this;
$blacklist = array('id', 'object_type', 'object_name');
$get = 'get' . $what;
$getInherited = 'getInherited' . $what;
$getOrigins = 'getOrigins' . $what;
foreach ($objects as $name => $object) {
$props[$name] = (object) array();
if ($name === $this->object_name) {
$pprops = $object->getProperties();
} else {
$pprops = $object->getResolvedProperties();
$origins = $object->$getOrigins();
foreach ($object->$getInherited() as $key => $value) {
// $vals[$name]->$key = $value;
$vals['_MERGED_']->$key = $value;
$vals['_INHERITED_']->$key = $value;
$vals['_ORIGINS_']->$key = $origins->$key;
}
foreach ($pprops as $key => $value) {
if (in_array($key, $blacklist)) continue;
if ($value !== null) {
$props[$name]->$key = $value;
$props['_MERGED_']->$key = $value;
}
foreach ($object->$get() as $key => $value) {
if ($value === null) continue;
$vals['_MERGED_']->$key = $value;
$vals['_INHERITED_']->$key = $value;
$vals['_ORIGINS_']->$key = $name;
}
}
return $props;
$blacklist = array('id', 'object_type', 'object_name');
foreach ($this->$get() as $key => $value) {
if ($value === null) continue;
if (in_array($key, $blacklist)) continue;
// $vals[$this->object_name]->$key = $value;
$vals['_MERGED_']->$key = $value;
}
return $vals;
}
protected function assertCustomVarsSupport()
@ -243,6 +356,39 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return $this->getShortTableName() . '_id';
}
public function getFields()
{
$fields = (object) array();
if (! $this->supportsFields()) {
return $fields;
}
$db = $this->getDb();
$query = $db->select()->from(
array('df' => 'director_datafield'),
array(
'datafield_id' => 'f.datafield_id',
'is_required' => 'f.is_required',
'varname' => 'df.varname'
)
)->join(
array('f' => $this->getTableName() . '_field'),
'df.id = f.datafield_id',
array()
)->where('f.' . $this->getShortTableName() . '_id = ?', (int) $this->id)
->order('df.caption ASC');
$res = $db->fetchAll($query);
foreach ($res as $r) {
$fields->{$r->varname} = $r;
}
return $fields;
}
public function isTemplate()
{
return $this->hasProperty('object_type')

View File

@ -158,19 +158,9 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
if ($import instanceof $class) {
$this->imports[$import->object_name] = $import;
} elseif (is_string($import)) {
$query = $this->object->getDb()->select()->from(
$this->object->getTableName()
)->where('object_name = ?', $import);
$imports = $class::loadAll($connection, $query, 'object_name');
$import = $class::load($import, $connection);
$this->imports[$import->object_name] = $import;
}
if (! array_key_exists($import, $imports)) {
throw new ProgrammingError(
'The import "%s" doesn\'t exists.',
$import
);
}
$this->imports[$import] = $imports[$import];
$this->modified = true;
$this->refreshIndex();

View File

@ -38,6 +38,8 @@ class IcingaService extends IcingaObject
protected $supportsCustomVars = true;
protected $supportsFields = true;
protected $supportsImports = true;
protected function renderCheck_command_id()

View File

@ -2,13 +2,21 @@
namespace Icinga\Module\Director;
use Icinga\Authentication\Auth;
use Icinga\Data\ResourceFactory;
use Icinga\Module\Director\Web\Form\QuickForm;
use Icinga\Web\Url;
use Zend_Db_Expr;
class Util
{
protected static $auth;
protected static $allowedDbResources;
public static function pgBinEscape($binary)
{
return new \Zend_Db_Expr("'\\x" . bin2hex($binary) . "'");
return new Zend_Db_Expr("'\\x" . bin2hex($binary) . "'");
}
public static function hex2binary($bin)
@ -20,4 +28,84 @@ class Util
{
return current(unpack('H*', $hex));
}
public static function auth()
{
if (self::$auth === null) {
self::$auth = Auth::getInstance();
}
return self::$auth;
}
public static function hasPermission($name)
{
return self::auth()->hasPermission($name);
}
public static function getRestrictions($name)
{
return self::auth()->getRestrictions($name);
}
public static function dbResourceIsAllowed($name)
{
if (self::$allowedDbResources === null) {
$restrictions = self::getRestrictions('director/dbresources/use');
$list = array();
foreach ($restrictions as $restriction) {
foreach (preg_split('/\s*,\s*/', $restriction, -1, PREG_SPLIT_NO_EMPTY) as $key) {
$list[$key] = $key;
}
}
self::$allowedDbResources = $list;
} else {
$list = self::$allowedDbResources;
}
if (empty($list) || array_key_exists($name, $list)) {
return true;
}
return false;
}
public static function enumDbResources()
{
$resources = array();
foreach (ResourceFactory::getResourceConfigs() as $name => $resource) {
if ($resource->type === 'db' && self::dbResourceIsAllowed($name)) {
$resources[$name] = $name;
}
}
return $resources;
}
public static function addDbResourceFormElement(QuickForm $form, $name)
{
$list = Util::enumDbResources();
$form->addElement('select', $name, array(
'label' => 'Resource name',
'multiOptions' => $form->optionalEnum($list),
'required' => true,
));
if (true && empty($list)) {
if (self::hasPermission('config/application/resources')) {
$hint = $form->translate('Please click %s to create new DB resources');
$link = sprintf(
'<a href="' . Url::fromPath('config/resource') . '" data-base-target="_main">%s</a>',
$form->translate('here')
);
$form->addHtmlHint(sprintf($hint, $link));
$msg = $form->translate('No db resource available');
} else {
$msg = $form->translate('Please ask an administrator to grant you access to DB resources');
}
$form->getElement($name)->addError($msg);
}
}
}

View File

@ -16,18 +16,18 @@ abstract class ObjectController extends ActionController
if ($name = $this->params->get('name')) {
$params['name'] = $name;
$this->getTabs()->add($type, array(
'url' => sprintf('director/%s', $ltype),
'urlParams' => $params,
'label' => $this->translate(ucfirst($ltype)),
))->add('modify', array(
$this->getTabs()->add('modify', array(
'url' => sprintf('director/%s/edit', $ltype),
'urlParams' => $params,
'label' => $this->translate('Modify')
'label' => $this->translate(ucfirst($ltype))
))->add('delete', array(
'url' => sprintf('director/%s/delete', $ltype),
'urlParams' => $params,
'label' => $this->translate('Delete')
))->add('render', array(
'url' => sprintf('director/%s/render', $ltype),
'urlParams' => $params,
'label' => $this->translate('Preview'),
))->add('history', array(
'url' => sprintf('director/%s/history', $ltype),
'urlParams' => $params,
@ -35,16 +35,21 @@ abstract class ObjectController extends ActionController
));
} else {
$this->getTabs()->add('add', array(
'url' => sprintf('director/%s', $type),
'url' => sprintf('director/%s/add', $type),
'label' => sprintf($this->translate('Add %s'), ucfirst($type)),
));
}
}
public function indexAction()
{
return $this->editAction();
}
public function renderAction()
{
$type = $this->getType();
$this->getTabs()->activate($type);
$this->getTabs()->activate('render');
$this->view->object = $this->object();
$this->render('object/show', null, true);
}
@ -80,17 +85,22 @@ abstract class ObjectController extends ActionController
'icinga' . ucfirst($type)
)->setDb($this->db());
$form->loadObject($this->params->get('name'));
$object = $form->getObject();
$url = Url::fromPath(
sprintf('director/%s', $ltype),
array('name' => $form->getObject()->object_name)
array('name' => $object->object_name)
);
$form->setSuccessUrl($url);
$this->view->title = sprintf(
$this->translate('Modify Icinga %s'),
ucfirst($ltype)
);
if ($object->isTemplate()) {
$title = $this->translate('Modify Icinga %s template');
$form->setObjectType('template'); // WHY??
} else {
$title = $this->translate('Modify Icinga %s');
}
$this->view->title = sprintf($title, ucfirst($ltype));
$this->view->form->handleRequest();
$this->render('object/form', null, true);
}
@ -102,15 +112,19 @@ abstract class ObjectController extends ActionController
$ltype = strtolower($type);
$url = sprintf('director/%ss', $ltype);
$this->view->form = $this->loadForm('icinga' . ucfirst($type))
$form = $this->view->form = $this->loadForm('icinga' . ucfirst($type))
->setDb($this->db())
->setSuccessUrl($url);
$this->view->title = sprintf(
$this->translate('Add new Icinga %s'),
ucfirst($ltype)
);
$this->view->form->handleRequest();
if ($this->params->get('type') === 'template') {
$form->setObjectType('template');
$title = $this->translate('Add new Icinga %s template');
} else {
$title = $this->translate('Add new Icinga %s');
}
$this->view->title = sprintf($title, ucfirst($ltype));
$form->handleRequest();
$this->render('object/form', null, true);
}

View File

@ -16,14 +16,12 @@ abstract class ObjectsController extends ActionController
public function init()
{
$tabs = $this->getTabs();
$type = $this->getType();
$ltype = strtolower($type);
$object = $this->dummyObject();
if (in_array(ucfirst($type), $this->globalTypes)) {
$ltype = strtolower($type);
$tabs = $this->getTabs();
foreach ($this->globalTypes as $tabType) {
$ltabType = strtolower($tabType);
$tabs->add($ltabType, array(
@ -33,67 +31,98 @@ abstract class ObjectsController extends ActionController
}
$tabs->activate($ltype);
} elseif ($object->isGroup()) {
$singleType = substr($type, 0, -5);
$tabs = $this->getTabs()->add('objects', array(
'url' => sprintf('director/%ss', $singleType),
'label' => $this->translate(ucfirst($singleType) . 's'),
));
$tabs->add('objectgroups', array(
'url' => sprintf('director/%ss', strtolower($type)),
'label' => $this->translate(ucfirst(strtolower($type)) . 's')
));
} else {
$tabs = $this->getTabs()->add('objects', array(
'url' => sprintf('director/%ss', strtolower($type)),
'label' => $this->translate(ucfirst($type) . 's'),
));
if ($object->supportsGroups()) {
$tabs->add('objectgroups', array(
'url' => sprintf('director/%sgroups', $type),
'label' => $this->translate(ucfirst($type) . 'groups')
));
}
return;
}
$object = $this->dummyObject();
if ($object->isGroup()) {
$type = substr($type, 0, -5);
}
$tabs = $this->getTabs()->add('objects', array(
'url' => sprintf('director/%ss', strtolower($type)),
'label' => $this->translate(ucfirst($type) . 's'),
));
$tabs = $this->getTabs()->add('objecttemplates', array(
'url' => sprintf('director/%stemplates', strtolower($type)),
'label' => $this->translate('Templates'),
));
if ($object->supportsGroups() || $object->isGroup()) {
$tabs->add('objectgroups', array(
'url' => sprintf('director/%sgroups', $type),
'label' => $this->translate('Groups')
));
}
$tabs->add('tree', array(
'url' => sprintf('director/%stemplates/tree', $type),
'label' => $this->translate('Tree'),
));
}
public function indexAction()
{
$type = $this->getType();
$ltype = strtolower($type);
$dummy = $this->dummyObject();
if (! in_array($type, $this->globalTypes)) {
if ($this->dummyObject()->isGroup()) {
if ($dummy->isGroup()) {
$this->getTabs()->activate('objectgroups');
$table = 'icinga' . ucfirst($type);
} elseif ($dummy->isTemplate()) {
$this->getTabs()->activate('objecttemplates');
$table = 'icinga' . ucfirst($type);
$this->loadTable($table);
$table = 'icinga' . ucfirst($type) . 'Template';
} else {
$this->getTabs()->activate('objects');
$table = 'icinga' . ucfirst($type);
}
} else {
$table = 'icinga' . ucfirst($type);
}
if ($dummy->isTemplate()) {
$addParams = array('type' => 'template');
$addTitle = $this->translate('Add %s template');
} else {
$addParams = array();
$addTitle = $this->translate('Add %s');
}
$this->view->addLink = $this->view->qlink(
$this->translate('Add ' . ucfirst($ltype)),
'director/' . $ltype . '/add'
sprintf($addTitle, $this->translate(ucfirst($ltype))),
'director/' . $ltype .'/add',
$addParams
);
$this->view->title = $this->translate('Icinga ' . ucfirst($ltype));
$table = $this->loadTable('icinga' . ucfirst($type))->setConnection($this->db());
$table = $this->loadTable($table)->setConnection($this->db());
$this->setupFilterControl($table->getFilterEditor($this->getRequest()));
$this->view->table = $this->applyPaginationLimits($table);
$this->render('objects/table', null, true);
}
public function treeAction()
{
$this->getTabs()->activate('tree');
$this->view->tree = $this->db()->fetchTemplateTree(strtolower($this->getType()));
}
protected function dummyObject()
{
if ($this->dummy === null) {
$class = $this->getObjectClassname();
$this->dummy = $class::create(array());
if ($this->dummy->hasProperty('object_type')) {
if (false === strpos($this->getRequest()->getControllerName(), 'template')) {
$this->dummy->object_type = 'object';
} else {
$this->dummy->object_type = 'template';
}
}
}
return $this->dummy;
@ -105,7 +134,11 @@ abstract class ObjectsController extends ActionController
return preg_replace(
array('/group$/', '/period$/', '/argument$/'),
array('Group', 'Period', 'Argument'),
substr($this->getRequest()->getControllerName(), 0, -1)
str_replace(
'template',
'',
substr($this->getRequest()->getControllerName(), 0, -1)
)
);
}

View File

@ -3,6 +3,8 @@
namespace Icinga\Module\Director\Web\Form;
use Icinga\Module\Director\Objects\IcingaObject;
use Icinga\Module\Director\Objects\DirectorDatafield;
use Zend_Form_Element_Select as Zf_Select;
abstract class DirectorObjectForm extends QuickForm
{
@ -10,10 +12,12 @@ abstract class DirectorObjectForm extends QuickForm
protected $object;
private $objectName;
protected $objectName;
private $className;
private $objectType = 'object';
protected function object($values = array())
{
if ($this->object === null) {
@ -37,49 +41,124 @@ abstract class DirectorObjectForm extends QuickForm
return;
}
if ($object->supportsCustomVars()) {
$this->addElement('note', '_newvar_hint', array('label' => 'New custom variable'));
$this->addElement('text', '_newvar_name', array(
'label' => 'Name'
));
$this->addElement('text', '_newvar_value', array(
'label' => 'Value'
));
$this->addElement('select', '_newvar_format', array(
'label' => 'Type',
'multiOptions' => array('string' => $this->translate('String'))
));
}
protected function isTemplate()
{
return $this->objectType === 'template';
}
protected function handleImports($object, & $values)
{
if (! $object->supportsImports()) {
return;
}
if (false && $object->supportsRanges()) {
/* TODO implement when new logic is there
$this->addElement('note', '_newrange_hint', array('label' => 'New range'));
$this->addElement('text', '_newrange_name', array(
'label' => 'Name'
));
$this->addElement('text', '_newrange_value', array(
'label' => 'Value'
));
*/
if (array_key_exists('imports', $values)) {
$value = $values['imports'];
unset($values['imports']);
$object->clearImportedObjects();
$object->imports()->set($value);
}
$el = $this->getElement('imports');
if ($el) {
$el->setMultiOptions($this->enumAllowedTemplates());
$el->setValue($object->imports()->listImportNames());
}
}
protected function handleIcingaObject(& $values)
protected function handleRanges($object, & $values)
{
$object = $this->object();
$handled = array();
if ($object->supportsGroups()) {
if (array_key_exists('groups', $values)) {
$object->groups()->set(
preg_split('/\s*,\s*/', $values['groups'], -1, PREG_SPLIT_NO_EMPTY)
);
$handled['groups'] = true;
}
if (! $object->supportsRanges()) {
return;
}
if ($this->object->supportsCustomVars()) {
$key = 'ranges';
$object = $this->object();
/* Sample:
array(
'monday' => 'eins',
'tuesday' => '00:00-24:00',
'sunday' => 'zwei',
);
*/
if (array_key_exists($key, $values)) {
$object->ranges()->set($values[$key]);
unset($values[$key]);
}
foreach ($object->ranges()->getRanges() as $key => $value) {
$this->addRange($key, $value);
}
/*
// TODO implement when new logic is there
$this->addElement('note', '_newrange_hint', array('label' => 'New range'));
$this->addElement('text', '_newrange_name', array(
'label' => 'Name'
));
$this->addElement('text', '_newrange_value', array(
'label' => 'Value'
));
*/
}
protected function handleGroups($object, & $values)
{
if (! $object->supportsGroups()) {
return;
}
if (array_key_exists('groups', $values)) {
$value = $values['groups'];
unset($values['groups']);
// TODO: Drop this once we have arrays everwhere
if (is_string($value)) {
$value = preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
}
$object->groups()->set($value);
}
}
protected function handleProperties($object, & $values)
{
if ($this->hasBeenSent()) {
$object->setProperties($values);
}
$props = $object->getProperties();
if (! $object instanceof IcingaObject) {
$this->setDefaults($props);
return $this;
}
$inherited = $object->getInheritedProperties();
$origins = $object->getOriginsProperties();
foreach ($props as $k => $v) {
if (property_exists($inherited, $k)) {
$this->setElementValue($k, $v, $inherited->$k, $origins->$k);
} else {
$this->setElementValue($k, $v);
}
}
}
protected function handleCustomVars($object, & $values)
{
if (! $object->supportsCustomVars()) {
return;
}
if ($this->hasBeenSent()) {
$vars = array();
$handled = array();
$newvar = array(
'type' => 'string',
'name' => null,
@ -99,62 +178,160 @@ abstract class DirectorObjectForm extends QuickForm
}
foreach ($vars as $k => $v) {
$this->object->vars()->$k = $v;
if ($v === '' || $v === null) {
unset($object->vars()->$k);
} else {
$object->vars()->$k = $v;
}
}
if ($newvar['name'] && $newvar['value']) {
$this->object->vars()->{$newvar['name']} = $newvar['value'];
$object->vars()->{$newvar['name']} = $newvar['value'];
}
foreach ($handled as $key) {
unset($values[$key]);
}
}
if ($object->supportsImports()) {
if (array_key_exists('imports', $values)) {
$object->imports()->set(
preg_split('/\s*,\s*/', $values['imports'], -1, PREG_SPLIT_NO_EMPTY)
);
$handled['imports'] = true;
$vars = $object->getVars();
$fields = $object->getResolvedFields();
$inherits = $object->getInheritedVars();
$origins = $object->getOriginsVars();
foreach ($fields as $field) {
$varname = $field->varname;
// Get value from the related varname if set:
if (property_exists($vars, $varname)) {
$value = $vars->$varname;
} else {
$value = null;
}
if (property_exists($inherits, $varname)) {
$inheritedValue = $inherits->$varname;
$inheritFrom = $origins->$varname;
if ($inheritFrom === $object->object_name) {
$inherited = false;
} else {
$inherited = true;
}
} else {
$inheritedValue = null;
$inheritFrom = false;
$inherited = false;
}
$this->addField($field, $value, $inheritedValue, $inheritFrom);
}
if ($object->supportsRanges()) {
$object->ranges()->set(array(
'monday' => 'eins',
'tuesday' => '00:00-24:00',
'sunday' => 'zwei',
// Additional vars
foreach ($vars as $key => $value) {
// Did we already create a field for this var? Then skip it:
if (array_key_exists($key, $fields)) {
continue;
}
// Show inheritance information in case we inherited this var:
if (isset($inherited->$key)) {
$this->addCustomVar($key, $value, $inherited->$key, $origins->$key);
} else {
$this->addCustomVar($key, $value);
}
}
if ($object->isTemplate()) {
$this->addHtml('<h3>Add a custom variable</h3>');
$this->addElement('text', '_newvar_name', array(
'label' => 'Name'
));
$this->addElement('text', '_newvar_value', array(
'label' => 'Value'
));
$this->addElement('select', '_newvar_format', array(
'label' => 'Type',
'multiOptions' => array('string' => $this->translate('String'))
));
}
}
foreach ($handled as $key => $value) {
unset($values[$key]);
public function setObjectType($type)
{
$this->objectType = $type;
return $this;
}
protected function addField($field, $value = null, $inherited = null, $inheritedFrom = null)
{
$datafield = DirectorDatafield::load($field->datafield_id, $this->getDb());
$datatype = new $datafield->datatype;
$datatype->setSettings($datafield->getSettings());
$name = 'var_' . $datafield->varname;
$el = $datatype->getFormElement($name, $this);
$el->setLabel($datafield->caption);
$el->setDescription($datafield->description);
if ($field->is_required === 'y' && ! $this->isTemplate()) {
$el->setRequired(true);
}
$this->addElement($el);
$this->setElementValue($name, $value, $inherited, $inheritedFrom);
return $el;
}
protected function setElementValue($name, $value = null, $inherited = null, $inheritedFrom = null)
{
$el = $this->getElement($name);
if (! $el) {
return;
}
if ($value !== null) {
$el->setValue($value);
}
if ($inherited === null || empty($inherited)) {
return;
}
if ($el instanceof Zf_Select) {
$multi = $el->getMultiOptions();
if (array_key_exists($inherited, $multi)) {
$multi[null] = $multi[$inherited] . sprintf(' (%s)', $inheritedFrom);
} else {
$multi[null] = $this->translate('- inherited -');
}
$el->setMultiOptions($multi);
} else {
$el->setAttrib('placeholder', $inherited . sprintf(' (%s)', $inheritedFrom));
}
}
public function onSuccess()
{
$object = $this->object;
$values = $this->getValues();
if ($object instanceof IcingaObject) {
$this->handleIcingaObject($values);
$object = $this->object();
if ($object->hasBeenModified()) {
$msg = sprintf(
$object->hasBeenLoadedFromDb()
? $this->translate('The %s has successfully been stored')
: $this->translate('A new %s has successfully been created'),
$this->translate($this->getObjectName())
);
$object->store($this->db);
} else {
$msg = $this->translate('No action taken, object has not been modified');
}
$object->setProperties($values);
$msg = sprintf(
$object->hasBeenLoadedFromDb()
? 'The Icinga %s has successfully been stored'
: 'A new Icinga %s has successfully been created',
$this->translate($this->getObjectName())
);
$object->store($this->db);
$this->redirectOnSuccess($msg);
}
protected function optionalEnum($enum)
{
return array(
null => $this->translate('- please choose -')
) + $enum;
}
protected function optionalBoolean($key, $label, $description)
{
return $this->addElement('select', $key, array(
@ -202,65 +379,55 @@ abstract class DirectorObjectForm extends QuickForm
return $this->objectName;
}
protected function onRequest()
{
$object = $this->object();
$values = array();
if ($this->hasBeenSent()) {
$post = $this->getRequest()->getPost();
foreach ($post as $key => $value) {
$el = $this->getElement($key);
if ($el && ! $el->getIgnore()) {
$values[$key] = $value;
}
}
}
if ($object instanceof IcingaObject) {
if (! $object->hasBeenLoadedFromDb()) {
$object->object_type = $this->objectType;
}
$this->handleImports($object, $values);
$this->handleCustomVars($object, $values);
$this->handleGroups($object, $values);
$this->handleRanges($object, $values);
}
$this->handleProperties($object, $values);
$this->moveSubmitToBottom();
}
public function loadObject($id)
{
$this->prepareElements();
$class = $this->getObjectClassname();
$this->object = $class::load($id, $this->db);
// TODO: hmmmm...
if (! is_array($id)) {
$this->addHidden('id');
}
$this->setDefaults($this->object->getProperties());
if (! $this->object instanceof IcingaObject) {
return $this;
}
if ($submit = $this->getElement('submit')) {
$this->removeElement('submit');
}
if ($this->object->supportsGroups()) {
$this->getElement('groups')->setValue(
implode(', ', $this->object->groups()->listGroupNames())
);
}
if ($this->object->supportsImports()) {
$this->getElement('imports')->setValue(
implode(', ', $this->object->imports()->listImportNames())
);
}
if ($this->object->supportsCustomVars()) {
foreach ($this->object->vars() as $key => $value) {
$this->addCustomVar($key, $value);
}
}
if ($this->object->supportsRanges()) {
/* TODO implement when new logic for customvars is there
foreach ($this->object->ranges()->getRanges() as $key => $value) {
$this->addRange($key, $value);
}
*/
}
if ($submit) {
$this->addElement($submit);
}
if (! $this->hasBeenSubmitted()) {
$this->beforeValidation($this->object->getProperties());
}
return $this;
}
protected function addCustomVar($key, $range)
protected function addCustomVar($key, $value, $inherited = null, $inheritedFrom = null)
{
$this->addElement('text', 'var_' . $key, array(
'label' => 'vars.' . $key,
'value' => $range->getValue()
));
$label = 'vars.' . $key;
$key = 'var_' . $key;
$this->addElement('text', $key, array('label' => $label));
$this->setElementValue($key, $value, $inherited, $inheritedFrom);
}
protected function addRange($key, $range)
@ -282,55 +449,102 @@ abstract class DirectorObjectForm extends QuickForm
if ($this->object !== null) {
$this->object->setConnection($db);
}
if ($this->hasElement('parent_zone_id')) {
$this->getElement('parent_zone_id')
->setMultiOptions($this->optionalEnum($db->enumZones()));
}
if ($this->hasElement('host_id')) {
$this->getElement('host_id')
->setMultiOptions($this->optionalEnum($db->enumHosts()));
}
if ($this->hasElement('hostgroup_id')) {
$this->getElement('hostgroup_id')
->setMultiOptions($this->optionalEnum($db->enumHostgroups()));
}
if ($this->hasElement('service_id')) {
$this->getElement('service_id')
->setMultiOptions($this->optionalEnum($db->enumServices()));
}
if ($this->hasElement('servicegroup_id')) {
$this->getElement('servicegroup_id')
->setMultiOptions($this->optionalEnum($db->enumServicegroups()));
}
if ($this->hasElement('user_id')) {
$this->getElement('user_id')
->setMultiOptions($this->optionalEnum($db->enumUsers()));
}
if ($this->hasElement('usergroup_id')) {
$this->getElement('usergroup_id')
->setMultiOptions($this->optionalEnum($db->enumUsergroups()));
}
if ($this->hasElement('zone_id')) {
$this->getElement('zone_id')
->setMultiOptions($this->optionalEnum($db->enumZones()));
}
if ($this->hasElement('check_command_id')) {
$this->getElement('check_command_id')
->setMultiOptions($this->optionalEnum($db->enumCheckCommands()));
}
if ($this->hasElement('command_id')) {
$this->getElement('command_id')
->setMultiOptions($this->optionalEnum($db->enumCommands()));
}
return $this;
}
protected function addZoneElement()
{
$this->addElement('select', 'zone_id', array(
'label' => $this->translate('Cluster Zone'),
'description' => $this->translate('Icinga cluster zone'),
'multiOptions' => $this->optionalEnum($this->db->enumZones())
));
return $this;
}
protected function addImportsElement()
{
$this->addElement('multiselect', 'imports', array(
'label' => $this->translate('Imports'),
'description' => $this->translate('Importable templates'),
'multiOptions' => $this->enumAllowedTemplates(),
'class' => 'autosubmit'
));
return $this;
}
protected function addCheckExecutionElements()
{
$this->addHtml('<h3>Check execution</h3>');
$this->addElement('select', 'check_command_id', array(
'label' => $this->translate('Check command'),
'description' => $this->translate('Check command definition'),
'multiOptions' => $this->optionalEnum($this->db->enumCheckCommands())
));
$this->optionalBoolean(
'enable_active_checks',
$this->translate('Execute active checks'),
$this->translate('Whether to actively check this object')
);
$this->optionalBoolean(
'enable_passive_checks',
$this->translate('Accept passive checks'),
$this->translate('Whether to accept passive check results for this object')
);
$this->optionalBoolean(
'enable_notifications',
$this->translate('Send notifications'),
$this->translate('Whether to send notifications for this object')
);
$this->optionalBoolean(
'enable_event_handler',
$this->translate('Enable event handler'),
$this->translate('Whether to enable event handlers this object')
);
$this->optionalBoolean(
'enable_perfdata',
$this->translate('Process performance data'),
$this->translate('Whether to process performance data provided by this object')
);
$this->optionalBoolean(
'volatile',
$this->translate('Volatile'),
$this->translate('Whether this check is volatile.')
);
return $this;
}
protected function enumAllowedTemplates()
{
$object = $this->object();
$tpl = $this->db->enumIcingaTemplates($object->getShortTableName());
$tpl = array_combine($tpl, $tpl);
$id = $object->object_name;
if (array_key_exists($id, $tpl)) {
unset($tpl[$id]);
}
return $tpl;
}
private function dummyForTranslation()
{
$this->translate('Host');
$this->translate('Service');
$this->translate('Zone');
$this->translate('Command');
$this->translate('User');
// ... TBC
}
}

View File

@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Web\Form;
use Icinga\Application\Icinga;
use Icinga\Application\Modules\Module;
use Icinga\Exception\ProgrammingError;
use Icinga\Web\Notification;
use Icinga\Web\Request;
use Icinga\Web\Url;
@ -60,24 +61,39 @@ abstract class QuickForm extends Zend_Form
*/
protected $icingaModule;
protected $icingaModuleName;
protected $hintCount = 0;
public function __construct($options = null)
{
if ($options !== null && array_key_exists('icingaModule', $options)) {
$this->icingaModule = $options['icingaModule'];
unset($options['icingaModule']);
}
parent::__construct($options);
parent::__construct($this->handleOptions($options));
$this->setMethod('post');
$this->setAction(Url::fromRequest());
$this->createIdElement();
$this->regenerateCsrfToken();
}
protected function handleOptions($options = null)
{
if ($options === null) {
return $options;
}
if (array_key_exists('icingaModule', $options)) {
$this->icingaModule = $options['icingaModule'];
$this->icingaModuleName = $this->icingaModule->getName();
unset($options['icingaModule']);
}
return $options;
}
protected function addSubmitButtonIfSet()
{
if (false !== ($label = $this->getSubmitLabel())) {
$this->addElement('submit', $label);
$this->getElement($label)->setLabel($label);
$this->getElement($label)->setLabel($label)->removeDecorator('Label');
}
}
@ -140,6 +156,7 @@ abstract class QuickForm extends Zend_Form
$element = $this->getElement(self::CSRF);
}
$element->setValue(CsrfToken::generate())->setIgnore(true);
return $this;
}
@ -159,6 +176,30 @@ abstract class QuickForm extends Zend_Form
return $this;
}
public function addHtmlHint($html, $options = array())
{
return $this->addHtml('<div class="hint">' . $html . '</div>', $options);
}
public function addHtml($html, $options = array())
{
$name = '_HINT' . ++$this->hintCount;
$this->addElement('note', $name, $options);
$this->getElement($name)
->setValue($html)
->setIgnore(true)
->removeDecorator('Label');
return $this;
}
public function optionalEnum($enum)
{
return array(
null => $this->translate('- please choose -')
) + $enum;
}
public function setSuccessUrl($url)
{
$this->successUrl = $url;
@ -217,8 +258,8 @@ abstract class QuickForm extends Zend_Form
{
if (! $this->didSetup) {
$this->setup();
$this->onSetup();
$this->addSubmitButtonIfSet();
$this->onSetup();
$this->didSetup = true;
}
@ -228,11 +269,9 @@ abstract class QuickForm extends Zend_Form
public function handleRequest(Request $request = null)
{
if ($request !== null) {
$this->request = $request;
$this->setRequest($request);
}
$this->prepareElements();
if ($this->hasBeenSent()) {
$post = $this->getRequest()->getPost();
if ($this->hasBeenSubmitted()) {
@ -254,8 +293,11 @@ abstract class QuickForm extends Zend_Form
public function translate($string)
{
// TODO: A module should use it's own domain
return t($string);
if ($this->icingaModuleName === null) {
return t($string);
} else {
return mt($this->icingaModuleName, $string);
}
}
public function onSuccess()
@ -311,10 +353,26 @@ abstract class QuickForm extends Zend_Form
Icinga::app()->getFrontController()->getResponse()->redirectAndExit($url);
}
protected function onRequest()
{
}
public function setRequest(Request $request)
{
if ($this->request !== null) {
throw new ProgrammingError('Unable to set request twice');
}
$this->request = $request;
$this->prepareElements();
$this->onRequest();
return $this;
}
public function getRequest()
{
if ($this->request === null) {
$this->request = Icinga::app()->getFrontController()->getRequest();
$this->setRequest(Icinga::app()->getFrontController()->getRequest());
}
return $this->request;
}

View File

@ -1,6 +1,90 @@
form p.description {
display: none;
}
input, select, select option, textarea {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
select::-ms-expand, input::-ms-expand, textarea::-ms-expand { /* for IE 11 */
display: none;
}
select {
border: 1px solid #f9f9f9;
cursor: pointer;
}
input, textarea {
border: 1px solid #f9f9f9;
padding-left: 0.5em;
}
select:hover, input:hover, textarea:hover, select:focus, input:focus, textarea:focus {
border: 1px solid #666;
}
select[value=""] {
color: blue;
border: 1px solid #666;
}
select option {
color: inherit;
padding-left: 0.5em;
}
select option[value=""] {
color: #aaa;
}
ul.main-actions {
margin: 0;
li {
list-style-type: none;
width: 20em;
height: 20em;
text-align: center;
display: block;
padding: 0;
float: left;
a {
i {
width: 100%;
height: 1.3em;
font-size: 8em;
display: inline-block;
line-height: 1em;
}
border: 1px solid #666;
padding: 1em;
margin: 0.5em;
font-size: 1.1em;
color: #666;
font-weight: bold;
display: block;
&:hover {
background-color: #666;
color: white;
text-decoration: none;
}
}
}
}
/* BEGIN Forms */
form dt label {
width: auto;
font-weight: normal;
&.required {
font-weight: bold;
}
}
form dd {
@ -10,15 +94,44 @@ form dd {
form dt {
display: inline-block;
min-width: 16em;
min-width: 12em;
width: 30%;
}
form dd:after {
display: block;
content: '';
}
textarea {
height: 10em;
form textarea {
height: auto;
}
form dd ul.errors {
list-style-type: none;
padding-left: 0.3em;
font-size: 0.857em;
li {
color: @colorCritical;
padding: 0.3em;
}
}
form div.hint {
font-size: 0.857em;
padding: 1em;
background-color: #f2f4fd;
border: 1px solid lightgrey;
margin: 1em 0;
pre {
font-style: normal;
background-color: white;
font-size: 1.25em;
margin: 0;
padding: 1em;
}
}
/* END of Forms */
@ -145,10 +258,30 @@ table.simple {
tr {
padding: 0;
margin: 0;
td:first-child {
border-left: 0.5em solid transparent;
}
td:last-child {
border-right: 0.5em solid transparent;
}
background-color: #fafcfe;
}
tr:nth-child(even) {
background-color: #e6e6e6;
background-color: #f6f8fa;
}
tr:hover {
background-color: #888;
td {
color: white;
}
}
tr.active td {
border-color: black;
}
th {
@ -158,7 +291,7 @@ table.simple {
}
td {
padding: 0.1em;
padding: 0.1em 1em;
margin: 0;
white-space: nowrap;
}

View File

@ -0,0 +1,189 @@
ALTER TABLE director_generated_file ALTER COLUMN content SET DEFAULT NULL;
ALTER TABLE icinga_host_field ALTER COLUMN is_required SET NOT NULL;
ALTER TABLE icinga_service_field ALTER COLUMN is_required SET NOT NULL;
CREATE TABLE import_source (
id serial,
source_name character varying(64) NOT NULL,
key_column character varying(64) NOT NULL,
provider_class character varying(72) NOT NULL,
PRIMARY KEY (id)
);
CREATE INDEX import_source_search_idx ON import_source (key_column);
CREATE TABLE import_source_setting (
source_id integer NOT NULL,
setting_name character varying(64) NOT NULL,
setting_value text NOT NULL,
PRIMARY KEY (source_id, setting_name),
CONSTRAINT import_source_settings_source
FOREIGN KEY (source_id)
REFERENCES import_source (id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE INDEX import_source_setting_source ON import_source_setting (source_id);
CREATE TABLE imported_rowset (
checksum bytea CHECK(LENGTH(checksum) = 20),
PRIMARY KEY (checksum)
);
CREATE TABLE import_run (
id serial,
source_id integer NOT NULL,
rowset_checksum bytea CHECK(LENGTH(rowset_checksum) = 20),
start_time timestamp with time zone NOT NULL,
end_time timestamp with time zone NOT NULL,
succeeded enum_boolean DEFAULT NULL,
PRIMARY KEY (id),
CONSTRAINT import_run_source
FOREIGN KEY (source_id)
REFERENCES import_source (id)
ON DELETE RESTRICT
ON UPDATE CASCADE,
CONSTRAINT import_run_rowset
FOREIGN KEY (rowset_checksum)
REFERENCES imported_rowset (checksum)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
CREATE INDEX import_run_import_source ON import_run (source_id);
CREATE INDEX import_run_rowset ON import_run (rowset_checksum);
CREATE TABLE imported_row (
checksum bytea CHECK(LENGTH(checksum) = 20),
object_name character varying(255) NOT NULL,
PRIMARY KEY (checksum)
);
COMMENT ON COLUMN imported_row.checksum IS 'sha1(object_name;property_checksum;...)';
CREATE TABLE imported_rowset_row (
rowset_checksum bytea CHECK(LENGTH(checksum) = 20),
row_checksum bytea CHECK(LENGTH(checksum) = 20),
PRIMARY KEY (rowset_checksum, row_checksum),
CONSTRAINT imported_rowset_row_rowset
FOREIGN KEY (rowset_checksum)
REFERENCES imported_rowset (checksum)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT imported_rowset_row_row
FOREIGN KEY (row_checksum)
REFERENCES imported_row (checksum)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
CREATE INDEX imported_rowset_row_rowset_checksum ON imported_rowset_row (rowset_checksum);
CREATE INDEX imported_rowset_row_row_checksum ON imported_rowset_row (row_checksum);
CREATE TABLE imported_property (
checksum bytea CHECK(LENGTH(checksum) = 20),
property_name character varying(64) NOT NULL,
property_value text NOT NULL,
format enum_property_format,
PRIMARY KEY (checksum)
);
CREATE INDEX imported_property_search_idx ON imported_property (property_name);
CREATE TABLE imported_row_property (
row_checksum bytea CHECK(LENGTH(row_checksum) = 20),
property_checksum bytea CHECK(LENGTH(property_checksum) = 20),
PRIMARY KEY (row_checksum, property_checksum),
CONSTRAINT imported_row_property_row
FOREIGN KEY (row_checksum)
REFERENCES imported_row (checksum)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT imported_row_property_property
FOREIGN KEY (property_checksum)
REFERENCES imported_property (checksum)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
CREATE INDEX imported_row_property_row_checksum ON imported_row_property (row_checksum);
CREATE INDEX imported_row_property_property_checksum ON imported_row_property (property_checksum);
CREATE TYPE enum_sync_rule_object_type AS ENUM('host', 'user');
CREATE TYPE enum_sync_rule_update_policy AS ENUM('merge', 'override', 'ignore');
CREATE TABLE sync_rule (
id serial,
rule_name character varying(255) NOT NULL,
object_type enum_sync_rule_object_type NOT NULL,
update_policy enum_sync_rule_update_policy NOT NULL,
purge_existing enum_boolean NOT NULL DEFAULT 'n',
filter_expression text DEFAULT NULL,
PRIMARY KEY (id)
);
CREATE TYPE enum_sync_property_merge_policy AS ENUM('override', 'merge');
CREATE TABLE sync_property (
id serial,
rule_id integer NOT NULL,
source_id integer NOT NULL,
source_expression character varying(255) NOT NULL,
destination_field character varying(64),
priority smallint NOT NULL,
filter_expression text DEFAULT NULL,
merge_policy enum_sync_property_merge_policy NOT NULL,
PRIMARY KEY (id),
CONSTRAINT sync_property_rule
FOREIGN KEY (rule_id)
REFERENCES sync_rule (id)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT sync_property_source
FOREIGN KEY (source_id)
REFERENCES import_source (id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
CREATE INDEX sync_property_rule ON sync_property (rule_id);
CREATE INDEX sync_property_source ON sync_property (source_id);
CREATE TABLE import_row_modifier (
id serial,
property_id integer NOT NULL,
provider_class character varying(72) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE import_row_modifier_setting (
modifier_id integer NOT NULL,
setting_name character varying(64) NOT NULL,
setting_value text DEFAULT NULL,
PRIMARY KEY (modifier_id)
);
CREATE TABLE director_datafield_setting (
datafield_id integer NOT NULL,
setting_name character varying(64) NOT NULL,
setting_value text NOT NULL,
PRIMARY KEY (datafield_id, setting_name),
CONSTRAINT datafield_id_settings
FOREIGN KEY (datafield_id)
REFERENCES director_datafield (id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE INDEX director_datafield_datafield ON director_datafield_setting (datafield_id);

View File

@ -9,11 +9,6 @@
-- INSERT INTO director_activity_log (object_type, object_name, action_name, author, change_time, checksum) VALUES('object', 'foo', 'create', 'alex', CURRENT_TIMESTAMP, decode('cf23df2207d99a74fbe169e3eba035e633b65d94', 'hex'));
--
--
-- Enumerable Types
--
-- TODO: what about translation of the strings?
CREATE TYPE enum_activity_action AS ENUM('create', 'delete', 'modify');
CREATE TYPE enum_boolean AS ENUM('y', 'n');
CREATE TYPE enum_property_format AS ENUM('string', 'expression', 'json');
@ -24,6 +19,9 @@ CREATE TYPE enum_command_object_type AS ENUM('object', 'template', 'external_obj
CREATE TYPE enum_apply_object_type AS ENUM('object', 'template', 'apply');
CREATE TYPE enum_state_name AS ENUM('OK', 'Warning', 'Critical', 'Unknown', 'Up', 'Down');
CREATE TYPE enum_type_name AS ENUM('DowntimeStart', 'DowntimeEnd', 'DowntimeRemoved', 'Custom', 'Acknowledgement', 'Problem', 'Recovery', 'FlappingStart', 'FlappingEnd');
CREATE TYPE enum_sync_rule_object_type AS ENUM('host', 'user');
CREATE TYPE enum_sync_rule_update_policy AS ENUM('merge', 'override', 'ignore');
CREATE TYPE enum_sync_property_merge_policy AS ENUM('override', 'merge');
CREATE TABLE director_dbversion (
@ -73,7 +71,7 @@ COMMENT ON COLUMN director_generated_config.duration IS 'Config generation durat
CREATE TABLE director_generated_file (
checksum bytea CHECK(LENGTH(checksum) = 20),
content text NOT NULL,
content text DEFAULT NULL,
PRIMARY KEY (checksum)
);
@ -486,7 +484,7 @@ CREATE INDEX host_inheritance_host_parent ON icinga_host_inheritance (parent_hos
CREATE TABLE icinga_host_field (
host_id integer NOT NULL,
datafield_id integer NOT NULL,
is_required enum_boolean DEFAULT NULL,
is_required enum_boolean NOT NULL,
PRIMARY KEY (host_id, datafield_id),
CONSTRAINT icinga_host_field_host
FOREIGN KEY (host_id)
@ -610,7 +608,7 @@ CREATE INDEX service_inheritance_service_parent ON icinga_service_inheritance (p
CREATE TABLE icinga_service_field (
service_id integer NOT NULL,
datafield_id integer NOT NULL,
is_required enum_boolean DEFAULT NULL,
is_required enum_boolean NOT NULL,
PRIMARY KEY (service_id, datafield_id),
CONSTRAINT icinga_service_field_service
FOREIGN KEY (service_id)
@ -963,6 +961,183 @@ CREATE TABLE icinga_usergroup_parent (
CREATE INDEX usergroup_parent_usergroup ON icinga_usergroup_parent (usergroup_id);
CREATE INDEX usergroup_parent_parent ON icinga_usergroup_parent (parent_usergroup_id);
--
-- TODO: unfinished: see mysql.sql schema from sync_*
--
CREATE TABLE import_source (
id serial,
source_name character varying(64) NOT NULL,
key_column character varying(64) NOT NULL,
provider_class character varying(72) NOT NULL,
PRIMARY KEY (id)
);
CREATE INDEX import_source_search_idx ON import_source (key_column);
CREATE TABLE import_source_setting (
source_id integer NOT NULL,
setting_name character varying(64) NOT NULL,
setting_value text NOT NULL,
PRIMARY KEY (source_id, setting_name),
CONSTRAINT import_source_settings_source
FOREIGN KEY (source_id)
REFERENCES import_source (id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE INDEX import_source_setting_source ON import_source_setting (source_id);
CREATE TABLE imported_rowset (
checksum bytea CHECK(LENGTH(checksum) = 20),
PRIMARY KEY (checksum)
);
CREATE TABLE import_run (
id serial,
source_id integer NOT NULL,
rowset_checksum bytea CHECK(LENGTH(rowset_checksum) = 20),
start_time timestamp with time zone NOT NULL,
end_time timestamp with time zone NOT NULL,
succeeded enum_boolean DEFAULT NULL,
PRIMARY KEY (id),
CONSTRAINT import_run_source
FOREIGN KEY (source_id)
REFERENCES import_source (id)
ON DELETE RESTRICT
ON UPDATE CASCADE,
CONSTRAINT import_run_rowset
FOREIGN KEY (rowset_checksum)
REFERENCES imported_rowset (checksum)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
CREATE INDEX import_run_import_source ON import_run (source_id);
CREATE INDEX import_run_rowset ON import_run (rowset_checksum);
CREATE TABLE imported_row (
checksum bytea CHECK(LENGTH(checksum) = 20),
object_name character varying(255) NOT NULL,
PRIMARY KEY (checksum)
);
COMMENT ON COLUMN imported_row.checksum IS 'sha1(object_name;property_checksum;...)';
CREATE TABLE imported_rowset_row (
rowset_checksum bytea CHECK(LENGTH(checksum) = 20),
row_checksum bytea CHECK(LENGTH(checksum) = 20),
PRIMARY KEY (rowset_checksum, row_checksum),
CONSTRAINT imported_rowset_row_rowset
FOREIGN KEY (rowset_checksum)
REFERENCES imported_rowset (checksum)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT imported_rowset_row_row
FOREIGN KEY (row_checksum)
REFERENCES imported_row (checksum)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
CREATE INDEX imported_rowset_row_rowset_checksum ON imported_rowset_row (rowset_checksum);
CREATE INDEX imported_rowset_row_row_checksum ON imported_rowset_row (row_checksum);
CREATE TABLE imported_property (
checksum bytea CHECK(LENGTH(checksum) = 20),
property_name character varying(64) NOT NULL,
property_value text NOT NULL,
format enum_property_format,
PRIMARY KEY (checksum)
);
CREATE INDEX imported_property_search_idx ON imported_property (property_name);
CREATE TABLE imported_row_property (
row_checksum bytea CHECK(LENGTH(row_checksum) = 20),
property_checksum bytea CHECK(LENGTH(property_checksum) = 20),
PRIMARY KEY (row_checksum, property_checksum),
CONSTRAINT imported_row_property_row
FOREIGN KEY (row_checksum)
REFERENCES imported_row (checksum)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT imported_row_property_property
FOREIGN KEY (property_checksum)
REFERENCES imported_property (checksum)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
CREATE INDEX imported_row_property_row_checksum ON imported_row_property (row_checksum);
CREATE INDEX imported_row_property_property_checksum ON imported_row_property (property_checksum);
CREATE TABLE sync_rule (
id serial,
rule_name character varying(255) NOT NULL,
object_type enum_sync_rule_object_type NOT NULL,
update_policy enum_sync_rule_update_policy NOT NULL,
purge_existing enum_boolean NOT NULL DEFAULT 'n',
filter_expression text DEFAULT NULL,
PRIMARY KEY (id)
);
CREATE TABLE sync_property (
id serial,
rule_id integer NOT NULL,
source_id integer NOT NULL,
source_expression character varying(255) NOT NULL,
destination_field character varying(64),
priority smallint NOT NULL,
filter_expression text DEFAULT NULL,
merge_policy enum_sync_property_merge_policy NOT NULL,
PRIMARY KEY (id),
CONSTRAINT sync_property_rule
FOREIGN KEY (rule_id)
REFERENCES sync_rule (id)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT sync_property_source
FOREIGN KEY (source_id)
REFERENCES import_source (id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
CREATE INDEX sync_property_rule ON sync_property (rule_id);
CREATE INDEX sync_property_source ON sync_property (source_id);
CREATE TABLE import_row_modifier (
id serial,
property_id integer NOT NULL,
provider_class character varying(72) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE import_row_modifier_setting (
modifier_id integer NOT NULL,
setting_name character varying(64) NOT NULL,
setting_value text DEFAULT NULL,
PRIMARY KEY (modifier_id)
);
CREATE TABLE director_datafield_setting (
datafield_id integer NOT NULL,
setting_name character varying(64) NOT NULL,
setting_value text NOT NULL,
PRIMARY KEY (datafield_id, setting_name),
CONSTRAINT datafield_id_settings
FOREIGN KEY (datafield_id)
REFERENCES director_datafield (id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE INDEX director_datafield_datafield ON director_datafield_setting (datafield_id);