Merge branch 'feature/branches-rewrite'

This commit is contained in:
Thomas Gelf 2021-10-06 09:41:58 +02:00
commit 2906dc8acc
79 changed files with 4660 additions and 1378 deletions

View File

@ -5,18 +5,15 @@ namespace Icinga\Module\Director\Controllers;
use gipfl\Diff\HtmlRenderer\SideBySideDiff;
use gipfl\Diff\PhpDiff;
use gipfl\IcingaWeb2\Widget\NameValueTable;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Data\Json;
use Icinga\Module\Director\Db\Branch\IcingaObjectModification;
use Icinga\Module\Director\Db\Branch\ObjectModification;
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
use Icinga\Module\Director\Db\Branch\BranchActivity;
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
use Icinga\Module\Director\Objects\IcingaObject;
use Icinga\Module\Director\PlainObjectRenderer;
use Icinga\Module\Director\Web\Controller\ActionController;
use Icinga\Module\Director\Web\Controller\BranchHelper;
use Icinga\Module\Director\Web\Widget\IcingaConfigDiff;
use ipl\Html\Html;
use ipl\Html\ValidHtml;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
class BranchController extends ActionController
{
@ -29,66 +26,75 @@ class BranchController extends ActionController
public function activityAction()
{
$this->assertPermission('director/showconfig');
$uuid = Uuid::fromString($this->params->getRequired('uuid'));
$ts = $this->params->getRequired('ts');
$this->addSingleTab($this->translate('Activity'));
$this->addTitle($this->translate('Branch Activity'));
$activity = $this->loadBranchActivity($uuid);
$activity = BranchActivity::load($ts, $this->db());
$this->content()->add($this->prepareActivityInfo($activity));
$this->showActivity($activity);
}
protected function prepareActivityInfo($activity)
protected function prepareActivityInfo(BranchActivity $activity)
{
$modification = ObjectModification::fromSerialization(json_decode($activity->change_set));
/** @var IcingaObject $class IDE hint, it's a string */
$class = $modification->getClassName();
$keyParams = (array) $modification->getKeyParams(); // TODO: verify type
$dummy = $class::create($keyParams);
$table = new NameValueTable();
$table->addNameValuePairs([
$this->translate('Author') => 'branch owner',
$this->translate('Date') => date('Y-m-d H:i:s', $activity->change_time / 1000),
$this->translate('Action') => $modification->getAction()
. ' ' . $dummy->getShortTableName()
. ' ' . $dummy->getObjectName(),
$this->translate('Change UUID') => Uuid::fromBytes($activity->uuid)->toString(),
$this->translate('Author') => $activity->getAuthor(),
$this->translate('Date') => date('Y-m-d H:i:s', $activity->getTimestamp()),
$this->translate('Action') => $activity->getAction()
. ' ' . preg_replace('/^icinga_/', '', $activity->getObjectTable())
. ' ' . $activity->getObjectName(),
// $this->translate('Actions') => ['Undo form'],
]);
return $table;
}
protected function showActivity($activity)
protected function leftFromActivity(BranchActivity $activity)
{
$modification = ObjectModification::fromSerialization(Json::decode($activity->change_set));
/** @var string|DbObject $class */
$class = $modification->getClassName();
// TODO: Show JSON-Diff for non-IcingaObject's
$keyParams = (array) $modification->getKeyParams(); // TODO: verify type
$dummy = $class::create($keyParams, $this->db());
if ($modification->isCreation()) {
$left = $this->createEmptyConfig();
$right = $dummy->setProperties(
(array) $modification->getProperties()->jsonSerialize()
)->toSingleIcingaConfig();
} elseif ($modification->isDeletion()) {
$left = $class::load($keyParams, $this->db())->toSingleIcingaConfig();
$right = $this->createEmptyConfig();
} else {
// TODO: highlight properties that have been changed in the meantime
// TODO: Deal with missing $existing
$existing = $class::load($keyParams, $this->db());
$left = $existing->toSingleIcingaConfig();
$right = clone($existing);
IcingaObjectModification::applyModification($modification, $right, $this->db());
$right = $right->toSingleIcingaConfig();
if ($activity->isActionCreate()) {
return null;
}
$changes = $this->getConfigDiffs($left, $right);
foreach ($changes as $filename => $diff) {
$object = DbObjectTypeRegistry::newObject($activity->getObjectTable(), [], $this->db());
foreach ($activity->getFormerProperties()->jsonSerialize() as $key => $value) {
$object->set($key, $value);
}
return $object;
}
protected function rightFromActivity(BranchActivity $activity)
{
if ($activity->isActionDelete()) {
return null;
}
$object = DbObjectTypeRegistry::newObject($activity->getObjectTable(), [], $this->db());
if (! $activity->isActionCreate()) {
foreach ($activity->getFormerProperties()->jsonSerialize() as $key => $value) {
$object->set($key, $value);
}
}
foreach ($activity->getModifiedProperties()->jsonSerialize() as $key => $value) {
$object->set($key, $value);
}
return $object;
}
protected function showActivity(BranchActivity $activity)
{
$left = $this->leftFromActivity($activity);
$right = $this->rightFromActivity($activity);
if ($left instanceof IcingaObject || $right instanceof IcingaObject) {
$this->content()->add(new IcingaConfigDiff(
$left ? $left->toSingleIcingaConfig() : $this->createEmptyConfig(),
$right ? $right->toSingleIcingaConfig() : $this->createEmptyConfig()
));
} else {
$this->content()->add([
Html::tag('h3', $filename),
$diff
Html::tag('h3', $this->translate('Modification')),
new SideBySideDiff(new PhpDiff(
PlainObjectRenderer::render($left->getProperties()),
PlainObjectRenderer::render($right->getProperties())
))
]);
}
}
@ -97,47 +103,4 @@ class BranchController extends ActionController
{
return new IcingaConfig($this->db());
}
/**
* @param IcingaConfig $oldConfig
* @param IcingaConfig $newConfig
* @return ValidHtml[]
*/
protected function getConfigDiffs(IcingaConfig $oldConfig, IcingaConfig $newConfig)
{
$oldFileNames = $oldConfig->getFileNames();
$newFileNames = $newConfig->getFileNames();
$fileNames = array_merge($oldFileNames, $newFileNames);
$diffs = [];
foreach ($fileNames as $filename) {
if (in_array($filename, $oldFileNames)) {
$left = $oldConfig->getFile($filename)->getContent();
} else {
$left = '';
}
if (in_array($filename, $newFileNames)) {
$right = $newConfig->getFile($filename)->getContent();
} else {
$right = '';
}
if ($left === $right) {
continue;
}
$diffs[$filename] = new SideBySideDiff(new PhpDiff($left, $right));
}
return $diffs;
}
protected function loadBranchActivity(UuidInterface $uuid)
{
$db = $this->db()->getDbAdapter();
return $db->fetchRow(
$db->select()->from('director_branch_activity')->where('uuid = ?', $uuid->getBytes())
);
}
}

View File

@ -3,6 +3,8 @@
namespace Icinga\Module\Director\Controllers;
use gipfl\Web\Widget\Hint;
use Icinga\Module\Director\Objects\IcingaCommandArgument;
use Icinga\Module\Director\Web\Table\BranchedIcingaCommandArgumentTable;
use ipl\Html\Html;
use Icinga\Module\Director\Forms\IcingaCommandArgumentForm;
use Icinga\Module\Director\Objects\IcingaCommand;
@ -22,9 +24,14 @@ class CommandController extends ObjectController
parent::init();
$o = $this->object;
if ($o && ! $o->isExternal()) {
if ($this->getBranch()->isBranch()) {
$urlParams = ['uuid' => $o->getUniqueId()->toString()];
} else {
$urlParams = ['name' => $o->getObjectName()];
}
$this->tabs()->add('arguments', [
'url' => 'director/command/arguments',
'urlParams' => ['name' => $o->getObjectName()],
'urlParams' => $urlParams,
'label' => 'Arguments'
]);
}
@ -83,16 +90,33 @@ class CommandController extends ObjectController
$o = $this->object;
$this->tabs()->activate('arguments');
$this->addTitle($this->translate('Command arguments: %s'), $o->getObjectName());
$form = IcingaCommandArgumentForm::load()->setCommandObject($o);
if ($id = $p->shift('argument_id')) {
$form = (new IcingaCommandArgumentForm)
->setBranch($this->getBranch())
->setCommandObject($o);
if ($argument = $p->shift('argument')) {
$this->addBackLink('director/command/arguments', [
'name' => $p->get('name')
]);
$form->loadObject($id);
if ($this->branch->isBranch()) {
$arguments = $o->arguments();
$argument = $arguments->get($argument);
// IcingaCommandArgument::create((array) $arguments->get($argument)->toFullPlainObject());
// $argument->setBeingLoadedFromDb();
} else {
$argument = IcingaCommandArgument::load([
'command_id' => $o->get('id'),
'argument_name' => $argument
], $this->db());
}
$form->setObject($argument);
}
$form->handleRequest();
$this->content()->add([$form]);
IcingaCommandArgumentTable::create($o)->renderTo($this);
if ($this->branch->isBranch()) {
(new BranchedIcingaCommandArgumentTable($o, $this->getBranch()))->renderTo($this);
} else {
(new IcingaCommandArgumentTable($o, $this->getBranch()))->renderTo($this);
}
}
protected function hasBasketSupport()

View File

@ -432,6 +432,9 @@ class ConfigController extends ActionController
protected function showOptionalBranchActivity()
{
if ($this->url()->hasParam('idRangeEx')) {
return;
}
$branch = $this->getBranch();
if ($branch->isBranch() && (int) $this->params->get('page', '1') === 1) {
$table = new BranchActivityTable($branch->getUuid(), $this->db());
@ -443,12 +446,12 @@ class ConfigController extends ActionController
$this->Auth(),
$this->translate('configuration branch')
))));
$table = new BranchActivityTable($branch->getUuid(), $this->db());
$this->content()->add($table);
$this->content()->add(Html::tag('br'));
$this->content()->add(Hint::ok($this->translate(
'...and the modifications below are already in the main branch:'
)));
$this->content()->add(Html::tag('br'));
}
}
}

View File

@ -19,17 +19,11 @@ class DatafieldController extends ActionController
public function indexAction()
{
$edit = false;
if ($id = $this->params->get('id')) {
$edit = true;
}
$form = DirectorDatafieldForm::load()
->setDb($this->db());
if ($edit) {
$form->loadObject($id);
if ($id = $this->params->get('id')) {
$form->loadObject((int) $id);
$this->addTitle(
$this->translate('Modify %s'),
$form->getObject()->varname

View File

@ -107,6 +107,7 @@ class HostController extends ObjectController
$this->addTitle($this->translate('Add Service to %s'), $host->getObjectName());
$this->content()->add(
IcingaAddServiceForm::load()
->setBranch($this->getBranch())
->setHost($host)
->setDb($this->db())
->handleRequest()
@ -199,12 +200,21 @@ class HostController extends ObjectController
public function servicesAction()
{
$this->addServicesHeader();
$db = $this->db();
$host = $this->getHostObject();
$this->addTitle($this->translate('Services: %s'), $host->getObjectName());
$branch = $this->getBranch();
if ($branch->isBranch() && $host->get('id') === null) {
$this->content()->add(Hint::info(
$this->translate('Managing services on new Hosts is possible only after they have been merged.')
));
return;
}
$content = $this->content();
$table = IcingaHostServiceTable::load($host)
->setTitle($this->translate('Individual Service objects'));
if ($branch->isBranch()) {
$table->setBranchUuid($branch->getUuid());
}
if (count($table)) {
$content->add($table);
@ -598,7 +608,7 @@ class HostController extends ObjectController
*/
protected function getHostObject()
{
/** @var IcingaHost $this->object */
assert($this->object instanceof IcingaHost);
return $this->object;
}
}

View File

@ -3,12 +3,15 @@
namespace Icinga\Module\Director\Controllers;
use Exception;
use gipfl\Web\Widget\Hint;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Forms\ImportRowModifierForm;
use Icinga\Module\Director\Forms\ImportSourceForm;
use Icinga\Module\Director\Hook\ImportSourceHook;
use Icinga\Module\Director\Web\ActionBar\AutomationObjectActionBar;
use Icinga\Module\Director\Web\Controller\ActionController;
use Icinga\Module\Director\Objects\ImportSource;
use Icinga\Module\Director\Web\Controller\BranchHelper;
use Icinga\Module\Director\Web\Form\CloneImportSourceForm;
use Icinga\Module\Director\Web\Table\ImportrunTable;
use Icinga\Module\Director\Web\Table\ImportsourceHookTable;
@ -18,9 +21,12 @@ use Icinga\Module\Director\Web\Widget\ImportSourceDetails;
use InvalidArgumentException;
use gipfl\IcingaWeb2\Link;
use ipl\Html\Error;
use ipl\Html\Html;
class ImportsourceController extends ActionController
{
use BranchHelper;
/** @var ImportSource|null */
private $importSource;
@ -85,6 +91,14 @@ class ImportsourceController extends ActionController
$this->translate('Import source: %s'),
$source->get('source_name')
)->setAutorefreshInterval(10);
$branch = $this->getBranch();
if ($this->getBranch()->isBranch()) {
$this->content()->add(Hint::info(Html::sprintf($this->translate(
'Please note that importing data will take place in your main Branch.'
. ' Modifications to Import Sources are not allowed while being in a Configuration Branch.'
. ' To get the full functionality, please deactivate %s'
), Branch::requireHook()->linkToBranch($branch, $this->getAuth(), $branch->getName()))));
}
$this->content()->add(new ImportSourceDetails($source));
}
@ -284,7 +298,7 @@ class ImportsourceController extends ActionController
. (int) $source->get('id');
$this->content()->prepend(
ImportRowModifierForm::load()->setDb($this->db())
->loadObject($this->params->getRequired('id'))
->loadObject((int) $this->params->getRequired('id'))
->setListUrl($listUrl)
->setSource($source)
->handleRequest()

View File

@ -6,10 +6,13 @@ use gipfl\IcingaWeb2\Link;
use Icinga\Module\Director\Forms\DirectorJobForm;
use Icinga\Module\Director\Web\Controller\ActionController;
use Icinga\Module\Director\Objects\DirectorJob;
use Icinga\Module\Director\Web\Controller\BranchHelper;
use Icinga\Module\Director\Web\Widget\JobDetails;
class JobController extends ActionController
{
use BranchHelper;
/**
* @throws \Icinga\Exception\MissingParameterException
* @throws \Icinga\Exception\NotFoundError
@ -29,13 +32,17 @@ class JobController extends ActionController
{
$this
->addSingleTab($this->translate('New Job'))
->addTitle($this->translate('Add a new Job'))
->content()->add(
DirectorJobForm::load()
->setSuccessUrl('director/job')
->setDb($this->db())
->handleRequest()
);
->addTitle($this->translate('Add a new Job'));
if ($this->showNotInBranch($this->translate('Creating Jobs'))) {
return;
}
$this->content()->add(
DirectorJobForm::load()
->setSuccessUrl('director/job')
->setDb($this->db())
->handleRequest()
);
}
/**
@ -45,16 +52,19 @@ class JobController extends ActionController
public function editAction()
{
$job = $this->requireJob();
$this
->addJobTabs($job, 'edit')
->addTitle($this->translate('Job: %s'), $job->get('job_name'))
->addToBasketLink();
if ($this->showNotInBranch($this->translate('Modifying Jobs'))) {
return;
}
$form = DirectorJobForm::load()
->setListUrl('director/jobs')
->setObject($job)
->handleRequest();
$this
->addJobTabs($job, 'edit')
->addTitle($this->translate('Job: %s'), $job->get('job_name'))
->addToBasketLink()
->content()->add($form);
$this->content()->add($form);
}
/**

View File

@ -4,13 +4,19 @@ namespace Icinga\Module\Director\Controllers;
use Exception;
use Icinga\Module\Director\Forms\KickstartForm;
use Icinga\Module\Director\Web\Controller\BranchHelper;
class KickstartController extends DashboardController
{
use BranchHelper;
public function indexAction()
{
$this->addSingleTab($this->translate('Kickstart'))
->addTitle($this->translate('Director Kickstart Wizard'));
if ($this->showNotInBranch($this->translate('Kickstart'))) {
return;
}
$form = KickstartForm::load();
try {
$form->setEndpoint($this->db()->getDeploymentEndpoint());

View File

@ -3,10 +3,11 @@
namespace Icinga\Module\Director\Controllers;
use Exception;
use Icinga\Module\Director\Data\Db\DbObjectStore;
use Icinga\Module\Director\Db\Branch\UuidLookup;
use Icinga\Module\Director\Forms\IcingaServiceForm;
use Icinga\Module\Director\Monitoring;
use Icinga\Module\Director\Web\Controller\ObjectController;
use Icinga\Module\Director\Objects\IcingaServiceSet;
use Icinga\Module\Director\Objects\IcingaService;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
@ -28,65 +29,68 @@ class ServiceController extends ObjectController
{
if ($this->hasPermission('director/monitoring/services')) {
$monitoring = new Monitoring();
return $monitoring->authCanEditService($this->Auth(), $this->getParam('host'), $this->getParam('name'));
if ($monitoring->authCanEditService($this->Auth(), $this->getParam('host'), $this->getParam('name'))) {
return;
}
}
$this->assertPermission('director/hosts');
}
public function init()
{
if ($host = $this->params->get('host')) {
$this->host = IcingaHost::load($host, $this->db());
} elseif ($hostId = $this->params->get('host_id')) {
$this->host = IcingaHost::loadWithAutoIncId($hostId, $this->db());
} elseif ($set = $this->params->get('set')) {
$this->set = IcingaServiceSet::load(['object_name' => $set], $this->db());
} elseif ($apply = $this->params->get('apply')) {
$this->apply = IcingaService::load(
['object_name' => $apply, 'object_type' => 'template'],
$this->db()
);
}
parent::init();
$this->loadOptionalHost();
$this->loadOptionalSet();
$this->addOptionalHostTabs();
$this->addOptionalSetTabs();
}
if ($this->host) {
$hostname = $this->host->getObjectName();
$tabs = new Tabs();
$tabs->add('host', [
'url' => 'director/host',
'urlParams' => ['name' => $hostname],
'label' => $this->translate('Host'),
])->add('services', [
'url' => 'director/host/services',
'urlParams' => ['name' => $hostname],
'label' => $this->translate('Services'),
]);
$this->addParamToTabs('host', $hostname);
$this->controls()->prependTabs($tabs);
}
if ($this->object) {
if (! $this->set && $this->object->get('service_set_id')) {
$this->set = $this->object->getRelated('service_set');
protected function loadOptionalHost()
{
$host = $this->params->get('host', $this->params->get('host_id'));
if ($host === null && $this->object) {
if ($host = $this->object->get('host_id')) {
$host = (int) $host;
} else {
$host = $this->object->get('host');
var_dump($host);
exit;
}
}
if ($this->set) {
$setName = $this->set->getObjectName();
$tabs = new Tabs();
$tabs->add('set', [
'url' => 'director/serviceset',
'urlParams' => ['name' => $setName],
'label' => $this->translate('ServiceSet'),
])->add('services', [
'url' => 'director/serviceset/services',
'urlParams' => ['name' => $setName],
'label' => $this->translate('Services'),
]);
if ($host !== null) {
$key = UuidLookup::findUuidForKey($host, 'icinga_host', $this->db(), $this->getBranch());
$this->host = $this->loadSpecificObject('icinga_host', $key);
}
}
$this->addParamToTabs('serviceset', $setName);
$this->controls()->prependTabs($tabs);
protected function loadOptionalSet()
{
$key = $this->params->get('set', $this->params->get('service_set_id'));
if ($key === null && $this->object && $key = $this->object->get('service_set_id')) {
$key = (int) $key;
}
if ($key !== null) {
$uuid = UuidLookup::findUuidForKey($key, 'icinga_service_set', $this->db(), $this->getBranch());
$this->set = $this->loadSpecificObject('icinga_service_set', $uuid);
}
}
/**
* TODO: Is this still a thing? It's unused.
*
* @throws \Icinga\Exception\NotFoundError
*/
protected function loadOptionalApplyRule()
{
if ($apply = $this->params->get('apply')) {
// Hint: doesn't work, DbObjectStore::load does no longer exist
$store = new DbObjectStore($this->db(), $this->getBranch());
$this->apply = $store->load('service', [
'object_name' => $apply,
'object_type' => 'template'
]);
}
}
@ -104,6 +108,7 @@ class ServiceController extends ObjectController
{
parent::addAction();
if ($this->host) {
// TODO: use setTitle. And figure out, where we use this old route.
$this->view->title = $this->host->object_name . ': ' . $this->view->title;
} elseif ($this->set) {
$this->view->title = sprintf(
@ -218,33 +223,74 @@ class ServiceController extends ObjectController
$this->content()->add($table);
}
protected function loadObject()
protected function getLegacyKey()
{
if ($this->object === null) {
if ($id = $this->params->get('id')) {
$this->object = IcingaService::loadWithAutoIncId(
(int) $id,
$this->db()
);
} elseif ($name = $this->params->get('name')) {
$params = array('object_name' => $name);
$db = $this->db();
if ($this->host) {
// $this->view->host = $this->host;
$params['host_id'] = $this->host->id;
}
if ($this->set) {
// $this->view->set = $this->set;
$params['service_set_id'] = $this->set->id;
}
$this->object = IcingaService::load($params, $db);
} else {
parent::loadObject();
}
if ($key = $this->params->get('id')) {
$key = (int) $key;
} else {
$key = $this->params->get('name');
}
return $this->object;
if ($key === null) {
throw new \InvalidArgumentException('uuid, name or id required');
}
return $key;
}
protected function loadObject()
{
if ($this->params->has('uuid')) {
parent::loadObject();
return;
}
$key = $this->getLegacyKey();
$uuid = UuidLookup::findServiceUuid($this->db(), $this->getBranch(), 'object', $key, $this->host, $this->set);
$this->params->set('uuid', $uuid->toString());
parent::loadObject();
}
protected function addOptionalHostTabs()
{
if ($this->host === null) {
return;
}
$hostname = $this->host->getObjectName();
$tabs = new Tabs();
$urlParams = ['uuid' => $this->host->getUniqueId()->toString()];
$tabs->add('host', [
'url' => 'director/host',
'urlParams' => $urlParams,
'label' => $this->translate('Host'),
])->add('services', [
'url' => 'director/host/services',
'urlParams' => $urlParams,
'label' => $this->translate('Services'),
]);
$this->addParamToTabs('host', $hostname);
$this->controls()->prependTabs($tabs);
}
protected function addOptionalSetTabs()
{
if ($this->set === null) {
return;
}
$setName = $this->set->getObjectName();
$tabs = new Tabs();
$tabs->add('set', [
'url' => 'director/serviceset',
'urlParams' => ['name' => $setName],
'label' => $this->translate('ServiceSet'),
])->add('services', [
'url' => 'director/serviceset/services',
'urlParams' => ['name' => $setName],
'label' => $this->translate('Services'),
]);
$this->addParamToTabs('serviceset', $setName);
$this->controls()->prependTabs($tabs);
}
}

View File

@ -6,6 +6,7 @@ use gipfl\Diff\HtmlRenderer\SideBySideDiff;
use gipfl\Diff\PhpDiff;
use gipfl\IcingaWeb2\Link;
use gipfl\Web\Widget\Hint;
use Icinga\Module\Director\Web\Widget\IcingaConfigDiff;
use Icinga\Module\Director\Web\Widget\UnorderedList;
use Icinga\Module\Director\Db\Cache\PrefetchCache;
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
@ -309,7 +310,7 @@ class SyncruleController extends ActionController
$cfgOld = new IcingaConfig($this->db());
$oldObject->renderToConfig($cfgOld);
$object->renderToConfig($cfgNew);
foreach ($this->getConfigDiffs($cfgOld, $cfgNew) as $file => $diff) {
foreach (IcingaConfigDiff::getDiffs($cfgOld, $cfgNew) as $file => $diff) {
$names[$name . '___PRETITLE___' . $file] = Html::tag('h3', $file);
$names[$name . '___PREVIEW___' . $file] = $diff;
}
@ -334,7 +335,7 @@ class SyncruleController extends ActionController
$cfgOld = new IcingaConfig($this->db());
$oldObject->renderToConfig($cfgOld);
$object->renderToConfig($cfgNew);
foreach ($this->getConfigDiffs($cfgOld, $cfgNew) as $file => $diff) {
foreach (IcingaConfigDiff::getDiffs($cfgOld, $cfgNew) as $file => $diff) {
$names[$name . '___PRETITLE___' . $file] = Html::tag('h3', $file);
$names[$name . '___PREVIEW___' . $file] = $diff;
}
@ -364,43 +365,6 @@ class SyncruleController extends ActionController
return $list;
}
/**
* Stolen from elsewhere, should be de-duplicated
*
* @param IcingaConfig $oldConfig
* @param IcingaConfig $newConfig
* @return ValidHtml[]
*/
protected function getConfigDiffs(IcingaConfig $oldConfig, IcingaConfig $newConfig)
{
$oldFileNames = $oldConfig->getFileNames();
$newFileNames = $newConfig->getFileNames();
$fileNames = array_merge($oldFileNames, $newFileNames);
$diffs = [];
foreach ($fileNames as $filename) {
if (in_array($filename, $oldFileNames)) {
$left = $oldConfig->getFile($filename)->getContent();
} else {
$left = '';
}
if (in_array($filename, $newFileNames)) {
$right = $newConfig->getFile($filename)->getContent();
} else {
$right = '';
}
if ($left === $right) {
continue;
}
$diffs[$filename] = new SideBySideDiff(new PhpDiff($left, $right));
}
return $diffs;
}
protected function listModifiedProperties($properties)
{
$list = new UnorderedList();

View File

@ -4,9 +4,12 @@ namespace Icinga\Module\Director\Controllers;
use Icinga\Module\Director\Forms\IcingaTemplateChoiceForm;
use Icinga\Module\Director\Web\Controller\ActionController;
use Icinga\Module\Director\Web\Controller\BranchHelper;
class TemplatechoiceController extends ActionController
{
use BranchHelper;
protected function checkDirectorPermissions()
{
$this->assertPermission('director/admin');
@ -24,12 +27,15 @@ class TemplatechoiceController extends ActionController
protected function prepare($type, $title)
{
$this->addSingleTab('Choice')
->addTitle($title);
$form = IcingaTemplateChoiceForm::create($type, $this->db())
->optionallyLoad($this->params->get('name'))
->setListUrl("director/templatechoices/$type")
->handleRequest();
$this->addSingleTab('Choice')
->addTitle($title)
->content()->add($form);
if ($this->showNotInBranch($this->translate('Modifying Template Choices'))) {
return;
}
$this->content()->add($form);
}
}

View File

@ -161,10 +161,11 @@ class IcingaAddServiceForm extends DirectorObjectForm
$plain = $this->object->toPlainObject();
$db = $this->object->getConnection();
// TODO: Test this:
foreach ($this->hosts as $host) {
IcingaService::fromPlainObject($plain, $db)
->set('host_id', $host->get('id'))
->store();
$service = IcingaService::fromPlainObject($plain, $db)
->set('host_id', $host->get('id'));
$this->getDbObjectStore()->store($service);
}
$msg = sprintf(

View File

@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Forms;
use gipfl\Web\Widget\Hint;
use Icinga\Exception\IcingaException;
use Icinga\Module\Director\Acl;
use Icinga\Module\Director\Data\Db\DbObjectStore;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaObject;
@ -24,7 +25,9 @@ class IcingaCloneObjectForm extends DirectorForm
public function setup()
{
if ($this->branch->isBranch() && $this->object instanceof IcingaObject && $this->object->isTemplate()) {
$isBranch = $this->branch && $this->branch->isBranch();
$branchOnly = $this->object->get('id') === null;
if ($isBranch && $this->object instanceof IcingaObject && $this->object->isTemplate()) {
$this->addHtml(Hint::error($this->translate(
'Templates cannot be cloned in Configuration Branches'
)));
@ -38,7 +41,7 @@ class IcingaCloneObjectForm extends DirectorForm
'value' => $name,
));
if (Acl::instance()->hasPermission('director/admin')) {
if (!$branchOnly && Acl::instance()->hasPermission('director/admin')) {
$this->addElement('select', 'clone_type', array(
'label' => 'Clone type',
'required' => true,
@ -49,8 +52,8 @@ class IcingaCloneObjectForm extends DirectorForm
));
}
if ($this->object instanceof IcingaHost
|| $this->object instanceof IcingaServiceSet
if (!$branchOnly && ($this->object instanceof IcingaHost
|| $this->object instanceof IcingaServiceSet)
) {
$this->addBoolean('clone_services', [
'label' => $this->translate('Clone Services'),
@ -60,7 +63,7 @@ class IcingaCloneObjectForm extends DirectorForm
], 'y');
}
if ($this->object instanceof IcingaHost) {
if (!$branchOnly && $this->object instanceof IcingaHost) {
$this->addBoolean('clone_service_sets', [
'label' => $this->translate('Clone Service Sets'),
'description' => $this->translate(
@ -139,6 +142,10 @@ class IcingaCloneObjectForm extends DirectorForm
$object->getObjectName()
);
if ($object->isTemplate() && $this->branch && $this->branch->isBranch()) {
throw new IcingaException('Cloning templates is not available for Branches');
}
if ($object->isTemplate() && $object->getObjectName() === $newName) {
throw new IcingaException(
$this->translate('Name needs to be changed when cloning a Template')
@ -188,7 +195,8 @@ class IcingaCloneObjectForm extends DirectorForm
$fields = [];
}
if ($new->store()) {
$store = new DbObjectStore($connection, $this->branch);
if ($store->store($new)) {
$newId = $new->get('id');
foreach ($services as $service) {
$clone = IcingaService::fromPlainObject(
@ -201,14 +209,15 @@ class IcingaCloneObjectForm extends DirectorForm
} elseif ($new instanceof IcingaServiceSet) {
$clone->set('service_set_id', $newId);
}
$clone->store();
$store->store($clone);
}
foreach ($sets as $set) {
IcingaServiceSet::fromPlainObject(
$newSet = IcingaServiceSet::fromPlainObject(
$set->toPlainObject(),
$connection
)->set('host_id', $newId)->store();
)->set('host_id', $newId);
$store->store($newSet);
}
foreach ($fields as $row) {

View File

@ -134,16 +134,22 @@ class IcingaCommandArgumentForm extends DirectorObjectForm
$cmd = $this->commandObject;
$msg = sprintf(
'%s argument "%s" has been removed',
$this->translate('%s argument "%s" has been removed'),
$this->translate($this->getObjectShortClassName()),
$object->argument_name
);
$url = $this->getSuccessUrl()->without('argument_id');
// TODO: remove argument_id, once verified that it is no longer in use
$url = $this->getSuccessUrl()->without('argument_id')->without('argument');
$cmd->arguments()->remove($object->argument_name);
if ($cmd->store()) {
if ($this->branch->isBranch()) {
$this->getDbObjectStore()->store($cmd);
$this->setSuccessUrl($url);
} else {
if ($cmd->store()) {
$this->setSuccessUrl($url);
}
}
$this->redirectOnSuccess($msg);
@ -167,20 +173,17 @@ class IcingaCommandArgumentForm extends DirectorObjectForm
$this->translate('The argument %s has successfully been stored'),
$object->get('argument_name')
);
$cmd->store($this->db);
$this->getDbObjectStore()->store($cmd);
} else {
if ($this->isApiRequest()) {
$this->setHttpResponseCode(304);
}
$msg = $this->translate('No action taken, object has not been modified');
}
$this->setSuccessUrl(
'director/command/arguments',
[
'argument_id' => $object->get('id'),
'name' => $cmd->getObjectName()
]
);
$this->setSuccessUrl('director/command/arguments', [
'argument' => $object->get('argument_name'),
'name' => $cmd->getObjectName()
]);
$this->redirectOnSuccess($msg);
}

View File

@ -181,7 +181,7 @@ class CustomVariables implements Iterator, Countable, IcingaConfigRenderer
$vars->vars[$row->varname] = CustomVariable::fromDbRow($row);
}
$vars->refreshIndex();
$vars->setUnmodified();
$vars->setBeingLoadedFromDb();
return $vars;
}
@ -192,7 +192,7 @@ class CustomVariables implements Iterator, Countable, IcingaConfigRenderer
$vars->vars[$row->varname] = CustomVariable::fromDbRow($row);
}
$vars->refreshIndex();
$vars->setUnmodified();
$vars->setBeingLoadedFromDb();
return $vars;
}
@ -237,7 +237,7 @@ class CustomVariables implements Iterator, Countable, IcingaConfigRenderer
}
}
$this->setUnmodified();
$this->setBeingLoadedFromDb();
}
public function get($key)
@ -264,14 +264,16 @@ class CustomVariables implements Iterator, Countable, IcingaConfigRenderer
return false;
}
public function setUnmodified()
public function setBeingLoadedFromDb()
{
$this->modified = false;
$this->storedVars = array();
foreach ($this->vars as $key => $var) {
$this->storedVars[$key] = clone($var);
$var->setUnmodified();
$var->setLoadedFromDb();
}
return $this;
}

View File

@ -3,11 +3,13 @@
namespace Icinga\Module\Director\Data\Db;
use Icinga\Exception\NotFoundError;
use Icinga\Module\Director\Data\InvalidDataException;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Exception\DuplicateKeyException;
use Icinga\Module\Director\Util;
use InvalidArgumentException;
use LogicException;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use RuntimeException;
use Zend_Db_Adapter_Abstract;
use Zend_Db_Exception;
@ -69,6 +71,9 @@ abstract class DbObject
*/
protected $autoincKeyName;
/** @var string optional uuid column */
protected $uuidColumn;
/** @var bool forbid updates to autoinc values */
protected $protectAutoinc = true;
@ -307,6 +312,9 @@ abstract class DbObject
$value = null;
}
if (is_resource($value)) {
$value = stream_get_contents($value);
}
$func = 'validate' . ucfirst($key);
if (method_exists($this, $func) && $this->$func($value) !== true) {
throw new InvalidArgumentException(sprintf(
@ -530,6 +538,44 @@ abstract class DbObject
return $this->autoincKeyName;
}
/**
* @return ?string
*/
public function getUuidColumn()
{
return $this->uuidColumn;
}
/**
* @return bool
*/
public function hasUuidColumn()
{
return $this->uuidColumn !== null;
}
/**
* @return \Ramsey\Uuid\UuidInterface
*/
public function getUniqueId()
{
if ($this->hasUuidColumn()) {
$binaryValue = $this->properties[$this->uuidColumn];
if (is_resource($binaryValue)) {
throw new RuntimeException('Properties contain binary UUID, probably a programming error');
}
if ($binaryValue === null) {
$uuid = Uuid::uuid4();
$this->reallySet($this->uuidColumn, $uuid->getBytes());
return $uuid;
}
return Uuid::fromBytes($binaryValue);
}
throw new InvalidArgumentException(sprintf('%s has no UUID column', $this->getTableName()));
}
public function getKeyParams()
{
$params = array();
@ -651,15 +697,22 @@ abstract class DbObject
}
/**
* @param object $row
* @param object|array $row
* @param Db $db
* @return self
*/
public static function fromDbRow($row, Db $db)
{
return (new static())
->setConnection($db)
->setDbProperties($row);
$self = (new static())->setConnection($db);
if (is_object($row)) {
return $self->setDbProperties((array) $row);
}
if (is_array($row)) {
return $self->setDbProperties($row);
}
throw new InvalidDataException('array or object', $row);
}
protected function setDbProperties($properties)
@ -694,6 +747,16 @@ abstract class DbObject
$this->modifiedProperties = [];
}
public function setLoadedProperty($key, $value)
{
if ($this->hasBeenLoadedFromDb()) {
$this->set($key, $value);
$this->loadedProperties[$key] = $this->get($key);
} else {
throw new RuntimeException('Cannot set loaded property for new object');
}
}
public function getOriginalProperties()
{
return $this->loadedProperties;
@ -737,6 +800,7 @@ abstract class DbObject
// Fake true, we might have manually set this to "modified"
return true;
}
$this->quoteBinaryProperties($properties);
// TODO: Remember changed data for audit and log
return $this->db->update(
@ -760,18 +824,23 @@ abstract class DbObject
unset($properties[$this->autoincKeyName]);
}
}
$this->quoteBinaryProperties($properties);
return $this->db->insert($this->table, $properties);
}
protected function quoteBinaryProperties(&$properties)
{
foreach ($properties as $key => $value) {
if ($this->isBinaryColumn($key)) {
$properties[$key] = $this->getConnection()->quoteBinary($value);
}
}
return $this->db->insert($this->table, $properties);
}
protected function isBinaryColumn($column)
{
return in_array($column, $this->binaryProperties);
return in_array($column, $this->binaryProperties) || $this->getUuidColumn() === $column;
}
/**
@ -1273,6 +1342,69 @@ abstract class DbObject
return $obj->existsInDb();
}
public static function uniqueIdExists(UuidInterface $uuid, DbConnection $connection)
{
$db = $connection->getDbAdapter();
$obj = new static;
$column = $obj->getUuidColumn();
$query = $db->select()
->from($obj->getTableName(), $column)
->where("$column = ?", $connection->quoteBinary($uuid->getBytes()));
$result = $db->fetchRow($query);
return $result !== false;
}
public static function requireWithUniqueId(UuidInterface $uuid, DbConnection $connection)
{
if ($object = static::loadWithUniqueId($uuid, $connection)) {
return $object;
}
throw new NotFoundError(sprintf(
'No %s with UUID=%s has been found',
(new static)->getTableName(),
$uuid->toString()
));
}
public static function loadWithUniqueId(UuidInterface $uuid, DbConnection $connection)
{
$db = $connection->getDbAdapter();
$obj = new static;
$query = $db->select()
->from($obj->getTableName())
->where($obj->getUuidColumn() . ' = ?', $connection->quoteBinary($uuid->getBytes()));
$result = $db->fetchRow($query);
if ($result) {
return $obj->setConnection($connection)->setDbProperties($result);
}
return null;
}
public function setUniqueId(UuidInterface $uuid)
{
if ($column = $this->getUuidColumn()) {
$binary = $uuid->getBytes();
$current = $this->get($column);
if ($current === null) {
$this->set($column, $binary);
} else {
if ($current !== $binary) {
throw new RuntimeException(sprintf(
'Changing the UUID (from %s to %s) is not allowed',
Uuid::fromBytes($current)->toString(),
Uuid::fromBytes($binary)->toString()
));
}
}
}
}
public function __destruct()
{
unset($this->db);

View File

@ -2,12 +2,10 @@
namespace Icinga\Module\Director\Data\Db;
use Icinga\Exception\NotFoundError;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Db\Branch\BranchModificationStore;
use Icinga\Module\Director\Db\Branch\IcingaObjectModification;
use function in_array;
use Icinga\Module\Director\Db\Branch\BranchActivity;
use Icinga\Module\Director\Db\Branch\BranchedObject;
/**
* Loader for Icinga/DbObjects
@ -21,96 +19,46 @@ class DbObjectStore
/** @var Db */
protected $connection;
/** @var Branch */
/** @var ?Branch */
protected $branch;
public function __construct(Db $connection)
public function __construct(Db $connection, Branch $branch = null)
{
$this->connection = $connection;
}
public function setBranch(Branch $branch)
{
$this->branch = $branch;
}
protected function typeSupportsBranches($type)
public function store(DbObject $object)
{
return in_array($type, ['host', 'user', 'zone', 'timeperiod']);
}
if ($this->branch && $this->branch->isBranch()) {
$activity = BranchActivity::forDbObject($object, $this->branch);
$this->connection->runFailSafeTransaction(function () use ($activity) {
$activity->store($this->connection);
BranchedObject::withActivity($activity, $this->connection)->store($this->connection);
});
/**
* @param string $shortType
* @param string|array $key
* @return DbObject
* @throws NotFoundError
*/
public function load($shortType, $key)
{
return $this->loadWithBranchModification($shortType, $key)[0];
}
/**
* @param string $shortType
* @param int|string|array $key
* @return array
* @throws NotFoundError
*/
public function loadWithBranchModification($shortType, $key)
{
/** @var string|DbObject $class */
$class = DbObjectTypeRegistry::classByType($shortType);
if ($this->branch && $this->branch->isBranch() && $this->typeSupportsBranches($shortType) && is_string($key)) {
$branchStore = new BranchModificationStore($this->connection, $shortType);
return true;
} else {
$branchStore = null;
return $object->store($this->connection);
}
$modification = null;
try {
if (is_int($key)) {
$object = $class::loadWithAutoIncId($key, $this->connection);
} else {
$object = $class::load($key, $this->connection);
}
if ($branchStore && $modification = $branchStore->eventuallyLoadModification(
$object->get('id'),
$this->branch->getUuid()
)) {
$object = IcingaObjectModification::applyModification($modification, $object, $this->connection);
}
} catch (NotFoundError $e) {
if ($this->branch && $this->branch->isBranch() && is_string($key)) {
$branchStore = new BranchModificationStore($this->connection, $shortType);
$modification = $branchStore->loadOptionalModificationByName($key, $this->branch->getUuid());
if ($modification) {
$object = IcingaObjectModification::applyModification($modification, null, $this->connection);
$object->setConnection($this->connection);
if ($id = $object->get('id')) { // Object has probably been renamed
try {
// TODO: can be one step I guess, but my brain is slow today ;-)
$renamedObject = $class::load($id, $this->connection);
$object = IcingaObjectModification::applyModification(
$modification,
$renamedObject,
$this->connection
);
} catch (NotFoundError $e) {
// Well... it was worth trying
$object->setConnection($this->connection);
$object->setBeingLoadedFromDb();
}
} else {
$object->setConnection($this->connection);
$object->setBeingLoadedFromDb();
}
} else {
throw $e;
}
} else {
throw $e;
}
}
public function delete(DbObject $object)
{
if ($this->branch && $this->branch->isBranch()) {
$activity = BranchActivity::deleteObject($object, $this->branch);
$this->connection->runFailSafeTransaction(function () use ($activity) {
$activity->store($this->connection);
BranchedObject::load(
$this->connection,
$activity->getObjectTable(),
$activity->getObjectUuid(),
$this->branch
)->delete($this->connection);
});
return true;
}
return [$object, $modification];
return $object->delete();
}
}

View File

@ -3,9 +3,14 @@
namespace Icinga\Module\Director\Data\Db;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\IcingaObject;
class DbObjectTypeRegistry
{
/**
* @param $type
* @return string|DbObject Fake typehint for IDE
*/
public static function classByType($type)
{
// allow for icinga_host and host
@ -44,6 +49,23 @@ class DbObjectTypeRegistry
return 'Icinga\\Module\\Director\\Objects\\' . $prefix . ucfirst($type);
}
public static function tableNameByType($type)
{
$class = static::classByType($type);
$dummy = $class::create([]);
return $dummy->getTableName();
}
public static function shortTypeForObject(DbObject $object)
{
if ($object instanceof IcingaObject) {
return $object->getShortTableName();
}
return $object->getTableName();
}
public static function newObject($type, $properties = [], Db $db = null)
{
/** @var DbObject $class fake hint for the IDE, it's a string */

View File

@ -52,4 +52,18 @@ class Json
return $result;
}
/**
* @param $string
* @return ?string
* @throws JsonEncodeException
*/
public static function decodeOptional($string)
{
if ($string === null) {
return null;
}
return static::decode($string);
}
}

View File

@ -30,8 +30,8 @@ class Branch
/** @var @var string */
protected $description;
/** @var bool */
protected $shouldBeMerged;
/** @var ?int */
protected $tsMergeRequest;
/** @var int */
protected $cntActivities;
@ -39,10 +39,16 @@ class Branch
public static function fromDbRow(stdClass $row)
{
$self = new static;
if (is_resource($row->uuid)) {
$row->uuid = stream_get_contents($row->uuid);
}
if (strlen($row->uuid) !== 16) {
throw new RuntimeException('Valid UUID expected, got ' . var_export($row->uuid, 1));
}
$self->branchUuid = Uuid::fromBytes($row->uuid);
$self->name = $row->branch_name;
$self->owner = $row->owner;
$self->shouldBeMerged = $row->should_be_merged === 'y';
$self->tsMergeRequest = $row->ts_merge_request;
if (isset($row->cnt_activities)) {
$self->cntActivities = $row->cnt_activities;
} else {
@ -118,6 +124,13 @@ class Branch
return $this->branchUuid !== null;
}
public function assertBranch()
{
if ($this->isMain()) {
throw new RuntimeException('Branch expected, but working in main branch');
}
}
/**
* @return bool
*/
@ -131,7 +144,7 @@ class Branch
*/
public function shouldBeMerged()
{
return $this->shouldBeMerged;
return $this->tsMergeRequest !== null;
}
/**

View File

@ -0,0 +1,376 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Authentication\Auth;
use Icinga\Exception\NotFoundError;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
use Icinga\Module\Director\Data\Json;
use Icinga\Module\Director\Data\SerializableValue;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\IcingaObject;
use InvalidArgumentException;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use RuntimeException;
class BranchActivity
{
const DB_TABLE = 'director_branch_activity';
const ACTION_CREATE = 'create';
const ACTION_MODIFY = 'modify';
const ACTION_DELETE = 'delete';
/** @var int */
protected $timestampNs;
/** @var UuidInterface */
protected $objectUuid;
/** @var UuidInterface */
protected $branchUuid;
/** @var string create, modify, delete */
protected $action;
/** @var string */
protected $objectTable;
/** @var string */
protected $author;
/** @var SerializableValue */
protected $modifiedProperties;
/** @var ?SerializableValue */
protected $formerProperties;
public function __construct(
UuidInterface $objectUuid,
UuidInterface $branchUuid,
$action,
$objectType,
$author,
SerializableValue $modifiedProperties,
SerializableValue $formerProperties
) {
$this->objectUuid = $objectUuid;
$this->branchUuid = $branchUuid;
$this->action = $action;
$this->objectTable = $objectType;
$this->author = $author;
$this->modifiedProperties = $modifiedProperties;
$this->formerProperties = $formerProperties;
}
public static function deleteObject(DbObject $object, Branch $branch)
{
return new static(
$object->getUniqueId(),
$branch->getUuid(),
self::ACTION_DELETE,
$object->getTableName(),
Auth::getInstance()->getUser()->getUsername(),
SerializableValue::fromSerialization(null),
SerializableValue::fromSerialization(self::getFormerObjectProperties($object))
);
}
public static function forDbObject(DbObject $object, Branch $branch)
{
if (! $object->hasBeenModified()) {
throw new InvalidArgumentException('Cannot get modifications for unmodified object');
}
if (! $branch->isBranch()) {
throw new InvalidArgumentException('Branch activity requires an active branch');
}
$author = Auth::getInstance()->getUser()->getUsername();
if ($object instanceof IcingaObject && $object->shouldBeRemoved()) {
$action = self::ACTION_DELETE;
$old = self::getFormerObjectProperties($object);
$new = null;
} elseif ($object->hasBeenLoadedFromDb()) {
$action = self::ACTION_MODIFY;
$old = self::getFormerObjectProperties($object);
$new = self::getObjectProperties($object);
} else {
$action = self::ACTION_CREATE;
$old = null;
$new = self::getObjectProperties($object);
}
if ($new !== null) {
$new = PlainObjectPropertyDiff::calculate(
$old,
$new
);
}
return new static(
$object->getUniqueId(),
$branch->getUuid(),
$action,
$object->getTableName(),
$author,
SerializableValue::fromSerialization($new),
SerializableValue::fromSerialization($old)
);
}
public function applyToDbObject(DbObject $object)
{
if (!$this->isActionModify()) {
throw new RuntimeException('Only BranchActivity instances with action=modify can be applied');
}
foreach ($this->getModifiedProperties()->jsonSerialize() as $key => $value) {
$object->set($key, $value);
}
return $object;
}
public function createDbObject()
{
if (!$this->isActionCreate()) {
throw new RuntimeException('Only BranchActivity instances with action=create can create objects');
}
$class = DbObjectTypeRegistry::classByType($this->getObjectTable());
$object = $class::create();
$object->setUniqueId($this->getObjectUuid());
foreach ($this->getModifiedProperties()->jsonSerialize() as $key => $value) {
$object->set($key, $value);
}
return $object;
}
public function deleteDbObject(Db $connection)
{
if (!$this->isActionDelete()) {
throw new RuntimeException('Only BranchActivity instances with action=delete can delete objects');
}
$db = $connection->getDbAdapter();
return $db->delete($this->getObjectTable(), $db->quoteInto(
'uuid = ?',
$connection->quoteBinary($this->getObjectUuid()->getBytes())
));
}
public static function load($ts, Db $connection)
{
$db = $connection->getDbAdapter();
$row = $db->fetchRow(
$db->select()->from('director_branch_activity')->where('timestamp_ns = ?', $ts)
);
if ($row) {
return static::fromDbRow($row);
}
throw new NotFoundError('Not found');
}
protected static function fixPgResource(&$value)
{
if (is_resource($value)) {
$value = stream_get_contents($value);
}
}
public static function fromDbRow($row)
{
static::fixPgResource($row->object_uuid);
static::fixPgResource($row->branch_uuid);
$activity = new static(
Uuid::fromBytes($row->object_uuid),
Uuid::fromBytes($row->branch_uuid),
$row->action,
$row->object_table,
$row->author,
SerializableValue::fromSerialization(Json::decodeOptional($row->modified_properties)),
SerializableValue::fromSerialization(Json::decodeOptional($row->former_properties))
);
$activity->timestampNs = $row->timestamp_ns;
return $activity;
}
/**
* Must be run in a transaction! Repeatable read?
* @param Db $connection
* @throws \Icinga\Module\Director\Exception\JsonEncodeException
* @throws \Zend_Db_Adapter_Exception
*/
public function store(Db $connection)
{
if ($this->timestampNs !== null) {
throw new InvalidArgumentException(sprintf(
'Cannot store activity with a given timestamp: %s',
$this->timestampNs
));
}
$db = $connection->getDbAdapter();
$last = $db->fetchRow(
$db->select()->from('director_branch_activity', ['timestamp_ns' => 'MAX(timestamp_ns)'])
);
if (PHP_INT_SIZE !== 8) {
throw new RuntimeException('PHP with 64bit integer support is required');
}
$timestampNs = (int) floor(microtime(true) * 1000000);
if ($last) {
if ($last->timestamp_ns >= $timestampNs) {
$timestampNs = $last + 1;
}
}
$old = Json::encode($this->formerProperties);
$new = Json::encode($this->modifiedProperties);
$db->insert(self::DB_TABLE, [
'timestamp_ns' => $timestampNs,
'object_uuid' => $connection->quoteBinary($this->objectUuid->getBytes()),
'branch_uuid' => $connection->quoteBinary($this->branchUuid->getBytes()),
'action' => $this->action,
'object_table' => $this->objectTable,
'author' => $this->author,
'former_properties' => $old,
'modified_properties' => $new,
]);
}
/**
* @return int
*/
public function getTimestampNs()
{
return $this->timestampNs;
}
/**
* @return int
*/
public function getTimestamp()
{
return (int) floor($this->timestampNs / 1000000);
}
/**
* @return UuidInterface
*/
public function getObjectUuid()
{
return $this->objectUuid;
}
/**
* @return UuidInterface
*/
public function getBranchUuid()
{
return $this->branchUuid;
}
/**
* @return string
*/
public function getObjectName()
{
return $this->getProperty('object_name', 'unknown object name');
}
/**
* @return string
*/
public function getAction()
{
return $this->action;
}
public function isActionDelete()
{
return $this->action === self::ACTION_DELETE;
}
public function isActionCreate()
{
return $this->action === self::ACTION_CREATE;
}
public function isActionModify()
{
return $this->action === self::ACTION_MODIFY;
}
/**
* @return string
*/
public function getObjectTable()
{
return $this->objectTable;
}
/**
* @return string
*/
public function getAuthor()
{
return $this->author;
}
/**
* @return ?SerializableValue
*/
public function getModifiedProperties()
{
return $this->modifiedProperties;
}
/**
* @return ?SerializableValue
*/
public function getFormerProperties()
{
return $this->formerProperties;
}
public function getProperty($key, $default = null)
{
if ($this->modifiedProperties) {
$properties = $this->modifiedProperties->jsonSerialize();
if (isset($properties->$key)) {
return $properties->$key;
}
}
if ($this->formerProperties) {
$properties = $this->formerProperties->jsonSerialize();
if (isset($properties->$key)) {
return $properties->$key;
}
}
return $default;
}
protected static function getFormerObjectProperties(DbObject $object)
{
if (! $object instanceof IcingaObject) {
throw new RuntimeException('Plain object helpers for DbObject must be implemented');
}
return (array) $object->getPlainUnmodifiedObject();
}
protected static function getObjectProperties(DbObject $object)
{
if (! $object instanceof IcingaObject) {
throw new RuntimeException('Plain object helpers for DbObject must be implemented');
}
return (array) $object->toPlainObject(false, true);
}
}

View File

@ -1,89 +0,0 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Module\Director\Data\Json;
use Icinga\Module\Director\Db;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
class BranchActivityStore
{
protected $connection;
protected $db;
protected $table = 'director_branch_activity';
public function __construct(Db $connection)
{
$this->connection = $connection;
$this->db = $connection->getDbAdapter();
}
public function count(UuidInterface $branchUuid)
{
$query = $this->db->select()
->from($this->table, ['cnt' => 'COUNT(*)'])
->where('branch_uuid = ?', $branchUuid->getBytes());
return (int) $this->db->fetchOne($query);
}
public function loadAll(UuidInterface $branchUuid)
{
$query = $this->db->select()
->from($this->table)
->where('branch_uuid = ?', $branchUuid->getBytes())
->order('change_time DESC');
return $this->db->fetchAll($query);
}
public static function objectModificationForDbRow($row)
{
$modification = ObjectModification::fromSerialization(json_decode($row->change_set));
return $modification;
}
/**
* Must be run in a transaction!
*
* @param ObjectModification $modification
* @param UuidInterface $branchUuid
* @throws \Icinga\Module\Director\Exception\JsonEncodeException
* @throws \Zend_Db_Adapter_Exception
*/
public function persistModification(ObjectModification $modification, UuidInterface $branchUuid)
{
$db = $this->db;
$last = $db->fetchOne(
$db->select()
->from('director_branch_activity', 'checksum')
->order('change_time DESC')
->order('uuid') // Just in case, this gives a guaranteed order
);
// TODO: eventually implement more checks, allow only one change per millisecond
// alternatively use last change_time plus one, when now < change_time
if (strlen($last) !== 20) {
$last = '';
}
$binaryUuid = Uuid::uuid4()->getBytes();
$timestampMs = $this->now();
$encoded = Json::encode($modification);
// HINT: checksums are useless! -> merge only
$this->db->insert('director_branch_activity', [
'uuid' => $binaryUuid,
'branch_uuid' => $branchUuid->getBytes(),
'change_set' => $encoded, // TODO: rename -> object_modification
'change_time' => $timestampMs, // TODO: ns!!
'checksum' => sha1("$last/$binaryUuid/$timestampMs/$encoded", true),
'parent_checksum' => $last === '' ? null : $last,
]);
}
protected function now()
{
return floor(microtime(true) * 1000);
}
}

View File

@ -3,9 +3,9 @@
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Data\InvalidDataException;
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
use Icinga\Module\Director\Db;
use Ramsey\Uuid\Uuid;
use Icinga\Module\Director\Objects\IcingaObject;
use Ramsey\Uuid\UuidInterface;
class BranchMerger
@ -20,7 +20,7 @@ class BranchMerger
protected $db;
/** @var array */
protected $ignoreUuids = [];
protected $ignoreActivities = [];
/** @var bool */
protected $ignoreDeleteWhenMissing = false;
@ -64,88 +64,76 @@ class BranchMerger
}
/**
* @param array $uuids
* @param int $key
*/
public function ignoreUuids(array $uuids)
public function ignoreActivity($key)
{
foreach ($uuids as $uuid) {
$this->ignoreUuid($uuid);
}
$this->ignoreActivities[$key] = true;
}
/**
* @param UuidInterface|string $uuid
* @param BranchActivity $activity
* @return bool
*/
public function ignoreUuid($uuid)
public function ignoresActivity(BranchActivity $activity)
{
if (is_string($uuid)) {
$uuid = Uuid::fromString($uuid);
} elseif (! ($uuid instanceof UuidInterface)) {
throw new InvalidDataException('UUID', $uuid);
}
$binary = $uuid->getBytes();
$this->ignoreUuids[$binary] = $binary;
return isset($this->ignoreActivities[$activity->getTimestampNs()]);
}
/**
* @throws MergeError
* @throws \Exception
*/
public function merge()
{
$this->connection->runFailSafeTransaction(function () {
$activities = new BranchActivityStore($this->connection);
$rows = $activities->loadAll($this->branchUuid);
$query = $this->db->select()
->from(BranchActivity::DB_TABLE)
->where('branch_uuid = ?', $this->connection->quoteBinary($this->branchUuid->getBytes()))
->order('timestamp_ns ASC');
$rows = $this->db->fetchAll($query);
foreach ($rows as $row) {
$modification = BranchActivityStore::objectModificationForDbRow($row);
$this->applyModification($modification, Uuid::fromBytes($row->uuid));
$activity = BranchActivity::fromDbRow($row);
$this->applyModification($activity);
}
$this->db->delete('director_branch', $this->db->quoteInto('uuid = ?', $this->branchUuid->getBytes()));
(new BranchStore($this->connection))->deleteByUuid($this->branchUuid);
});
}
/**
* @param ObjectModification $modification
* @param UuidInterface $uuid
* @param BranchActivity $activity
* @throws MergeError
* @throws \Icinga\Exception\NotFoundError
* @throws \Icinga\Module\Director\Exception\DuplicateKeyException
*/
protected function applyModification(ObjectModification $modification, UuidInterface $uuid)
protected function applyModification(BranchActivity $activity)
{
$binaryUuid = $uuid->getBytes();
/** @var string|DbObject $class */
$class = $modification->getClassName();
$keyParams = (array) $modification->getKeyParams();
if (array_keys($keyParams) === ['object_name']) {
$keyParams = $keyParams['object_name'];
}
$class = DbObjectTypeRegistry::classByType($activity->getObjectTable());
$uuid = $activity->getObjectUuid();
$exists = $class::exists($keyParams, $this->connection);
if ($modification->isCreation()) {
$exists = $class::uniqueIdExists($uuid, $this->connection);
if ($activity->isActionCreate()) {
if ($exists) {
if (! isset($this->ignoreUuids[$uuid->getBytes()])) {
throw new MergeErrorRecreateOnMerge($modification, $uuid);
if (! $this->ignoresActivity($activity)) {
throw new MergeErrorRecreateOnMerge($activity);
}
} else {
$object = IcingaObjectModification::applyModification($modification, null, $this->connection);
$object->store($this->connection);
$activity->createDbObject()->store($this->connection);
}
} elseif ($modification->isDeletion()) {
} elseif ($activity->isActionDelete()) {
if ($exists) {
$object = IcingaObjectModification::applyModification($modification, $class::load($keyParams, $this->connection), $this->connection);
$object->setConnection($this->connection);
$object->delete();
} elseif (! $this->ignoreDeleteWhenMissing && ! isset($this->ignoreUuids[$binaryUuid])) {
throw new MergeErrorDeleteMissingObject($modification, $uuid);
$activity->deleteDbObject($this->connection);
} elseif (! $this->ignoreDeleteWhenMissing && ! $this->ignoresActivity($activity)) {
throw new MergeErrorDeleteMissingObject($activity);
}
} else {
if ($exists) {
$object = IcingaObjectModification::applyModification($modification, $class::load($keyParams, $this->connection), $this->connection);
// TODO: du änderst ein Objekt, und die geänderte Eigenschaften haben sich seit der Änderung geändert
$object->store($this->connection);
} elseif (! $this->ignoreModificationWhenMissing && ! isset($this->ignoreUuids[$binaryUuid])) {
throw new MergeErrorModificationForMissingObject($modification, $uuid);
$current = $class::requireWithUniqueId($uuid, $this->connection);
$activity->applyToDbObject($class::requireWithUniqueId($uuid, $this->connection))->store();
// TODO: you modified an object, and related properties have been changed in the meantime.
// We're able to detect this with the given data, and might want to offer a rebase.
} elseif (! $this->ignoreModificationWhenMissing && ! $this->ignoresActivity($activity)) {
throw new MergeErrorModificationForMissingObject($activity);
}
}
}

View File

@ -12,10 +12,13 @@ class BranchModificationInspection
{
use TranslationHelper;
protected $connection;
protected $db;
public function __construct(Db $connection)
{
$this->connection = $connection;
$this->db = $connection->getDbAdapter();
}
@ -74,10 +77,10 @@ class BranchModificationInspection
public function loadSingleTableStats($table, UuidInterface $uuid)
{
$query = $this->db->select()->from($table, [
'cnt_created' => "SUM(CASE WHEN created = 'y' THEN 1 ELSE 0 END)",
'cnt_deleted' => "SUM(CASE WHEN deleted = 'y' THEN 1 ELSE 0 END)",
'cnt_modified' => "SUM(CASE WHEN deleted = 'n' AND created = 'n' THEN 1 ELSE 0 END)",
])->where('branch_uuid = ?', $uuid->getBytes());
'cnt_created' => "SUM(CASE WHEN branch_created = 'y' THEN 1 ELSE 0 END)",
'cnt_deleted' => "SUM(CASE WHEN branch_deleted = 'y' THEN 1 ELSE 0 END)",
'cnt_modified' => "SUM(CASE WHEN branch_deleted = 'n' AND branch_created = 'n' THEN 1 ELSE 0 END)",
])->where('branch_uuid = ?', $this->connection->quoteBinary($uuid->getBytes()));
return $this->db->fetchRow($query);
}

View File

@ -1,267 +0,0 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
use Icinga\Module\Director\Data\Json;
use Icinga\Module\Director\Db;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
class BranchModificationStore
{
// TODO: Ranges is weird. key = scheduled_downtime_id, range_type, range_key
const ENCODED_ARRAYS = ['imports', 'groups', 'ranges'];
const ENCODED_DICTIONARIES = ['vars', 'arguments'];
protected $connection;
protected $db;
protected $shortType;
protected $table;
public function __construct(Db $connection, $shortType)
{
$this->connection = $connection;
$this->shortType = $shortType;
$this->table = "branched_icinga_$shortType";
$this->db = $connection->getDbAdapter();
}
public function loadAll(UuidInterface $branchUuid)
{
return $this->db->fetchAll($this->select()->where('branch_uuid = ?', $branchUuid->getBytes()));
}
public function eventuallyLoadModification($objectId, UuidInterface $branchUuid)
{
if ($objectId) {
$row = $this->fetchOptional($objectId, $branchUuid);
} else {
return null;
}
if ($row) {
$id = (int) $objectId;
$class = DbObjectTypeRegistry::classByType($this->shortType);
if ($row->deleted === 'y') {
return ObjectModification::delete($class, $id, static::cleanupRow($row));
}
if ($row->created === 'y') {
return ObjectModification::create($class, $row->object_name, static::cleanupRow($row));
}
// TODO: Former properties null? DB Problem.
return ObjectModification::modify($class, $id, null, static::filterNull(static::cleanupRow($row)));
}
return null;
}
public function loadOptionalModificationByName($objectName, UuidInterface $branchUuid)
{
$row = $this->fetchOptionalByName($objectName, $branchUuid);
if ($row) {
$class = DbObjectTypeRegistry::classByType($this->shortType);
if ($row->created === 'y') {
return ObjectModification::create($class, $row->object_name, static::cleanupRow($row));
}
if ($row->deleted === 'y') {
throw new \RuntimeException('Delete for a probably non-existing object? Not sure');
// return ObjectModification::delete($class, $row->object_name, ...);
}
// Hint: this is not correct. Former properties are missing. We finish up here, when loading renamed objects.
return ObjectModification::modify($class, $row->object_name, [], static::filterNull(static::cleanupRow($row)));
// TODO: better exception, handle this in the frontend
//throw new \RuntimeException('Got a modification for a probably non-existing object');
}
return null;
}
protected function filterNull($row)
{
return (object) array_filter((array) $row, function ($value) {
return $value !== null;
});
}
protected function cleanupRow($row)
{
unset($row->object_id, $row->class, $row->branch_uuid, $row->uuid, $row->created, $row->deleted);
return $row;
}
protected function fetchOptional($objectId, UuidInterface $branchUuid)
{
return $this->optionalRow($this->select()
->where('object_id = ?', $objectId)
->where('branch_uuid = ?', $branchUuid->getBytes()));
}
protected function fetchOptionalByName($objectName, UuidInterface $branchUuid)
{
return $this->optionalRow($this->select()
->where('object_name = ?', $objectName)
->where('branch_uuid = ?', $branchUuid->getBytes()));
}
protected function optionalRow($query)
{
if ($row = $this->db->fetchRow($query)) {
$this->decodeEncodedProperties($row);
return $row;
}
return null;
}
protected function select()
{
return $this->db->select()->from($this->table);
}
protected function decodeEncodedProperties($row)
{
foreach (array_merge(self::ENCODED_ARRAYS, self::ENCODED_DICTIONARIES) as $encodedProperty) {
// vars, imports and groups might be null or not set at all (if not supported)
if (! empty($row->$encodedProperty)) {
$row->$encodedProperty = Json::decode($row->$encodedProperty);
}
}
}
protected function prepareModificationForStore(ObjectModification $modification)
{
// TODO.
}
public function store(ObjectModification $modification, $objectId, UuidInterface $branchUuid)
{
if ($properties = $modification->getProperties()) {
$properties = (array) $properties->jsonSerialize();
} else {
$properties = [];
}
// Former properties are not needed, as they are dealt with in persistModification.
if ($objectId) {
$existing = $this->fetchOptional($objectId, $branchUuid);
} else {
$existing = null;
}
foreach (self::ENCODED_DICTIONARIES as $deepProperty) {
if (isset($properties[$deepProperty])) {
// TODO: flags
$properties[$deepProperty] = Json::encode($properties[$deepProperty]);
}
}
/* TODO: Nothing should be flat here, verify and remove this comment
foreach (self::ENCODED_DICTIONARIES as $property) {
$this->combineAndEncodeFlatDictionaries($properties, $existing, $property);
}
*/
foreach (self::ENCODED_ARRAYS as $deepProperty) {
if (isset($properties[$deepProperty])) {
// TODO: flags
$properties[$deepProperty] = Json::encode($properties[$deepProperty]);
}
}
$this->connection->runFailSafeTransaction(function () use (
$existing,
$modification,
$objectId,
$branchUuid,
$properties
) {
if ($existing) {
if ($modification->isDeletion()) {
$this->deleteExisting($existing->uuid);
$this->delete($objectId, $branchUuid);
} elseif ($existing->deleted === 'y') {
$this->deleteExisting($existing->uuid);
$this->create($objectId, $branchUuid, $properties);
} else {
$this->update($existing->uuid, $properties);
}
} else {
if ($modification->isCreation()) {
$this->create($objectId, $branchUuid, $properties);
} elseif ($modification->isDeletion()) {
$this->delete($objectId, $branchUuid);
} else {
$this->createModification($objectId, $branchUuid, $properties);
}
}
$activities = new BranchActivityStore($this->connection);
$activities->persistModification($modification, $branchUuid);
});
}
protected function combineAndEncodeFlatDictionaries(&$properties, $existing, $prefix)
{
if ($existing && ! empty($existing->$prefix)) {
// $vars = (array) Json::decode($existing->vars);
$vars = (array) ($existing->$prefix);
} else {
$vars = [];
}
$length = strlen($prefix) + 1;
foreach ($properties as $key => $value) {
if (substr($key, 0, $length) === "$prefix.") {
$vars[substr($key, $length)] = $value;
}
}
if (! empty($vars)) {
foreach (array_keys($vars) as $key) {
unset($properties["$prefix.$key"]);
}
$properties[$prefix] = Json::encode((object) $vars); // TODO: flags!
}
}
protected function deleteExisting($binaryUuid)
{
$this->db->delete($this->table, $this->db->quoteInto('uuid = ?', $binaryUuid));
}
protected function create($objectId, UuidInterface $branchUuid, $properties)
{
$this->db->insert($this->table, [
'branch_uuid' => $branchUuid->getBytes(),
'uuid' => Uuid::uuid4()->getBytes(),
'object_id' => $objectId,
'created' => 'y',
] + (array) $properties);
}
protected function delete($objectId, UuidInterface $branchUuid)
{
$this->db->insert($this->table, [
'branch_uuid' => $branchUuid->getBytes(),
'uuid' => Uuid::uuid4()->getBytes(),
'object_id' => $objectId,
'deleted' => 'y',
]);
}
protected function createModification($objectId, UuidInterface $branchUuid, $properties)
{
$this->db->insert($this->table, [
'branch_uuid' => $branchUuid->getBytes(),
'uuid' => Uuid::uuid4()->getBytes(),
'object_id' => $objectId,
] + (array) $properties);
}
protected function update($binaryUuid, $properties)
{
$this->db->update($this->table, [
'uuid' => Uuid::uuid4()->getBytes(),
] + (array) $properties, $this->db->quoteInto('uuid = ?', $binaryUuid));
}
}

View File

@ -0,0 +1,121 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Module\Director\Data\Json;
use function in_array;
/**
* Hardcoded branch-related settings
*/
class BranchSettings
{
// TODO: Ranges is weird. key = scheduled_downtime_id, range_type, range_key
const ENCODED_ARRAYS = ['imports', 'groups', 'ranges', 'users', 'usergroups'];
const ENCODED_DICTIONARIES = ['vars', 'arguments'];
const BRANCH_SPECIFIC_PROPERTIES = [
'uuid',
'branch_uuid',
'branch_created',
'branch_deleted',
'set_null',
];
const BRANCH_BOOLEANS = [
'branch_created',
'branch_deleted',
];
const RELATED_SETS = [
'types',
'states',
];
public static function propertyIsEncodedArray($property)
{
return in_array($property, self::ENCODED_ARRAYS, true);
}
public static function propertyIsRelatedSet($property)
{
// TODO: get from object class
return in_array($property, self::RELATED_SETS, true);
}
public static function propertyIsEncodedDictionary($property)
{
return in_array($property, self::ENCODED_DICTIONARIES, true);
}
public static function propertyIsBranchSpecific($property)
{
return in_array($property, self::BRANCH_SPECIFIC_PROPERTIES, true);
}
public static function flattenEncodedDicationaries(array &$properties)
{
foreach (self::ENCODED_DICTIONARIES as $property) {
self::flattenProperty($properties, $property);
}
}
public static function normalizeBranchedObjectFromDb($row)
{
$normalized = [];
$row = (array) $row;
foreach ($row as $key => $value) {
if (! static::propertyIsBranchSpecific($key)) {
if (is_resource($value)) {
$value = stream_get_contents($value);
}
if ($value !== null && static::propertyIsEncodedArray($key)) {
$value = Json::decode($value);
}
if ($value !== null && static::propertyIsRelatedSet($key)) {
// TODO: We might want to combine them (current VS branched)
$value = Json::decode($value);
}
if ($value !== null && static::propertyIsEncodedDictionary($key)) {
$value = Json::decode($value);
}
if ($value !== null) {
$normalized[$key] = $value;
}
}
}
static::flattenEncodedDicationaries($row);
if (isset($row['set_null'])) {
foreach (Json::decode($row['set_null']) as $property) {
$normalized[$property] = null;
}
}
foreach (self::BRANCH_BOOLEANS as $key) {
if ($row[$key] === 'y') {
$row[$key] = true;
} elseif ($row[$key] === 'n') {
$row[$key] = false;
} else {
throw new \RuntimeException(sprintf(
"Boolean DB property expected, got '%s' for '%s'",
$row[$key],
$key
));
}
}
return $normalized;
}
public static function flattenProperty(array &$properties, $property)
{
// TODO: dots in varnames -> throw or escape?
if (isset($properties[$property])) {
foreach ((array) $properties[$property] as $key => $value) {
$properties["$property.$key"] = $value;
}
unset($properties[$property]);
}
}
}

View File

@ -43,6 +43,9 @@ class BranchStore
protected function newFromDbResult($query)
{
if ($row = $this->db->fetchRow($query)) {
if (is_resource($row->uuid)) {
$row->uuid = stream_get_contents($row->uuid);
}
return Branch::fromDbRow($row);
}
@ -52,7 +55,7 @@ class BranchStore
public function setReadyForMerge(Branch $branch)
{
$update = [
'should_be_merged' => 'y'
'ts_merge_request' => (int) floor(microtime(true) * 1000000)
];
$name = $branch->getName();
@ -72,8 +75,8 @@ class BranchStore
'owner' => 'b.owner',
'branch_name' => 'b.branch_name',
'description' => 'b.description',
'should_be_merged' => 'b.should_be_merged',
'cnt_activities' => 'COUNT(ba.change_time)',
'ts_merge_request' => 'b.ts_merge_request',
'cnt_activities' => 'COUNT(ba.timestamp_ns)',
])->joinLeft(
['ba' => 'director_branch_activity'],
'b.uuid = ba.branch_uuid',
@ -103,16 +106,36 @@ class BranchStore
*/
public function createBranchByName($branchName, $owner)
{
$this->uuid = Uuid::uuid4();
$uuid = Uuid::uuid4();
$properties = [
'uuid' => $this->uuid->getBytes(),
'uuid' => $this->connection->quoteBinary($uuid->getBytes()),
'branch_name' => $branchName,
'owner' => $owner,
'description' => null,
'should_be_merged' => 'n',
'ts_merge_request' => null,
];
$this->db->insert($this->table, $properties);
return Branch::fromDbRow((object) $properties);
if ($branch = static::fetchBranchByUuid($uuid)) {
return $branch;
}
throw new \RuntimeException(sprintf(
'Branch with UUID=%s has been created, but could not be fetched from DB',
$uuid->toString()
));
}
public function deleteByUuid(UuidInterface $uuid)
{
return $this->db->delete($this->table, $this->db->quoteInto(
'uuid = ?',
$this->connection->quoteBinary($uuid->getBytes())
));
}
public function delete(Branch $branch)
{
return $this->deleteByUuid($branch->getUuid());
}
}

View File

@ -0,0 +1,387 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Exception\NotFoundError;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
use Icinga\Module\Director\Data\Json;
use Icinga\Module\Director\Db;
use Ramsey\Uuid\UuidInterface;
use stdClass;
class BranchedObject
{
/** @var UuidInterface */
protected $branchUuid;
/** @var ?DbObject */
protected $object;
/** @var ?stdClass */
protected $changes;
/** @var bool */
protected $branchDeleted;
/** @var bool */
protected $branchCreated;
/** @var UuidInterface */
private $objectUuid;
/** @var string */
private $objectTable;
/** @var bool */
private $loadedAsBranchedObject = false;
/**
* @param BranchActivity $activity
* @param Db $connection
* @return static
*/
public static function withActivity(BranchActivity $activity, Db $connection)
{
return self::loadOptional(
$connection,
$activity->getObjectTable(),
$activity->getObjectUuid(),
$activity->getBranchUuid()
)->applyActivity($activity, $connection);
}
public function store(Db $connection)
{
if ($this->object && ! $this->object->hasBeenModified() && empty($this->changes)) {
return false;
}
$db = $connection->getDbAdapter();
$properties = [
'branch_deleted' => $this->branchDeleted ? 'y' : 'n',
'branch_created' => $this->branchCreated ? 'y' : 'n',
] + $this->prepareChangedProperties();
$table = 'branched_' . $this->objectTable;
if ($this->loadedAsBranchedObject) {
return $db->update(
$table,
$properties,
$this->prepareWhereString($connection)
) === 1;
} else {
try {
return $db->insert($table, $this->prepareKeyProperties($connection) + $properties) === 1;
} catch (\Exception $e) {
var_dump($e->getMessage());
var_dump($this->prepareKeyProperties($connection) + $properties);
exit;
}
}
}
public function delete(Db $connection)
{
$db = $connection->getDbAdapter();
$table = 'branched_' . $this->objectTable;
$branchCreated = $db->fetchOne($this->filterQuery($db->select()->from($table, 'branch_created'), $connection));
// We do not want to nullify all properties, therefore: delete & insert
$db->delete($table, $this->prepareWhereString($connection));
if (! $branchCreated) {
// No need to insert a deleted object in case this object lived in this branch only
return $db->insert($table, $this->prepareKeyProperties($connection) + [
'branch_deleted' => 'y',
'branch_created' => 'n',
]) === 1;
}
return true;
}
protected function prepareKeyProperties(Db $connection)
{
return [
'uuid' => $connection->quoteBinary($this->objectUuid->getBytes()),
'branch_uuid' => $connection->quoteBinary($this->branchUuid->getBytes()),
];
}
protected function prepareWhereString(Db $connection)
{
$db = $connection->getDbAdapter();
$objectUuid = $connection->quoteBinary($this->objectUuid->getBytes());
$branchUuid = $connection->quoteBinary($this->branchUuid->getBytes());
return $db->quoteInto('uuid = ?', $objectUuid) . $db->quoteInto(' AND branch_uuid = ?', $branchUuid);
}
/**
* @param \Zend_Db_Select $query
* @param Db $connection
* @return \Zend_Db_Select
*/
protected function filterQuery(\Zend_Db_Select $query, Db $connection)
{
return $query->where('uuid = ?', $connection->quoteBinary($this->objectUuid->getBytes()))
->where('branch_uuid = ?', $connection->quoteBinary($this->branchUuid->getBytes()));
}
protected function prepareChangedProperties()
{
$properties = (array) $this->changes;
foreach (BranchSettings::ENCODED_DICTIONARIES as $property) {
$this->combineFlatDictionaries($properties, $property);
}
foreach (BranchSettings::ENCODED_DICTIONARIES as $property) {
if (isset($properties[$property])) {
$properties[$property] = Json::encode($properties[$property]);
}
}
foreach (BranchSettings::ENCODED_ARRAYS as $property) {
if (isset($properties[$property])) {
$properties[$property] = Json::encode($properties[$property]);
}
}
foreach (BranchSettings::RELATED_SETS as $property) {
if (isset($properties[$property])) {
$properties[$property] = Json::encode($properties[$property]);
}
}
$setNull = [];
if (array_key_exists('disabled', $properties) && $properties['disabled'] === null) {
unset($properties['disabled']);
}
foreach ($properties as $key => $value) {
if ($value === null) {
$setNull[] = $key;
}
}
if (empty($setNull)) {
$properties['set_null'] = null;
} else {
$properties['set_null'] = Json::encode($setNull);
}
return $properties;
}
protected function combineFlatDictionaries(&$properties, $prefix)
{
$vars = [];
$length = strlen($prefix) + 1;
foreach ($properties as $key => $value) {
if (substr($key, 0, $length) === "$prefix.") {
$vars[substr($key, $length)] = $value;
}
}
if (! empty($vars)) {
foreach (array_keys($vars) as $key) {
unset($properties["$prefix.$key"]);
}
$properties[$prefix] = (object) $vars;
}
}
public function applyActivity(BranchActivity $activity, Db $connection)
{
if ($activity->isActionDelete()) {
throw new \RuntimeException('Cannot apply a delete action');
}
if ($activity->isActionCreate()) {
if ($this->hasBeenTouchedByBranch()) {
throw new \RuntimeException('Cannot apply a CREATE activity to an already branched object');
} else {
$this->branchCreated = true;
}
}
foreach ($activity->getModifiedProperties()->jsonSerialize() as $key => $value) {
$this->changes[$key] = $value;
}
return $this;
}
/**
* @param Db $connection
* @param string $objectTable
* @param UuidInterface $uuid
* @param Branch $branch
* @return static
* @throws NotFoundError
*/
public static function load(Db $connection, $objectTable, UuidInterface $uuid, Branch $branch)
{
$object = static::loadOptional($connection, $objectTable, $uuid, $branch->getUuid());
if ($object->getOriginalDbObject() === null && ! $object->hasBeenTouchedByBranch()) {
throw new NotFoundError('Not found');
}
return $object;
}
/**
* @return bool
*/
public function hasBeenTouchedByBranch()
{
return $this->loadedAsBranchedObject;
}
/**
* @return bool
*/
public function hasBeenDeletedByBranch()
{
return $this->branchDeleted;
}
/**
* @return bool
*/
public function hasBeenCreatedByBranch()
{
return $this->branchCreated;
}
/**
* @return ?DbObject
*/
public function getOriginalDbObject()
{
return $this->object;
}
/**
* @return ?DbObject
*/
public function getBranchedDbObject(Db $connection)
{
if ($this->object) {
$branched = DbObjectTypeRegistry::newObject($this->objectTable, [], $connection);
// object_type first, to avoid:
// I can only assign for applied objects or objects with native support for assignments
if ($this->object->hasProperty('object_type')) {
$branched->set('object_type', $this->object->get('object_type'));
}
foreach ((array) $this->object->toPlainObject(false, true) as $key => $value) {
if ($key === 'object_type') {
continue;
}
$branched->set($key, $value);
}
$branched->set('id', $this->object->get('id'));
$branched->set('uuid', $this->object->get('uuid'));
} else {
$branched = DbObjectTypeRegistry::newObject($this->objectTable, [], $connection);
$branched->setUniqueId($this->objectUuid);
}
if ($this->changes === null) {
return $branched;
}
foreach ($this->changes as $key => $value) {
if ($key === 'set_null') {
if ($value !== null) {
foreach ($value as $k) {
$branched->set($k, null);
}
}
} else {
$branched->set($key, $value);
}
}
return $branched;
}
/**
* @return UuidInterface
*/
public function getBranchUuid()
{
return $this->branchUuid;
}
/**
* @param Db $connection
* @param string $table
* @param UuidInterface $uuid
* @param ?UuidInterface $branchUuid
* @return static
*/
protected static function loadOptional(
Db $connection,
$table,
UuidInterface $uuid,
UuidInterface $branchUuid = null
) {
$class = DbObjectTypeRegistry::classByType($table);
if ($row = static::optionalTableRowByUuid($connection, $table, $uuid)) {
$object = $class::fromDbRow((array) $row, $connection);
} else {
$object = null;
}
$self = new static();
$self->object = $object;
$self->objectUuid = $uuid;
$self->branchUuid = $branchUuid;
$self->objectTable = $table;
if ($branchUuid && $row = static::optionalBranchedTableRowByUuid($connection, $table, $uuid, $branchUuid)) {
if ($row->branch_deleted === 'y') {
$self->branchDeleted = true;
} elseif ($row->branch_created === 'y') {
$self->branchCreated = true;
}
$self->changes = BranchSettings::normalizeBranchedObjectFromDb($row);
$self->loadedAsBranchedObject = true;
}
return $self;
}
/**
* @param Db $connection
* @param string $table
* @param UuidInterface $uuid
* @return stdClass|boolean
*/
protected static function optionalTableRowByUuid(Db $connection, $table, UuidInterface $uuid)
{
$db = $connection->getDbAdapter();
return $db->fetchRow(
$db->select()->from($table)->where('uuid = ?', $connection->quoteBinary($uuid->getBytes()))
);
}
/**
* @param Db $connection
* @param string $table
* @param UuidInterface $uuid
* @return stdClass|boolean
*/
protected static function optionalBranchedTableRowByUuid(
Db $connection,
$table,
UuidInterface $uuid,
UuidInterface $branchUuid
) {
$db = $connection->getDbAdapter();
$query = $db->select()
->from("branched_$table")
->where('uuid = ?', $connection->quoteBinary($uuid->getBytes()))
->where('branch_uuid = ?', $connection->quoteBinary($branchUuid->getBytes()));
return $db->fetchRow($query);
}
protected function __construct()
{
}
}

View File

@ -1,142 +0,0 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Exception\ProgrammingError;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\IcingaObject;
class IcingaObjectModification
{
/**
* @param DbObject $object
* @return ObjectModification
*/
public static function getModification(DbObject $object)
{
if ($object->shouldBeRemoved()) {
return static::delete($object);
}
if ($object->hasBeenLoadedFromDb()) {
return static::modify($object);
}
return static::create($object);
}
protected static function fixForeignKeys($object)
{
// TODO: Generic, _name?? Lookup?
$keys = [
'check_command_name',
'check_period_name',
'event_command_name',
'command_endpoint_name',
'zone_name',
'host_name',
];
foreach ($keys as $key) {
if (property_exists($object, $key)) {
$object->{substr($key, 0, -5)} = $object->$key;
unset($object->$key);
}
}
}
public static function applyModification(ObjectModification $modification, DbObject $object = null, Db $db = null)
{
if ($modification->isDeletion()) {
$object->markForRemoval();
} elseif ($modification->isCreation()) {
/** @var string|DbObject $class */
$class = $modification->getClassName();
$properties = $modification->getProperties()->jsonSerialize();
self::fixForeignKeys($properties);
$object = $class::create((array) $properties, $db);
} else {
// TODO: Add "reset Properties", those that have been nulled
$properties = (array) $modification->getProperties()->jsonSerialize();
foreach (BranchModificationStore::ENCODED_DICTIONARIES as $property) {
self::flattenProperty($properties, $property);
}
if ($object === null) {
echo '<pre>';
debug_print_backtrace();
echo '</pre>';
exit;
}
foreach ($properties as $key => $value) {
$object->set($key, $value);
}
}
// Just to be on the safe side
if ($db) {
$object->setConnection($db);
}
return $object;
}
public static function delete(DbObject $object)
{
return ObjectModification::delete(
get_class($object),
self::getKey($object),
$object->toPlainObject(false, true)
);
}
public static function create(DbObject $object)
{
return ObjectModification::create(
get_class($object),
self::getKey($object),
$object->toPlainObject(false, true)
);
}
protected static function getKey(DbObject $object)
{
return $object->getKeyParams();
}
protected static function flattenProperty(array &$properties, $property)
{
// TODO: dots in varnames -> throw or escape?
if (isset($properties[$property])) {
foreach ((array) $properties[$property] as $key => $value) {
$properties["$property.$key"] = $value;
}
unset($properties[$property]);
}
}
public static function modify(DbObject $object)
{
if (! $object instanceof IcingaObject) {
throw new ProgrammingError('Plain object helpers for DbObject must be implemented');
}
$old = (array) $object->getPlainUnmodifiedObject();
$new = (array) $object->toPlainObject(false, true);
$unchangedKeys = [];
foreach (BranchModificationStore::ENCODED_DICTIONARIES as $property) {
self::flattenProperty($old, $property);
self::flattenProperty($new, $property);
}
foreach ($old as $key => $value) {
if (array_key_exists($key, $new) && $value === $new[$key]) {
$unchangedKeys[] = $key;
}
}
foreach ($unchangedKeys as $key) {
unset($old[$key]);
unset($new[$key]);
}
return ObjectModification::modify(get_class($object), self::getKey($object), $old, $new);
}
}

View File

@ -4,24 +4,17 @@ namespace Icinga\Module\Director\Db\Branch;
use Exception;
use gipfl\Translation\TranslationHelper;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Objects\IcingaObject;
use Ramsey\Uuid\UuidInterface;
abstract class MergeError extends Exception
{
use TranslationHelper;
/** @var ObjectModification */
protected $modification;
/** @var BranchActivity */
protected $activity;
/** @var UuidInterface */
protected $activityUuid;
public function __construct(ObjectModification $modification, UuidInterface $activityUuid)
public function __construct(BranchActivity $activity)
{
$this->modification = $modification;
$this->activityUuid = $activityUuid;
$this->activity = $activity;
parent::__construct($this->prepareMessage());
}
@ -29,33 +22,16 @@ abstract class MergeError extends Exception
public function getObjectTypeName()
{
/** @var string|DbObject $class */
$class = $this->getModification()->getClassName();
$dummy = $class::create([]);
if ($dummy instanceof IcingaObject) {
return $dummy->getShortTableName();
}
return $dummy->getTableName();
}
public function getActivityUuid()
{
return $this->activityUuid;
return preg_replace('/^icinga_/', '', $this->getActivity()->getObjectTable());
}
public function getNiceObjectName()
{
$keyParams = $this->getModification()->getKeyParams();
if (array_keys((array) $keyParams) === ['object_name']) {
return $keyParams->object_name;
}
return json_encode($keyParams);
return $this->activity->getObjectName();
}
public function getModification()
public function getActivity()
{
return $this->modification;
return $this->activity;
}
}

View File

@ -1,156 +0,0 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Module\Director\Data\DataArrayHelper;
use Icinga\Module\Director\Data\Serializable;
use Icinga\Module\Director\Data\SerializableValue;
use InvalidArgumentException;
class ObjectModification implements Serializable
{
const ACTION_CREATE = 'create';
const ACTION_MODIFY = 'modify';
const ACTION_DELETE = 'delete';
protected static $serializationProperties = [
'class',
'key',
'action',
'properties',
'formerProperties',
];
/** @var string */
protected $class;
/** @var \stdClass */
protected $key;
/** @var string */
protected $action;
/** @var SerializableValue|null */
protected $properties;
/** @var SerializableValue|null */
protected $formerProperties;
public function __construct(
$class,
$key,
$action,
SerializableValue $properties = null,
SerializableValue $formerProperties = null
) {
$this->class = $class;
$this->key = $key;
$this->assertValidAction($action);
$this->action = $action;
$this->properties = $properties;
$this->formerProperties = $formerProperties;
}
public static function delete($class, $key, $formerProperties)
{
return new static(
$class,
$key,
self::ACTION_DELETE,
null,
SerializableValue::wantSerializable($formerProperties)
);
}
public static function create($class, $key, $properties)
{
return new static($class, $key, self::ACTION_CREATE, SerializableValue::wantSerializable($properties));
}
public static function modify($class, $key, $formerProperties, $properties)
{
return new static(
$class,
$key,
self::ACTION_MODIFY,
SerializableValue::wantSerializable($properties),
SerializableValue::wantSerializable($formerProperties)
);
}
protected function assertValidAction($action)
{
if ($action !== self::ACTION_MODIFY
&& $action !== self::ACTION_CREATE
&& $action !== self::ACTION_DELETE
) {
throw new InvalidArgumentException("Valid action expected, got $action");
}
}
public function isDeletion()
{
return $this->action === self::ACTION_DELETE;
}
public function isCreation()
{
return $this->action === self::ACTION_CREATE;
}
public function isModification()
{
return $this->action === self::ACTION_MODIFY;
}
public function getAction()
{
return $this->action;
}
public function jsonSerialize()
{
return (object) [
'class' => $this->class,
'key' => $this->key,
'action' => $this->action,
'properties' => $this->properties,
'formerProperties' => $this->formerProperties,
];
}
public function getProperties()
{
return $this->properties;
}
public function getFormerProperties()
{
return $this->formerProperties;
}
public function getClassName()
{
return $this->class;
}
public function getKeyParams()
{
return $this->key;
}
public static function fromSerialization($value)
{
$value = DataArrayHelper::wantArray($value);
DataArrayHelper::failOnUnknownProperties($value, self::$serializationProperties);
DataArrayHelper::requireProperties($value, ['class', 'key', 'action']);
return new static(
$value['class'],
$value['key'],
$value['action'],
isset($value['properties']) ? SerializableValue::fromSerialization($value['properties']) : null,
isset($value['formerProperties']) ? SerializableValue::fromSerialization($value['formerProperties']) : null
);
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
class PlainObjectPropertyDiff
{
public static function calculate(array $old = null, array $new = null)
{
if ($new === null) {
throw new \RuntimeException('Cannot diff for delete');
}
if ($old === null) {
foreach (BranchSettings::ENCODED_DICTIONARIES as $property) {
self::flattenProperty($new, $property);
}
return $new;
}
$unchangedKeys = [];
foreach (BranchSettings::ENCODED_DICTIONARIES as $property) {
self::flattenProperty($old, $property);
self::flattenProperty($new, $property);
}
foreach ($old as $key => $value) {
if (array_key_exists($key, $new)) {
if ($value === $new[$key]) {
$unchangedKeys[] = $key;
}
} else {
$new[$key] = null;
}
}
foreach ($unchangedKeys as $key) {
unset($new[$key]);
}
return $new;
}
protected static function flattenProperty(array &$properties, $property)
{
// TODO: dots in varnames -> throw or escape?
if (isset($properties[$property])) {
foreach ((array) $properties[$property] as $key => $value) {
$properties["$property.$key"] = $value;
}
unset($properties[$property]);
}
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaServiceSet;
use Ramsey\Uuid\Uuid;
use RuntimeException;
use function is_int;
use function is_resource;
use function is_string;
class UuidLookup
{
/**
* @param Db $connection
* @param Branch $branch
* @param string $objectType
* @param int|string $key
* @param IcingaHost|null $host
* @param IcingaServiceSet $set
*/
public static function findServiceUuid(
Db $connection,
Branch $branch,
$objectType,
$key = null,
IcingaHost $host = null,
IcingaServiceSet $set = null
) {
$db = $connection->getDbAdapter();
$query = $db->select()->from('icinga_service', 'uuid')->where('object_type = ?', $objectType);
$query = self::addKeyToQuery($query, $key);
if ($host) {
$query->add('host_id = ?', $host->get('id'));
}
if ($set) {
$query->add('service_set_id = ?', $set->get('id'));
}
$uuid = self::fetchOptionalUuid($connection, $query);
if ($uuid === null && $branch->isBranch()) {
// TODO: use different tables?
$query = $db->select()->from('branched_icinga_service', 'uuid')->where('object_type = ?', $objectType);
$query = self::addKeyToQuery($query, $key);
if ($host) {
// TODO: uuid?
$query->add('host = ?', $host->getObjectName());
}
if ($set) {
$query->add('service_set = ?', $set->getObjectName());
}
$uuid = self::fetchOptionalUuid($connection, $query);
}
return $uuid;
}
public static function findUuidForKey($key, $table, Db $connection, Branch $branch)
{
$db = $connection->getDbAdapter();
$query = self::addKeyToQuery($db->select()->from($table, 'uuid'), $key);
$uuid = self::fetchOptionalUuid($connection, $query);
if ($uuid === null && $branch->isBranch()) {
$query = $db->select()->from("branched_$table", 'uuid')->where('object_name = ?', $key);
$uuid = self::fetchOptionalUuid($connection, $query);
}
return $uuid;
}
protected static function addKeyToQuery($query, $key)
{
if (is_int($key)) {
$query->where('id = ?', $key);
} elseif (is_string($key)) {
$query->where('object_name = ?', $key);
} else {
throw new RuntimeException('Cannot deal with non-int/string keys for UUID fallback');
}
return $query;
}
protected static function fetchOptionalUuid(Db $connection, $query)
{
$result = $connection->getDbAdapter()->fetchOne($query);
if (is_resource($result)) {
$result = stream_get_contents($result);
}
if (is_string($result)) {
return Uuid::fromBytes($result);
}
return null;
}
}

View File

@ -4,7 +4,6 @@ namespace Icinga\Module\Director\Hook;
use Icinga\Authentication\Auth;
use Icinga\Module\Director\Dashboard\Dashlet\Dashlet;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Db\Branch\BranchSTore;
@ -29,15 +28,6 @@ abstract class BranchSupportHook
*/
abstract public function linkToBranch(Branch $branch, Auth $auth, $label = null);
/**
* @param string $label
* @param Branch $branch
* @param DbObject $object
* @param Auth $auth
* @return ?ValidHtml
*/
abstract public function linkToBranchedObject($label, Branch $branch, DbObject $object, Auth $auth);
/**
* @param Db $db
* @return Dashlet[]

View File

@ -288,8 +288,6 @@ class ExtensibleSet
array_merge($props, array('property' => $value))
);
}
$this->fromDb['override'] = $this->ownValues;
}
if (! empty($this->plusValues)) {
@ -300,8 +298,6 @@ class ExtensibleSet
array_merge($props, array('property' => $value))
);
}
$this->fromDb['extend'] = $this->ownValues;
}
if (! empty($this->minusValues)) {
@ -312,9 +308,18 @@ class ExtensibleSet
array_merge($props, array('property' => $value))
);
}
$this->fromDb['blacklist'] = $this->ownValues;
}
$this->setBeingLoadedFromDb();
}
public function setBeingLoadedFromDb()
{
$this->fromDb = [
'override' => $this->ownValues ?: [],
'extend' => $this->plusValues ?: [],
'blacklist' => $this->minusValues ?: [],
];
}
public function override($values)

View File

@ -8,18 +8,21 @@ class IcingaApiUser extends IcingaObject
{
protected $table = 'icinga_apiuser';
protected $uuidColumn = 'uuid';
// TODO: Enable (and add table) if required
protected $supportsImports = false;
protected $defaultProperties = array(
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',
'password' => null,
'client_dn' => null,
'permissions' => null,
);
];
protected function renderPassword()
{

View File

@ -84,6 +84,10 @@ class IcingaArguments implements Iterator, Countable, IcingaConfigRenderer
public function set($key, $value)
{
if ($value === null) {
return $this->remove($key);
}
if ($value instanceof IcingaCommandArgument) {
$argument = $value;
} else {
@ -337,6 +341,15 @@ class IcingaArguments implements Iterator, Countable, IcingaConfigRenderer
return $arguments->loadFromDb();
}
public function setBeingLoadedFromDb()
{
foreach ($this->arguments as $argument) {
$argument->setBeingLoadedFromDb();
}
$this->refreshIndex();
$this->cloneStored();
}
/**
* @return $this
* @throws \Icinga\Module\Director\Exception\DuplicateKeyException
@ -349,8 +362,14 @@ class IcingaArguments implements Iterator, Countable, IcingaConfigRenderer
if ($argument->shouldBeRemoved()) {
$deleted[] = $key;
} else {
$argument->set('command_id', $this->object->get('id'));
$argument->store($db);
if ($argument->hasBeenModified()) {
if ($argument->hasBeenLoadedFromDb()) {
$argument->setLoadedProperty('command_id', $this->object->get('id'));
} else {
$argument->set('command_id', $this->object->get('id'));
}
$argument->store($db);
}
}
}

View File

@ -18,8 +18,11 @@ class IcingaCommand extends IcingaObject implements ObjectWithArguments, ExportI
protected $type = 'CheckCommand';
protected $uuidColumn = 'uuid';
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',

View File

@ -7,7 +7,9 @@ use RuntimeException;
class IcingaCommandArgument extends IcingaObject
{
protected $keyName = 'id';
protected $keyName = ['command_id', 'argument_name'];
protected $autoincKeyName = 'id';
protected $table = 'icinga_command_argument';
@ -129,6 +131,7 @@ class IcingaCommandArgument extends IcingaObject
}
$this->transformPlainArgumentValue($plain);
unset($plain->command_id);
// Will happen only combined with $skipDefaults
if (array_keys((array) $plain) === ['value']) {

View File

@ -16,6 +16,7 @@ class IcingaDependency extends IcingaObject implements ExportInterface
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',
@ -34,6 +35,8 @@ class IcingaDependency extends IcingaObject implements ExportInterface
'parent_service_by_name' => null,
];
protected $uuidColumn = 'uuid';
protected $supportsCustomVars = false;
protected $supportsImports = true;

View File

@ -15,8 +15,11 @@ class IcingaEndpoint extends IcingaObject
protected $supportsImports = true;
protected $uuidColumn = 'uuid';
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'zone_id' => null,
'object_name' => null,
'object_type' => null,

View File

@ -22,6 +22,7 @@ class IcingaHost extends IcingaObject implements ExportInterface
protected $defaultProperties = array(
'id' => null,
'uuid' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',
@ -101,6 +102,8 @@ class IcingaHost extends IcingaObject implements ExportInterface
/** @var HostGroupMembershipResolver */
protected $hostgroupMembershipResolver;
protected $uuidColumn = 'uuid';
public static function enumProperties(
DbConnection $connection = null,
$prefix = '',

View File

@ -14,6 +14,7 @@ class IcingaNotification extends IcingaObject implements ExportInterface
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',
@ -31,6 +32,8 @@ class IcingaNotification extends IcingaObject implements ExportInterface
'assign_filter' => null,
];
protected $uuidColumn = 'uuid';
protected $supportsCustomVars = true;
protected $supportsFields = true;

View File

@ -79,6 +79,7 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
// property => IcingaObjectClass
];
/** @var IcingaObjectMultiRelations[] */
protected $loadedMultiRelations = [];
/**
@ -250,6 +251,10 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return $prefix . $this->relatedSets[$property];
}
/**
* @param $property
* @return ExtensibleSet
*/
protected function getRelatedSet($property)
{
if (! array_key_exists($property, $this->loadedRelatedSets)) {
@ -262,6 +267,9 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return $this->loadedRelatedSets[$property];
}
/**
* @return ExtensibleSet[]
*/
protected function relatedSets()
{
$sets = [];
@ -828,7 +836,7 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
{
$this->assertGroupsSupport();
if ($this->groups === null) {
if ($this->hasBeenLoadedFromDb()) {
if ($this->hasBeenLoadedFromDb() && $this->get('id')) {
$this->groups = IcingaObjectGroups::loadForStoredObject($this);
} else {
$this->groups = new IcingaObjectGroups($this);
@ -1398,7 +1406,11 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
if (PrefetchCache::shouldBeUsed()) {
$this->vars = PrefetchCache::instance()->vars($this);
} else {
$this->vars = CustomVariables::loadForStoredObject($this);
if ($this->get('id')) {
$this->vars = CustomVariables::loadForStoredObject($this);
} else {
$this->vars = new CustomVariables();
}
}
if ($this->getShortTableName() === 'host') {
@ -1477,6 +1489,35 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
&& $this->get('object_type') === 'apply';
}
public function setBeingLoadedFromDb()
{
if ($this instanceof ObjectWithArguments && $this->gotArguments()) {
$this->arguments()->setBeingLoadedFromDb();
}
if ($this->supportsImports() && $this->gotImports()) {
$this->imports()->setBeingLoadedFromDb();
}
if ($this->supportsCustomVars() && $this->vars !== null) {
$this->vars()->setBeingLoadedFromDb();
}
if ($this->supportsGroups() && $this->groups !== null) {
$this->groups()->setBeingLoadedFromDb();
}
if ($this->supportsRanges() && $this->ranges === null) {
$this->ranges()->setBeingLoadedFromDb();
}
foreach ($this->loadedRelatedSets as $set) {
$set->setBeingLoadedFromDb();
}
foreach ($this->loadedMultiRelations as $multiRelation) {
$multiRelation->setBeingLoadedFromDb();
}
parent::setBeingLoadedFromDb();
}
/**
* @throws NotFoundError
* @throws \Icinga\Module\Director\Exception\DuplicateKeyException
@ -2147,6 +2188,11 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
return '';
}
public function renderUuid()
{
return '';
}
/**
* @return string
*/
@ -2773,6 +2819,9 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
foreach ($p as $k => $v) {
// Do not ship ids for IcingaObjects:
if ($k === $this->getUuidColumn()) {
continue;
}
if ($resolveIds) {
if ($k === 'id' && $keepId === false && $this->hasProperty('object_name')) {
continue;
@ -2991,6 +3040,9 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
public function getUrlParams()
{
$params = [];
if ($column = $this->getUuidColumn()) {
return [$column => $this->getUniqueId()->toString()];
}
if ($this->isApplyRule() && ! $this instanceof IcingaScheduledDowntime) {
$params['id'] = $this->get('id');
@ -3044,6 +3096,12 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer
if ($k === 'id' && $this->hasProperty('object_name')) {
continue;
}
if ($k === $this->getUuidColumn()) {
continue;
}
if ($k === 'disabled' && $v === null) {
continue;
}
if ('_id' === substr($k, -3)) {
$relKey = substr($k, 0, -3);

View File

@ -12,8 +12,11 @@ abstract class IcingaObjectGroup extends IcingaObject implements ExportInterface
protected $supportedInLegacy = true;
protected $uuidColumn = 'uuid';
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',

View File

@ -274,7 +274,7 @@ class IcingaObjectGroups implements Iterator, Countable, IcingaConfigRenderer
$class = $this->getGroupClass();
$this->groups = $class::loadAll($connection, $query, 'object_name');
$this->cloneStored();
$this->setBeingLoadedFromDb();
return $this;
}
@ -314,12 +314,12 @@ class IcingaObjectGroups implements Iterator, Countable, IcingaConfigRenderer
)
);
}
$this->cloneStored();
$this->setBeingLoadedFromDb();
return true;
}
protected function cloneStored()
public function setBeingLoadedFromDb()
{
$this->storedGroups = array();
foreach ($this->groups as $k => $v) {
@ -341,7 +341,7 @@ class IcingaObjectGroups implements Iterator, Countable, IcingaConfigRenderer
if (PrefetchCache::shouldBeUsed()) {
$groups->groups = PrefetchCache::instance()->groups($object);
$groups->cloneStored();
$groups->setBeingLoadedFromDb();
} else {
$groups->loadFromDb();
}

View File

@ -308,7 +308,7 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
$this->imports = array_combine($keys, $keys);
}
$this->cloneStored();
$this->setBeingLoadedFromDb();
return $this;
}
@ -355,12 +355,12 @@ class IcingaObjectImports implements Iterator, Countable, IcingaConfigRenderer
]);
}
$this->cloneStored();
$this->setBeingLoadedFromDb();
return true;
}
protected function cloneStored()
public function setBeingLoadedFromDb()
{
$this->storedNames = $this->listImportNames();
$this->modified = false;

View File

@ -323,7 +323,7 @@ class IcingaObjectMultiRelations implements Iterator, Countable, IcingaConfigRen
$class = $this->getRelatedClassName();
$this->relations = $class::loadAll($connection, $query, 'object_name');
$this->cloneStored();
$this->setBeingLoadedFromDb();
return $this;
}
@ -331,13 +331,10 @@ class IcingaObjectMultiRelations implements Iterator, Countable, IcingaConfigRen
public function store()
{
$db = $this->getDb();
$stored = array_keys($this->stored);
$relations = array_keys($this->relations);
$objectId = $this->object->id;
$type = $this->getType();
$type = $this->getType();
$objectCol = $type . '_id';
$relationCol = $this->getRelationIdColumn() . '_id';
@ -369,12 +366,12 @@ class IcingaObjectMultiRelations implements Iterator, Countable, IcingaConfigRen
)
);
}
$this->cloneStored();
$this->setBeingLoadedFromDb();
return true;
}
protected function cloneStored()
public function setBeingLoadedFromDb()
{
$this->stored = array();
foreach ($this->relations as $k => $v) {

View File

@ -11,6 +11,7 @@ class IcingaScheduledDowntime extends IcingaObject
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'zone_id' => null,
'object_name' => null,
'object_type' => null,
@ -24,6 +25,8 @@ class IcingaScheduledDowntime extends IcingaObject
'with_services' => null,
];
protected $uuidColumn = 'uuid';
protected $supportsImports = true;
protected $supportsRanges = true;

View File

@ -211,13 +211,18 @@ class IcingaScheduledDowntimeRanges implements Iterator, Countable, IcingaConfig
->order('o.range_key');
$this->ranges = IcingaScheduledDowntimeRange::loadAll($connection, $query, 'range_key');
$this->storedRanges = array();
$this->setBeingLoadedFromDb();
return $this;
}
public function setBeingLoadedFromDb()
{
$this->storedRanges = [];
foreach ($this->ranges as $key => $range) {
$this->storedRanges[$key] = clone($range);
}
return $this;
}
public function store()

View File

@ -23,8 +23,11 @@ class IcingaService extends IcingaObject implements ExportInterface
protected $table = 'icinga_service';
protected $uuidColumn = 'uuid';
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',

View File

@ -10,8 +10,11 @@ class IcingaTimePeriod extends IcingaObject implements ExportInterface
{
protected $table = 'icinga_timeperiod';
protected $defaultProperties = array(
protected $uuidColumn = 'uuid';
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'zone_id' => null,
'object_name' => null,
'object_type' => null,
@ -19,7 +22,7 @@ class IcingaTimePeriod extends IcingaObject implements ExportInterface
'prefer_includes' => null,
'display_name' => null,
'update_method' => null,
);
];
protected $booleans = [
'prefer_includes' => 'prefer_includes',

View File

@ -216,13 +216,18 @@ class IcingaTimePeriodRanges implements Iterator, Countable, IcingaConfigRendere
/** @var IcingaTimePeriodRange $class */
$class = $this->getClass();
$this->ranges = $class::loadAll($connection, $query, 'range_key');
$this->storedRanges = array();
$this->setBeingLoadedFromDb();
return $this;
}
public function setBeingLoadedFromDb()
{
$this->storedRanges = [];
foreach ($this->ranges as $key => $range) {
$this->storedRanges[$key] = clone($range);
}
return $this;
}
public function store()

View File

@ -12,6 +12,7 @@ class IcingaUser extends IcingaObject implements ExportInterface
protected $defaultProperties = array(
'id' => null,
'uuid' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',
@ -23,6 +24,8 @@ class IcingaUser extends IcingaObject implements ExportInterface
'zone_id' => null,
);
protected $uuidColumn = 'uuid';
protected $supportsGroups = true;
protected $supportsCustomVars = true;

View File

@ -6,8 +6,11 @@ class IcingaUserGroup extends IcingaObjectGroup
{
protected $table = 'icinga_usergroup';
protected $uuidColumn = 'uuid';
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',

View File

@ -10,8 +10,11 @@ class IcingaZone extends IcingaObject
{
protected $table = 'icinga_zone';
protected $uuidColumn = 'uuid';
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',

View File

@ -56,8 +56,7 @@ class ServiceActions extends ServiceActionsHook
$title = mt('director', 'Modify');
} elseif (Util::hasPermission('director/monitoring/services')) {
$monitoring = new Monitoring();
if (
$monitoring->isAvailable()
if ($monitoring->isAvailable()
&& $monitoring->authCanEditService(Auth::getInstance(), $hostname, $serviceName)
) {
$title = mt('director', 'Modify');

View File

@ -56,7 +56,8 @@ class HostgroupRestriction extends ObjectRestriction
return true;
}
if (! $host->hasBeenLoadedFromDb() || $host->hasModifiedGroups()) {
// Hint: branched hosts have no id
if (! $host->hasBeenLoadedFromDb() || $host->hasModifiedGroups() || $host->get('id') === null) {
foreach ($this->listRestrictedHostgroups() as $group) {
if ($host->hasGroup($group)) {
return true;

View File

@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Web\Controller;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Db\Branch\BranchStore;
use Icinga\Module\Director\Web\Widget\NotInBranchedHint;
trait BranchHelper
{
@ -47,4 +48,18 @@ trait BranchHelper
{
return $this->getBranchUuid() !== null;
}
/**
* @param string $subject
* @return bool
*/
protected function showNotInBranch($subject)
{
if ($this->getBranch()->isBranch()) {
$this->content()->add(new NotInBranchedHint($subject, $this->getBranch(), $this->Auth()));
return true;
}
return false;
}
}

View File

@ -7,8 +7,10 @@ use Icinga\Exception\IcingaException;
use Icinga\Exception\InvalidPropertyException;
use Icinga\Exception\NotFoundError;
use Icinga\Exception\ProgrammingError;
use Icinga\Module\Director\Data\Db\DbObjectStore;
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Db\Branch\BranchedObject;
use Icinga\Module\Director\Db\Branch\UuidLookup;
use Icinga\Module\Director\Deployment\DeploymentInfo;
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
use Icinga\Module\Director\Exception\NestingError;
@ -25,11 +27,15 @@ use Icinga\Module\Director\Web\Controller\Extension\ObjectRestrictions;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
use Icinga\Module\Director\Web\ObjectPreview;
use Icinga\Module\Director\Web\Table\ActivityLogTable;
use Icinga\Module\Director\Web\Table\BranchActivityTable;
use Icinga\Module\Director\Web\Table\GroupMemberTable;
use Icinga\Module\Director\Web\Table\IcingaObjectDatafieldTable;
use Icinga\Module\Director\Web\Tabs\ObjectTabs;
use Icinga\Module\Director\Web\Widget\ObjectModificationBranchHint;
use Icinga\Module\Director\Web\Widget\BranchedObjectHint;
use gipfl\IcingaWeb2\Link;
use ipl\Html\Html;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
abstract class ObjectController extends ActionController
{
@ -60,7 +66,7 @@ abstract class ObjectController extends ActionController
if ($this->getRequest()->isApiRequest()) {
$handler = new IcingaObjectHandler($this->getRequest(), $this->getResponse(), $this->db());
try {
$this->eventuallyLoadObject();
$this->loadOptionalObject();
} catch (NotFoundError $e) {
// Silently ignore the error, the handler will complain
$handler->sendJsonError($e, 404);
@ -80,7 +86,7 @@ abstract class ObjectController extends ActionController
// now.
exit;
} else {
$this->eventuallyLoadObject();
$this->loadOptionalObject();
if ($this->getRequest()->getActionName() === 'add') {
$this->addSingleTab(
sprintf($this->translate('Add %s'), ucfirst($this->getType())),
@ -260,6 +266,7 @@ abstract class ObjectController extends ActionController
if ($host = $this->params->get('host')) {
$table->filterHost($host);
}
$this->showOptionalBranchActivity($table);
$table->renderTo($this);
}
@ -452,48 +459,85 @@ abstract class ObjectController extends ActionController
return $this->assertPermission("director/$type");
}
protected function eventuallyLoadObject()
protected function loadOptionalObject()
{
if (null !== $this->params->get('name') || $this->params->get('id')) {
if ($this->params->get('uuid') || null !== $this->params->get('name') || $this->params->get('id')) {
$this->loadObject();
}
}
/**
* @return ?UuidInterface
* @throws InvalidPropertyException
* @throws NotFoundError
*/
protected function getUuidFromUrl()
{
$key = null;
if ($uuid = $this->params->get('uuid')) {
$key = Uuid::fromString($uuid);
} elseif ($id = $this->params->get('id')) {
$key = (int) $id;
} elseif (null !== ($name = $this->params->get('name'))) {
$key = $name;
}
if ($key === null) {
$request = $this->getRequest();
if ($request->isApiRequest() && $request->isGet()) {
$this->getResponse()->setHttpResponseCode(422);
throw new InvalidPropertyException(
'Cannot load object, missing parameters'
);
}
return null;
}
return $this->requireUuid($key);
}
protected function loadObject()
{
if ($this->object) {
throw new ProgrammingError('Loading an object twice is not very efficient');
}
$isApi = $this->getRequest()->isApiRequest();
$store = new DbObjectStore($this->db());
if ($id = $this->params->get('id')) {
$key = (int) $id;
} elseif (null !== ($name = $this->params->get('name'))) {
$key = $name;
}
if ($key === null) {
if ($isApi && $this->getRequest()->isGet()) {
$this->getResponse()->setHttpResponseCode(422);
$this->object = $this->loadSpecificObject($this->getTableName(), $this->getUuidFromUrl(), true);
}
throw new InvalidPropertyException(
'Cannot load object, missing parameters'
);
}
return;
}
protected function loadSpecificObject($tableName, $key, $showHint = false)
{
$branch = $this->getBranch();
$store->setBranch($branch);
list($object, $modification) = $store->loadWithBranchModification(strtolower($this->getType()), $key);
$branchedObject = BranchedObject::load($this->db(), $tableName, $key, $branch);
$object = $branchedObject->getBranchedDbObject($this->db());
assert($object instanceof IcingaObject);
$object->setBeingLoadedFromDb();
if (! $this->allowsObject($object)) {
throw new NotFoundError('No such object available');
}
if ($branch->isBranch() && ! $isApi) {
$this->content()->add(new ObjectModificationBranchHint($branch, $this->Auth(), $object, $modification));
if ($showHint && $branch->isBranch() && ! $this->getRequest()->isApiRequest()) {
$this->content()->add(new BranchedObjectHint($branch, $this->Auth(), $branchedObject));
}
$this->object = $object;
return $object;
}
protected function requireUuid($key)
{
if (! $key instanceof UuidInterface) {
$key = UuidLookup::findUuidForKey($key, $this->getTableName(), $this->db(), $this->getBranch());
if ($key === null) {
throw new NotFoundError('No such object available');
}
}
return $key;
}
protected function getTableName()
{
return DbObjectTypeRegistry::tableNameByType($this->getType());
}
protected function addDeploymentLink()
@ -618,4 +662,30 @@ abstract class ObjectController extends ActionController
return $this->object;
}
protected function showOptionalBranchActivity($activityTable)
{
$branch = $this->getBranch();
if ($branch->isBranch() && (int) $this->params->get('page', '1') === 1) {
$table = new BranchActivityTable($branch->getUuid(), $this->db(), $this->object->getUniqueId());
if (count($table) > 0) {
$this->content()->add(Hint::info(Html::sprintf($this->translate(
'The following modifications are visible in this %s only...'
), Branch::requireHook()->linkToBranch(
$branch,
$this->Auth(),
$this->translate('configuration branch')
))));
$this->content()->add($table);
if (count($activityTable) === 0) {
return;
}
$this->content()->add(Html::tag('br'));
$this->content()->add(Hint::ok($this->translate(
'...and the modifications below are already in the main branch:'
)));
$this->content()->add(Html::tag('br'));
}
}
}
}

View File

@ -5,12 +5,11 @@ namespace Icinga\Module\Director\Web\Form;
use Exception;
use gipfl\IcingaWeb2\Url;
use Icinga\Authentication\Auth;
use Icinga\Module\Director\Data\Db\DbObjectStore;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Data\Db\DbObjectWithSettings;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Db\Branch\BranchModificationStore;
use Icinga\Module\Director\Db\Branch\IcingaObjectModification;
use Icinga\Module\Director\Exception\NestingError;
use Icinga\Module\Director\Hook\IcingaObjectFormHook;
use Icinga\Module\Director\IcingaConfig\StateFilterSet;
@ -677,23 +676,7 @@ abstract class DirectorObjectForm extends DirectorForm
: $this->translate('A new %s has successfully been created'),
$this->translate($this->getObjectShortClassName())
);
if ($this->branch && $this->branch->isBranch()) {
if ($object->shouldBeRenamed()) {
$this->getElement('object_name')->addError(
$this->translate('Renaming objects in branches is not (yet) supported')
);
return;
}
$store = new BranchModificationStore($this->getDb(), $object->getShortTableName());
$store->store(
IcingaObjectModification::getModification($object),
$object->get('id'),
$this->branch->getUuid()
);
} else {
$object->store($this->db);
}
$this->getDbObjectStore()->store($object);
} else {
if ($this->isApiRequest()) {
$this->setHttpResponseCode(304);
@ -933,22 +916,21 @@ abstract class DirectorObjectForm extends DirectorForm
);
}
if ($this->branch && $this->branch->isBranch()) {
$store = new BranchModificationStore($this->getDb(), $object->getShortTableName());
$store->store(
IcingaObjectModification::delete($object),
$object->get('id'),
$this->branch->getUuid()
);
$this->setSuccessUrl($url);
} elseif ($object->delete()) {
if ($this->getDbObjectStore()->delete($object)) {
$this->setSuccessUrl($url);
}
// TODO: show object name and so
$this->redirectOnSuccess($msg);
}
/**
* @return DbObjectStore
*/
protected function getDbObjectStore()
{
$store = new DbObjectStore($this->getDb(), $this->branch);
return $store;
}
protected function addDeleteButton($label = null)
{
$object = $this->object;
@ -1076,18 +1058,20 @@ abstract class DirectorObjectForm extends DirectorForm
public function loadObject($id)
{
if ($this->branch && $this->branch->isBranch()) {
throw new \RuntimeException('Calling loadObject from form in a branch');
}
/** @var DbObject $class */
$class = $this->getObjectClassname();
if (is_int($id)) {
$this->object = $class::loadWithAutoIncId($id, $this->db);
if ($this->object->getKeyName() === 'id') {
$this->addHidden('id', $id);
}
} else {
$this->object = $class::load($id, $this->db);
}
// TODO: hmmmm...
if (! is_array($id) && $this->object->getKeyName() === 'id') {
$this->addHidden('id', $id);
}
return $this;
}

View File

@ -2,12 +2,11 @@
namespace Icinga\Module\Director\Web\Table;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Db\Branch\ObjectModification;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Db\Branch\BranchActivity;
use Icinga\Module\Director\Util;
use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
class BranchActivityTable extends ZfQueryBasedTable
@ -17,9 +16,13 @@ class BranchActivityTable extends ZfQueryBasedTable
/** @var UuidInterface */
protected $branchUuid;
public function __construct(UuidInterface $branchUuid, $db)
/** @var ?UuidInterface */
protected $objectUuid;
public function __construct(UuidInterface $branchUuid, $db, UuidInterface $objectUuid = null)
{
$this->branchUuid = $branchUuid;
$this->objectUuid = $objectUuid;
parent::__construct($db);
}
@ -30,93 +33,68 @@ class BranchActivityTable extends ZfQueryBasedTable
public function renderRow($row)
{
return $this->renderBranchRow($row);
}
public function renderBranchRow($row)
{
$ts = $row->change_time / 1000;
$ts = (int) floor($row->timestamp_ns / 1000000);
$this->splitByDay($ts);
$changes = ObjectModification::fromSerialization(json_decode($row->change_set));
$action = 'action-' . $changes->getAction(). ' branched'; // not gray
$activity = BranchActivity::fromDbRow($row);
return $this::tr([
$this::td($this->makeBranchLink(
$changes,
Uuid::fromBytes($row->uuid),
Uuid::fromBytes($row->branch_uuid)
))->setSeparator(' '),
$this::td($this->makeBranchLink($activity))->setSeparator(' '),
$this::td(strftime('%H:%M:%S', $ts))
])->addAttributes(['class' => $action]);
])->addAttributes(['class' => ['action-' . $activity->getAction(), 'branched']]);
}
protected function linkObject($type, $name)
protected function linkObject(BranchActivity $activity)
{
// $type, UuidInterface $uuid
// Later on replacing, service_set -> serviceset
// multi column key :(
if ($type === 'service') {
return "\"$name\"";
}
$type = preg_replace('/^icinga_/', '', $activity->getObjectTable());
return Link::create(
"\"$name\"",
$activity->getObjectName(),
'director/' . str_replace('_', '', $type),
['name' => $name],
['uuid' => $activity->getObjectUuid()->toString()],
['title' => $this->translate('Jump to this object')]
);
}
protected function makeBranchLink(ObjectModification $modification, UuidInterface $uuid, UuidInterface $branch)
protected function makeBranchLink(BranchActivity $activity)
{
/** @var string|DbObject $class */
$class = $modification->getClassName();
$type = $class::create([])->getShortTableName();
// TODO: short type in table, not class name
$keyParams = $modification->getKeyParams();
if (is_object($keyParams)) {
$keyParams = (array)$keyParams;
}
if (is_array($keyParams)) {
if (array_keys($keyParams) === ['object_name']) {
$name = $keyParams['object_name'];
} else {
$name = json_encode($keyParams);
}
} else {
$name = $keyParams;
}
$author = 'branch owner';
$type = preg_replace('/^icinga_/', '', $activity->getObjectTable());
if (Util::hasPermission('director/showconfig')) {
// Later on replacing, service_set -> serviceset
$id = 0; // $row->id
return [
'[' . $author . ']',
'[' . $activity->getAuthor() . ']',
Link::create(
$modification->getAction(),
$activity->getAction(),
'director/branch/activity',
array_merge(['uuid' => $uuid->toString()], $this->extraParams),
array_merge(['ts' => $activity->getTimestampNs()], $this->extraParams),
['title' => $this->translate('Show details related to this change')]
),
str_replace('_', ' ', $type),
$this->linkObject($type, $name)
$this->linkObject($activity)
];
} else {
return sprintf(
'[%s] %s %s "%s"',
$author,
$modification->getAction(),
$activity->getAuthor(),
$activity->getAction(),
$type,
$name
'object name'
);
}
}
public function prepareQuery()
{
return $this->db()->select()->from('director_branch_activity')
->where('branch_uuid = ?', $this->branchUuid->getBytes())
->order('change_time DESC');
/** @var Db $connection */
$connection = $this->connection();
$query = $this->db()->select()->from(['ba' => 'director_branch_activity'], 'ba.*')
->join(['b' => 'director_branch'], 'b.uuid = ba.branch_uuid', ['b.owner'])
->where('branch_uuid = ?', $connection->quoteBinary($this->branchUuid->getBytes()))
->order('timestamp_ns DESC');
if ($this->objectUuid) {
$query->where('ba.object_uuid = ?', $connection->quoteBinary($this->objectUuid->getBytes()));
}
return $query;
}
}

View File

@ -0,0 +1,78 @@
<?php
namespace Icinga\Module\Director\Web\Table;
use gipfl\IcingaWeb2\Data\SimpleQueryPaginationAdapter;
use gipfl\IcingaWeb2\Table\QueryBasedTable;
use Icinga\Data\DataArray\ArrayDatasource;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Objects\IcingaCommand;
use gipfl\IcingaWeb2\Link;
class BranchedIcingaCommandArgumentTable extends QueryBasedTable
{
/** @var IcingaCommand */
protected $command;
/** @var Branch */
protected $branch;
protected $searchColumns = [
'ca.argument_name',
'ca.argument_value',
];
public function __construct(IcingaCommand $command, Branch $branch)
{
$this->command = $command;
$this->branch = $branch;
$this->getAttributes()->set('data-base-target', '_self');
}
public function renderRow($row)
{
return $this::row([
Link::create($row->argument_name, 'director/command/arguments', [
'argument' => $row->argument_name,
'uuid' => $this->command->getUniqueId()->toString(),
]),
$row->argument_value
]);
}
public function getColumnsToBeRendered()
{
return [
$this->translate('Argument'),
$this->translate('Value'),
];
}
protected function getPaginationAdapter()
{
return new SimpleQueryPaginationAdapter($this->getQuery());
}
public function getQuery()
{
return $this->prepareQuery();
}
protected function fetchQueryRows()
{
return $this->getQuery()->fetchAll();
}
protected function prepareQuery()
{
$list = [];
foreach ($this->command->arguments()->toPlainObject() as $name => $argument) {
$new = (object) [];
$new->argument_name = $name;
$new->argument_value = isset($argument->value) ? $argument->value : null;
$list[] = $new;
}
return (new ArrayDatasource($list))->select();
}
}

View File

@ -2,6 +2,11 @@
namespace Icinga\Module\Director\Web\Table;
use Icinga\Data\DataArray\ArrayDatasource;
use Icinga\Module\Director\Data\Json;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Db\Branch\BranchModificationStore;
use Icinga\Module\Director\Objects\IcingaCommand;
use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
@ -11,20 +16,19 @@ class IcingaCommandArgumentTable extends ZfQueryBasedTable
/** @var IcingaCommand */
protected $command;
protected $searchColumns = array(
/** @var Branch */
protected $branch;
protected $searchColumns = [
'ca.argument_name',
'ca.argument_value',
);
];
public static function create(IcingaCommand $command)
{
$self = new static($command->getConnection());
$self->command = $command;
return $self;
}
public function assemble()
public function __construct(IcingaCommand $command, Branch $branch)
{
$this->command = $command;
$this->branch = $branch;
parent::__construct($command->getConnection());
$this->getAttributes()->set('data-base-target', '_self');
}
@ -32,8 +36,8 @@ class IcingaCommandArgumentTable extends ZfQueryBasedTable
{
return $this::row([
Link::create($row->argument_name, 'director/command/arguments', [
'argument_id' => $row->id,
'name' => $this->command->getObjectName()
'argument' => $row->argument_name,
'name' => $this->command->getObjectName()
]),
$row->argument_value
]);
@ -49,6 +53,27 @@ class IcingaCommandArgumentTable extends ZfQueryBasedTable
public function prepareQuery()
{
$db = $this->db();
if ($this->branch->isBranch()) {
return (new ArrayDatasource((array) $this->command->arguments()->toPlainObject()))->select();
/** @var Db $connection */
$connection = $this->connection();
$store = new BranchModificationStore($connection, 'command');
$modification = $store->loadOptionalModificationByName(
$this->command->getObjectName(),
$this->branch->getUuid()
);
if ($modification) {
$props = $modification->getProperties()->jsonSerialize();
if (isset($props->arguments)) {
return new ArrayDatasource((array) $this->command->arguments()->toPlainObject());
}
}
}
$id = $this->command->get('id');
if ($id === null) {
return new ArrayDatasource([]);
}
return $this->db()->select()->from(
['ca' => 'icinga_command_argument'],
[
@ -58,7 +83,7 @@ class IcingaCommandArgumentTable extends ZfQueryBasedTable
]
)->where(
'ca.command_id = ?',
$this->command->get('id')
$id
)->order('ca.sort_order')->order('ca.argument_name')->limit(100);
}
}

View File

@ -6,6 +6,7 @@ use ipl\Html\Html;
use Icinga\Module\Director\Objects\IcingaHost;
use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
use Ramsey\Uuid\UuidInterface;
class IcingaHostServiceTable extends ZfQueryBasedTable
{
@ -23,6 +24,9 @@ class IcingaHostServiceTable extends ZfQueryBasedTable
/** @var string|null */
protected $highlightedService;
/** @var ?UuidInterface */
protected $branchUuid;
protected $searchColumns = [
'service',
];
@ -45,6 +49,12 @@ class IcingaHostServiceTable extends ZfQueryBasedTable
return $this;
}
public function setBranchUuid(UuidInterface $uuid)
{
$this->branchUuid = $uuid;
return $this;
}
public function setHost(IcingaHost $host)
{
$this->host = $host;

View File

@ -13,6 +13,7 @@ use Icinga\Module\Director\Restriction\ObjectRestriction;
use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Table\ZfQueryBasedTable;
use gipfl\IcingaWeb2\Url;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
use Zend_Db_Select as ZfSelect;
@ -25,7 +26,7 @@ class ObjectsTable extends ZfQueryBasedTable
'object_name' => 'o.object_name',
'object_type' => 'o.object_type',
'disabled' => 'o.disabled',
'id' => 'o.id',
'uuid' => 'o.uuid',
];
protected $searchColumns = ['o.object_name'];
@ -44,6 +45,10 @@ class ObjectsTable extends ZfQueryBasedTable
/** @var IcingaObject */
protected $dummyObject;
protected $leftSubQuery;
protected $rightSubQuery;
/** @var Auth */
private $auth;
@ -147,7 +152,7 @@ class ObjectsTable extends ZfQueryBasedTable
{
$type = $this->baseObjectUrl;
$url = Url::fromPath("director/${type}", [
'name' => $row->object_name
'uuid' => Uuid::fromBytes($row->uuid)->toString()
]);
return static::td(Link::create($this->getMainLinkLabel($row), $url));
@ -167,6 +172,9 @@ class ObjectsTable extends ZfQueryBasedTable
public function renderRow($row)
{
if (isset($row->uuid) && is_resource($row->uuid)) {
$row->uuid = stream_get_contents($row->uuid);
}
$tr = static::tr([
$this->renderObjectNameColumn($row),
$this->renderExtraColumns($row)
@ -226,6 +234,7 @@ class ObjectsTable extends ZfQueryBasedTable
protected function loadRestrictions()
{
/** @var Db $db */
$db = $this->connection();
$auth = $this->getAuth();
@ -249,7 +258,9 @@ class ObjectsTable extends ZfQueryBasedTable
protected function branchifyColumns($columns)
{
$result = [];
$result = [
'uuid' => 'COALESCE(o.uuid, bo.uuid)'
];
$ignore = ['o.id'];
foreach ($columns as $alias => $column) {
if (substr($column, 0, 2) === 'o.' && ! in_array($column, $ignore)) {
@ -257,6 +268,11 @@ class ObjectsTable extends ZfQueryBasedTable
$column = "COALESCE(b$column, $column)";
}
// Used in Service Tables:
if ($column === 'h.object_name' && $alias = 'host') {
$column = "COALESCE(bo.host, $column)";
}
$result[$alias] = $column;
}
@ -299,19 +315,21 @@ class ObjectsTable extends ZfQueryBasedTable
['bo' => "branched_$table"],
// TODO: PgHexFunc
$this->db()->quoteInto(
'bo.object_id = o.id AND bo.branch_uuid = ?',
'bo.uuid = o.uuid AND bo.branch_uuid = ?',
$conn->quoteBinary($this->branchUuid->getBytes())
),
[]
)->where("(bo.deleted IS NULL OR bo.deleted = 'n')");
)->where("(bo.branch_deleted IS NULL OR bo.branch_deleted = 'n')");
$this->applyObjectTypeFilter($query, $right);
$right->joinRight(
['bo' => "branched_$table"],
'bo.object_id = o.id',
'bo.uuid = o.uuid',
[]
)
->where('o.id IS NULL')
->where('o.uuid IS NULL')
->where('bo.branch_uuid = ?', $conn->quoteBinary($this->branchUuid->getBytes()));
$this->leftSubQuery = $query;
$this->rightSubQuery = $right;
$query = $this->db()->select()->union([
'l' => new DbSelectParenthesis($query),
'r' => new DbSelectParenthesis($right),

View File

@ -13,6 +13,7 @@ class ObjectsTableCommand extends ObjectsTable implements FilterableByUsage
];
protected $columns = [
'uuid' => 'o.uuid',
'object_name' => 'o.object_name',
'object_type' => 'o.object_type',
'disabled' => 'o.disabled',

View File

@ -21,7 +21,7 @@ class ObjectsTableHost extends ObjectsTable
'display_name' => 'o.display_name',
'address' => 'o.address',
'disabled' => 'o.disabled',
'id' => 'o.id',
'uuid' => 'o.uuid',
];
protected $showColumns = [
@ -34,7 +34,7 @@ class ObjectsTableHost extends ObjectsTable
$this->enableMultiSelect(
'director/hosts/edit',
'director/hosts',
['name']
['uuid']
);
}
}

View File

@ -6,6 +6,7 @@ use ipl\Html\Html;
use gipfl\IcingaWeb2\Table\Extension\MultiSelect;
use gipfl\IcingaWeb2\Link;
use gipfl\IcingaWeb2\Url;
use Ramsey\Uuid\Uuid;
class ObjectsTableService extends ObjectsTable
{
@ -13,30 +14,28 @@ class ObjectsTableService extends ObjectsTable
protected $type = 'service';
protected $columns = [
'object_name' => 'o.object_name',
'disabled' => 'o.disabled',
'host' => 'h.object_name',
'host_object_type' => 'h.object_type',
'host_disabled' => 'h.disabled',
'id' => 'o.id',
'uuid' => 'o.uuid',
'blacklisted' => "CASE WHEN hsb.service_id IS NULL THEN 'n' ELSE 'y' END",
];
protected $searchColumns = [
'o.object_name',
'h.object_name'
];
public function getColumns()
{
return [
'object_name' => 'o.object_name',
'disabled' => 'o.disabled',
'host' => 'h.object_name',
'host_object_type' => 'h.object_type',
'host_disabled' => 'h.disabled',
'id' => 'o.id',
'blacklisted' => "CASE WHEN hsb.service_id IS NULL THEN 'n' ELSE 'y' END",
];
}
public function assemble()
{
$this->enableMultiSelect(
'director/services/edit',
'director/services',
['id']
['uuid']
);
}
@ -50,11 +49,27 @@ class ObjectsTableService extends ObjectsTable
public function renderRow($row)
{
$url = Url::fromPath('director/service/edit', [
'name' => $row->object_name,
'host' => $row->host,
'id' => $row->id,
]);
$params = [
'uuid' => Uuid::fromBytes($row->uuid)->toString(),
];
if ($row->host !== null) {
$params['host'] = $row->host;
}
$url = Url::fromPath('director/service/edit', $params);
/*
if ($this->branchUuid) {
$url = Url::fromPath('director/service/edit', [
'uuid' => Uuid::fromBytes($row->uuid)->toString(),
'host' => $row->host,
]);
} else {
$url = Url::fromPath('director/service/edit', [
'name' => $row->object_name,
'host' => $row->host,
'id' => $row->id,
]);
}
*/
$caption = $row->host === null
? Html::tag('span', ['class' => 'error'], '- none -')
@ -70,27 +85,40 @@ class ObjectsTableService extends ObjectsTable
]);
$attributes = $tr->getAttributes();
$classes = $this->getRowClasses($row);
if ($row->host_disabled === 'y' || $row->disabled === 'y') {
$attributes->add('class', 'disabled');
$classes[] = 'disabled';
}
if ($row->blacklisted === 'y') {
$attributes->add('class', 'strike-links');
$classes[] = 'strike-links';
}
$attributes->add('class', $classes);
return $tr;
}
public function prepareQuery()
{
return parent::prepareQuery()->joinLeft(
['h' => 'icinga_host'],
'o.host_id = h.id',
[]
)->joinLeft(
['hsb' => 'icinga_host_service_blacklist'],
'hsb.service_id = o.id AND hsb.host_id = o.host_id',
[]
)->where('o.service_set_id IS NULL')
->order('o.object_name')->order('h.object_name');
$query = parent::prepareQuery();
if ($this->branchUuid) {
$queries = [$this->leftSubQuery, $this->rightSubQuery];
} else {
$queries = [$query];
}
foreach ($queries as $subQuery) {
$subQuery->joinLeft(
['h' => 'icinga_host'],
'o.host_id = h.id',
[]
)->joinLeft(
['hsb' => 'icinga_host_service_blacklist'],
'hsb.service_id = o.id AND hsb.host_id = o.host_id',
[]
)->where('o.service_set_id IS NULL')
->order('o.object_name')->order('h.object_name');
}
return $query;
}
}

View File

@ -127,12 +127,12 @@ class ActivityLogInfo extends HtmlDocument
$this->add($this->getInfoTable());
if ($tabName === 'old') {
// $title = sprintf('%s former config', $this->entry->object_name);
$diffs = $this->getConfigDiffs($this->oldConfig(), $this->emptyConfig());
$diffs = IcingaConfigDiff::getDiffs($this->oldConfig(), $this->emptyConfig());
} elseif ($tabName === 'new') {
// $title = sprintf('%s new config', $this->entry->object_name);
$diffs = $this->getConfigDiffs($this->emptyConfig(), $this->newConfig());
$diffs = IcingaConfigDiff::getDiffs($this->emptyConfig(), $this->newConfig());
} else {
$diffs = $this->getConfigDiffs($this->oldConfig(), $this->newConfig());
$diffs = IcingaConfigDiff::getDiffs($this->oldConfig(), $this->newConfig());
}
$this->addDiffs($diffs);
@ -399,41 +399,6 @@ class ActivityLogInfo extends HtmlDocument
return $tabs;
}
/**
* @param IcingaConfig $oldConfig
* @param IcingaConfig $newConfig
* @return ValidHtml[]
*/
protected function getConfigDiffs(IcingaConfig $oldConfig, IcingaConfig $newConfig)
{
$oldFileNames = $oldConfig->getFileNames();
$newFileNames = $newConfig->getFileNames();
$fileNames = array_merge($oldFileNames, $newFileNames);
$diffs = [];
foreach ($fileNames as $filename) {
if (in_array($filename, $oldFileNames)) {
$left = $oldConfig->getFile($filename)->getContent();
} else {
$left = '';
}
if (in_array($filename, $newFileNames)) {
$right = $newConfig->getFile($filename)->getContent();
} else {
$right = '';
}
if ($left === $right) {
continue;
}
$diffs[$filename] = new SideBySideDiff(new PhpDiff($left, $right));
}
return $diffs;
}
/**
* @return IcingaObject
* @throws \Icinga\Exception\IcingaException

View File

@ -5,17 +5,16 @@ namespace Icinga\Module\Director\Web\Widget;
use gipfl\Translation\TranslationHelper;
use gipfl\Web\Widget\Hint;
use Icinga\Authentication\Auth;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Db\Branch\Branch;
use Icinga\Module\Director\Db\Branch\ObjectModification;
use Icinga\Module\Director\Db\Branch\BranchedObject;
use ipl\Html\Html;
use ipl\Html\HtmlDocument;
class ObjectModificationBranchHint extends HtmlDocument
class BranchedObjectHint extends HtmlDocument
{
use TranslationHelper;
public function __construct(Branch $branch, Auth $auth, DbObject $object, ObjectModification $modification = null)
public function __construct(Branch $branch, Auth $auth, BranchedObject $object)
{
if (! $branch->isBranch()) {
return;
@ -30,7 +29,7 @@ class ObjectModificationBranchHint extends HtmlDocument
}
$link = $hook->linkToBranch($branch, $auth, $label);
if ($modification === null) {
if (! $object->hasBeenTouchedByBranch()) {
$this->add(Hint::info(Html::sprintf($this->translate(
'Your changes will be stored in %s. The\'ll not be part of any deployment'
. ' unless being merged'
@ -38,23 +37,23 @@ class ObjectModificationBranchHint extends HtmlDocument
return;
}
if ($modification->isDeletion()) {
if ($object->hasBeenDeletedByBranch()) {
$this->add(Hint::info(Html::sprintf(
$this->translate('This object has been deleted in %s'),
$link
)));
} elseif ($modification->isModification()) {
} elseif ($object->hasBeenCreatedByBranch()) {
$this->add(Hint::info(Html::sprintf(
$this->translate('This object has been created in %s'),
$link
)));
} else {
$this->add(Hint::info(Html::sprintf(
$this->translate('This object has modifications visible only in %s'),
// TODO: Also link to object modifications
// $hook->linkToBranchedObject($this->translate('modifications'), $branch, $object, $auth),
$link
)));
} else {
$this->add(Hint::info(Html::sprintf(
$this->translate('This object has been created in %s'),
$link
)));
}
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace Icinga\Module\Director\Web\Widget;
use gipfl\Diff\HtmlRenderer\SideBySideDiff;
use gipfl\Diff\PhpDiff;
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
use ipl\Html\Html;
use ipl\Html\HtmlDocument;
use ipl\Html\ValidHtml;
class IcingaConfigDiff extends HtmlDocument
{
public function __construct(IcingaConfig $left, IcingaConfig $right)
{
foreach (static::getDiffs($left, $right) as $filename => $diff) {
$this->add([
Html::tag('h3', $filename),
$diff
]);
}
}
/**
* @param IcingaConfig $oldConfig
* @param IcingaConfig $newConfig
* @return ValidHtml[]
*/
public static function getDiffs(IcingaConfig $oldConfig, IcingaConfig $newConfig)
{
$oldFileNames = $oldConfig->getFileNames();
$newFileNames = $newConfig->getFileNames();
$fileNames = array_merge($oldFileNames, $newFileNames);
$diffs = [];
foreach ($fileNames as $filename) {
if (in_array($filename, $oldFileNames)) {
$left = $oldConfig->getFile($filename)->getContent();
} else {
$left = '';
}
if (in_array($filename, $newFileNames)) {
$right = $newConfig->getFile($filename)->getContent();
} else {
$right = '';
}
if ($left === $right) {
continue;
}
$diffs[$filename] = new SideBySideDiff(new PhpDiff($left, $right));
}
return $diffs;
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace Icinga\Module\Director\Web\Widget;
use gipfl\Translation\TranslationHelper;
use gipfl\Web\Widget\Hint;
use Icinga\Authentication\Auth;
use Icinga\Module\Director\Db\Branch\Branch;
use ipl\Html\Html;
class NotInBranchedHint extends Hint
{
use TranslationHelper;
public function __construct($forbiddenAction, Branch $branch, Auth $auth)
{
parent::__construct(Html::sprintf(
$this->translate('%s is not available while being in a Configuration Branch: %s'),
$forbiddenAction,
Branch::requireHook()->linkToBranch($branch, $auth, $branch->getName())
), 'info');
}
}

View File

@ -0,0 +1,241 @@
ALTER TABLE icinga_zone ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_zone SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_zone MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_timeperiod ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_timeperiod SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_timeperiod MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_command ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_command SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_command MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_apiuser ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_apiuser SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_apiuser MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_endpoint ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_endpoint SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_endpoint MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_host ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_host SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_host MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_service ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_service SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_service MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_hostgroup ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_hostgroup SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_hostgroup MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_servicegroup ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_servicegroup SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_servicegroup MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_user ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_user SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_user MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_usergroup ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_usergroup SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_usergroup MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_notification ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_notification SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_notification MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_dependency ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_dependency SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_dependency MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE icinga_scheduled_downtime ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE icinga_scheduled_downtime SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE icinga_scheduled_downtime MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
INSERT INTO director_schema_migration
(schema_version, migration_time)
VALUES (174, NOW());

View File

@ -0,0 +1,484 @@
CREATE TABLE director_branch (
uuid VARBINARY(16) NOT NULL,
owner VARCHAR(255) NOT NULL,
branch_name VARCHAR(255) NOT NULL,
description TEXT DEFAULT NULL,
ts_merge_request BIGINT DEFAULT NULL,
PRIMARY KEY(uuid),
UNIQUE KEY (branch_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE director_branch_activity (
timestamp_ns BIGINT(20) NOT NULL,
object_uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
action ENUM ('create', 'modify', 'delete') NOT NULL,
object_table VARCHAR(64) NOT NULL,
author VARCHAR(255) NOT NULL,
former_properties LONGTEXT NOT NULL, -- json-encoded
modified_properties LONGTEXT NOT NULL,
PRIMARY KEY (timestamp_ns),
INDEX object_uuid (object_uuid),
INDEX branch_uuid (branch_uuid),
CONSTRAINT branch_activity_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_host (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
address VARCHAR(255) DEFAULT NULL,
address6 VARCHAR(45) DEFAULT NULL,
check_command VARCHAR(255) DEFAULT NULL,
max_check_attempts MEDIUMINT UNSIGNED DEFAULT NULL,
check_period VARCHAR(255) DEFAULT NULL,
check_interval VARCHAR(8) DEFAULT NULL,
retry_interval VARCHAR(8) DEFAULT NULL,
check_timeout SMALLINT UNSIGNED DEFAULT NULL,
enable_notifications ENUM('y', 'n') DEFAULT NULL,
enable_active_checks ENUM('y', 'n') DEFAULT NULL,
enable_passive_checks ENUM('y', 'n') DEFAULT NULL,
enable_event_handler ENUM('y', 'n') DEFAULT NULL,
enable_flapping ENUM('y', 'n') DEFAULT NULL,
enable_perfdata ENUM('y', 'n') DEFAULT NULL,
event_command VARCHAR(255) DEFAULT NULL,
flapping_threshold_high SMALLINT UNSIGNED DEFAULT NULL,
flapping_threshold_low SMALLINT UNSIGNED DEFAULT NULL,
volatile ENUM('y', 'n') DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
command_endpoint VARCHAR(255) DEFAULT NULL,
notes TEXT DEFAULT NULL,
notes_url VARCHAR(255) DEFAULT NULL,
action_url VARCHAR(255) DEFAULT NULL,
icon_image VARCHAR(255) DEFAULT NULL,
icon_image_alt VARCHAR(255) DEFAULT NULL,
has_agent ENUM('y', 'n') DEFAULT NULL,
master_should_connect ENUM('y', 'n') DEFAULT NULL,
accept_config ENUM('y', 'n') DEFAULT NULL,
api_key VARCHAR(40) DEFAULT NULL,
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars MEDIUMTEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_host_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_hostgroup (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_hostgroup_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_servicegroup (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_servicegroup_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_usergroup (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_usergroup_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_user (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
email VARCHAR(255) DEFAULT NULL,
pager VARCHAR(255) DEFAULT NULL,
enable_notifications ENUM('y', 'n') DEFAULT NULL,
period VARCHAR(255) DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
states TEXT DEFAULT NULL,
types TEXT DEFAULT NULL,
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars MEDIUMTEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_user_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_zone (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
parent VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
is_global ENUM('y', 'n') DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_zone_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_timeperiod (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
update_method VARCHAR(64) DEFAULT NULL COMMENT 'Usually LegacyTimePeriod',
zone VARCHAR(255) DEFAULT NULL,
prefer_includes ENUM('y', 'n') DEFAULT NULL,
imports TEXT DEFAULT NULL,
ranges TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_timeperiod_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_command (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
methods_execute VARCHAR(64) DEFAULT NULL,
command TEXT DEFAULT NULL,
is_string ENUM('y', 'n') NULL,
timeout SMALLINT UNSIGNED DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
arguments TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_command_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_apiuser (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
password VARCHAR(255) DEFAULT NULL,
client_dn VARCHAR(64) DEFAULT NULL,
permissions TEXT DEFAULT NULL COMMENT 'JSON-encoded permissions',
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_apiuser_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_endpoint (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
host VARCHAR(255) DEFAULT NULL,
port SMALLINT UNSIGNED DEFAULT NULL,
log_duration VARCHAR(32) DEFAULT NULL,
apiuser VARCHAR(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_endpoint_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_service (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
host VARCHAR(255) DEFAULT NULL,
service_set VARCHAR(255) DEFAULT NULL,
check_command VARCHAR(255) DEFAULT NULL,
max_check_attempts MEDIUMINT UNSIGNED DEFAULT NULL,
check_period VARCHAR(255) DEFAULT NULL,
check_interval VARCHAR(8) DEFAULT NULL,
retry_interval VARCHAR(8) DEFAULT NULL,
check_timeout SMALLINT UNSIGNED DEFAULT NULL,
enable_notifications ENUM('y', 'n') DEFAULT NULL,
enable_active_checks ENUM('y', 'n') DEFAULT NULL,
enable_passive_checks ENUM('y', 'n') DEFAULT NULL,
enable_event_handler ENUM('y', 'n') DEFAULT NULL,
enable_flapping ENUM('y', 'n') DEFAULT NULL,
enable_perfdata ENUM('y', 'n') DEFAULT NULL,
event_command VARCHAR(255) DEFAULT NULL,
flapping_threshold_high SMALLINT UNSIGNED DEFAULT NULL,
flapping_threshold_low SMALLINT UNSIGNED DEFAULT NULL,
volatile ENUM('y', 'n') DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
command_endpoint VARCHAR(255) DEFAULT NULL,
notes TEXT DEFAULT NULL,
notes_url VARCHAR(255) DEFAULT NULL,
action_url VARCHAR(255) DEFAULT NULL,
icon_image VARCHAR(255) DEFAULT NULL,
icon_image_alt VARCHAR(255) DEFAULT NULL,
use_agent ENUM('y', 'n') DEFAULT NULL,
apply_for VARCHAR(255) DEFAULT NULL,
use_var_overrides ENUM('y', 'n') DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
-- template_choice VARCHAR(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars MEDIUMTEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_service_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_notification (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
apply_to ENUM('host', 'service') DEFAULT NULL,
host VARCHAR(255) DEFAULT NULL,
service VARCHAR(255) DEFAULT NULL,
times_begin INT(10) UNSIGNED DEFAULT NULL,
times_end INT(10) UNSIGNED DEFAULT NULL,
notification_interval INT(10) UNSIGNED DEFAULT NULL,
command VARCHAR(255) DEFAULT NULL,
period VARCHAR(255) DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
states TEXT DEFAULT NULL,
types TEXT DEFAULT NULL,
users TEXT DEFAULT NULL,
usergroups TEXT DEFAULT NULL,
imports TEXT DEFAULT NULL,
vars MEDIUMTEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_notification_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_scheduled_downtime (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
apply_to ENUM('host', 'service') DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
author VARCHAR(255) DEFAULT NULL,
comment TEXT DEFAULT NULL,
fixed ENUM('y', 'n') DEFAULT NULL,
duration INT(10) UNSIGNED DEFAULT NULL,
with_services ENUM('y', 'n') NULL DEFAULT NULL,
imports TEXT DEFAULT NULL,
ranges TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_scheduled_downtime_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_dependency (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
apply_to ENUM('host', 'service') DEFAULT NULL,
parent_host VARCHAR(255) DEFAULT NULL,
parent_host_var VARCHAR(128) DEFAULT NULL,
parent_service VARCHAR(255) DEFAULT NULL,
child_host VARCHAR(255) DEFAULT NULL,
child_service VARCHAR(255) DEFAULT NULL,
disable_checks ENUM('y', 'n') DEFAULT NULL,
disable_notifications ENUM('y', 'n') DEFAULT NULL,
ignore_soft_states ENUM('y', 'n') DEFAULT NULL,
period VARCHAR(255) DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
parent_service_by_name VARCHAR(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_dependency_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO director_schema_migration
(schema_version, migration_time)
VALUES (175, NOW());

View File

@ -231,12 +231,14 @@ CREATE TABLE director_setting (
CREATE TABLE icinga_zone (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
parent_id INT(10) UNSIGNED DEFAULT NULL,
object_name VARCHAR(255) NOT NULL,
object_type ENUM('object', 'template', 'external_object') NOT NULL,
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
is_global ENUM('y', 'n') NOT NULL DEFAULT 'n',
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE INDEX object_name (object_name),
CONSTRAINT icinga_zone_parent
FOREIGN KEY parent_zone (parent_id)
@ -265,6 +267,7 @@ CREATE TABLE icinga_zone_inheritance (
CREATE TABLE icinga_timeperiod (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) NOT NULL,
display_name VARCHAR(255) DEFAULT NULL,
update_method VARCHAR(64) DEFAULT NULL COMMENT 'Usually LegacyTimePeriod',
@ -273,6 +276,7 @@ CREATE TABLE icinga_timeperiod (
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
prefer_includes ENUM('y', 'n') DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE INDEX object_name (object_name, zone_id),
CONSTRAINT icinga_timeperiod_zone
FOREIGN KEY zone (zone_id)
@ -349,6 +353,7 @@ CREATE TABLE director_job_setting (
CREATE TABLE icinga_command (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) NOT NULL,
object_type ENUM('object', 'template', 'external_object') NOT NULL
COMMENT 'external_object is an attempt to work with existing commands',
@ -361,6 +366,7 @@ CREATE TABLE icinga_command (
timeout SMALLINT UNSIGNED DEFAULT NULL,
zone_id INT(10) UNSIGNED DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE INDEX object_name (object_name),
CONSTRAINT icinga_command_zone
FOREIGN KEY zone (zone_id)
@ -447,17 +453,20 @@ CREATE TABLE icinga_command_var (
CREATE TABLE icinga_apiuser (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) NOT NULL,
object_type ENUM('object', 'template', 'external_object') NOT NULL,
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
password VARCHAR(255) DEFAULT NULL,
client_dn VARCHAR(64) DEFAULT NULL,
permissions TEXT DEFAULT NULL COMMENT 'JSON-encoded permissions',
PRIMARY KEY (id)
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE icinga_endpoint (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
zone_id INT(10) UNSIGNED DEFAULT NULL,
object_name VARCHAR(255) NOT NULL,
object_type ENUM('object', 'template', 'external_object') NOT NULL,
@ -467,6 +476,7 @@ CREATE TABLE icinga_endpoint (
log_duration VARCHAR(32) DEFAULT NULL COMMENT '1d if not set',
apiuser_id INT(10) UNSIGNED DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE INDEX object_name (object_name),
CONSTRAINT icinga_endpoint_zone
FOREIGN KEY zone (zone_id)
@ -512,6 +522,7 @@ CREATE TABLE icinga_host_template_choice (
CREATE TABLE icinga_host (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) NOT NULL,
object_type ENUM('object', 'template') NOT NULL,
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
@ -547,6 +558,7 @@ CREATE TABLE icinga_host (
api_key VARCHAR(40) DEFAULT NULL,
template_choice_id INT(10) UNSIGNED DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE INDEX object_name (object_name),
UNIQUE INDEX api_key (api_key),
KEY search_idx (display_name),
@ -671,6 +683,7 @@ CREATE TABLE icinga_service_template_choice (
CREATE TABLE icinga_service (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) NOT NULL,
object_type ENUM('object', 'template', 'apply') NOT NULL,
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
@ -706,6 +719,7 @@ CREATE TABLE icinga_service (
assign_filter TEXT DEFAULT NULL,
template_choice_id INT(10) UNSIGNED DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE KEY object_key (object_name, host_id),
CONSTRAINT icinga_service_host
FOREIGN KEY host (host_id)
@ -876,12 +890,14 @@ CREATE TABLE icinga_service_set_var (
CREATE TABLE icinga_hostgroup (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) NOT NULL,
object_type ENUM('object', 'template', 'external_object') NOT NULL,
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
display_name VARCHAR(255) DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE INDEX object_name (object_name),
KEY search_idx (display_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@ -907,12 +923,14 @@ CREATE TABLE icinga_hostgroup_inheritance (
CREATE TABLE icinga_servicegroup (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template') NOT NULL,
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
display_name VARCHAR(255) DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE INDEX object_name (object_name),
KEY search_idx (display_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@ -1017,6 +1035,7 @@ CREATE TABLE icinga_hostgroup_parent (
CREATE TABLE icinga_user (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template') NOT NULL,
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
@ -1027,6 +1046,7 @@ CREATE TABLE icinga_user (
period_id INT(10) UNSIGNED DEFAULT NULL,
zone_id INT(10) UNSIGNED DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE INDEX object_name (object_name, zone_id),
CONSTRAINT icinga_user_zone
FOREIGN KEY zone (zone_id)
@ -1137,12 +1157,14 @@ CREATE TABLE icinga_user_field (
CREATE TABLE icinga_usergroup (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) NOT NULL,
object_type ENUM('object', 'template') NOT NULL,
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
display_name VARCHAR(255) DEFAULT NULL,
zone_id INT(10) UNSIGNED DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE INDEX object_name (object_name),
KEY search_idx (display_name),
CONSTRAINT icinga_usergroup_zone
@ -1204,6 +1226,7 @@ CREATE TABLE icinga_usergroup_parent (
CREATE TABLE icinga_notification (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') NOT NULL,
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
@ -1218,6 +1241,7 @@ CREATE TABLE icinga_notification (
zone_id INT(10) UNSIGNED DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
CONSTRAINT icinga_notification_host
FOREIGN KEY host (host_id)
REFERENCES icinga_host (id)
@ -1707,6 +1731,7 @@ CREATE TABLE icinga_user_resolved_var (
CREATE TABLE icinga_dependency (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') NOT NULL,
disabled ENUM('y', 'n') NOT NULL DEFAULT 'n',
@ -1724,6 +1749,7 @@ CREATE TABLE icinga_dependency (
assign_filter TEXT DEFAULT NULL,
parent_service_by_name VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
CONSTRAINT icinga_dependency_parent_host
FOREIGN KEY parent_host (parent_host_id)
REFERENCES icinga_host (id)
@ -1828,6 +1854,7 @@ CREATE TABLE icinga_timeperiod_exclude (
CREATE TABLE icinga_scheduled_downtime (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
object_name VARCHAR(255) NOT NULL,
zone_id INT(10) UNSIGNED DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') NOT NULL,
@ -1840,6 +1867,7 @@ CREATE TABLE icinga_scheduled_downtime (
duration INT(10) UNSIGNED DEFAULT NULL,
with_services ENUM('y', 'n') NULL DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE INDEX uuid (uuid),
UNIQUE INDEX object_name (object_name),
CONSTRAINT icinga_scheduled_downtime_zone
FOREIGN KEY zone (zone_id)
@ -1882,6 +1910,487 @@ CREATE TABLE icinga_scheduled_downtime_range (
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE director_branch (
uuid VARBINARY(16) NOT NULL,
owner VARCHAR(255) NOT NULL,
branch_name VARCHAR(255) NOT NULL,
description TEXT DEFAULT NULL,
ts_merge_request BIGINT DEFAULT NULL,
PRIMARY KEY(uuid),
UNIQUE KEY (branch_name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE director_branch_activity (
timestamp_ns BIGINT(20) NOT NULL,
object_uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
action ENUM ('create', 'modify', 'delete') NOT NULL,
object_table VARCHAR(64) NOT NULL,
author VARCHAR(255) NOT NULL,
former_properties LONGTEXT NOT NULL, -- json-encoded
modified_properties LONGTEXT NOT NULL,
PRIMARY KEY (timestamp_ns),
INDEX object_uuid (object_uuid),
INDEX branch_uuid (branch_uuid),
CONSTRAINT branch_activity_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_host (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
address VARCHAR(255) DEFAULT NULL,
address6 VARCHAR(45) DEFAULT NULL,
check_command VARCHAR(255) DEFAULT NULL,
max_check_attempts MEDIUMINT UNSIGNED DEFAULT NULL,
check_period VARCHAR(255) DEFAULT NULL,
check_interval VARCHAR(8) DEFAULT NULL,
retry_interval VARCHAR(8) DEFAULT NULL,
check_timeout SMALLINT UNSIGNED DEFAULT NULL,
enable_notifications ENUM('y', 'n') DEFAULT NULL,
enable_active_checks ENUM('y', 'n') DEFAULT NULL,
enable_passive_checks ENUM('y', 'n') DEFAULT NULL,
enable_event_handler ENUM('y', 'n') DEFAULT NULL,
enable_flapping ENUM('y', 'n') DEFAULT NULL,
enable_perfdata ENUM('y', 'n') DEFAULT NULL,
event_command VARCHAR(255) DEFAULT NULL,
flapping_threshold_high SMALLINT UNSIGNED DEFAULT NULL,
flapping_threshold_low SMALLINT UNSIGNED DEFAULT NULL,
volatile ENUM('y', 'n') DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
command_endpoint VARCHAR(255) DEFAULT NULL,
notes TEXT DEFAULT NULL,
notes_url VARCHAR(255) DEFAULT NULL,
action_url VARCHAR(255) DEFAULT NULL,
icon_image VARCHAR(255) DEFAULT NULL,
icon_image_alt VARCHAR(255) DEFAULT NULL,
has_agent ENUM('y', 'n') DEFAULT NULL,
master_should_connect ENUM('y', 'n') DEFAULT NULL,
accept_config ENUM('y', 'n') DEFAULT NULL,
api_key VARCHAR(40) DEFAULT NULL,
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars MEDIUMTEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_host_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_hostgroup (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_hostgroup_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_servicegroup (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_servicegroup_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_usergroup (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_usergroup_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_user (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
email VARCHAR(255) DEFAULT NULL,
pager VARCHAR(255) DEFAULT NULL,
enable_notifications ENUM('y', 'n') DEFAULT NULL,
period VARCHAR(255) DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
states TEXT DEFAULT NULL,
types TEXT DEFAULT NULL,
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars MEDIUMTEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_user_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_zone (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
parent VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
is_global ENUM('y', 'n') DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_zone_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_timeperiod (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
update_method VARCHAR(64) DEFAULT NULL COMMENT 'Usually LegacyTimePeriod',
zone VARCHAR(255) DEFAULT NULL,
prefer_includes ENUM('y', 'n') DEFAULT NULL,
imports TEXT DEFAULT NULL,
ranges TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_timeperiod_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_command (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
methods_execute VARCHAR(64) DEFAULT NULL,
command TEXT DEFAULT NULL,
is_string ENUM('y', 'n') NULL,
timeout SMALLINT UNSIGNED DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
arguments TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_command_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_apiuser (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
password VARCHAR(255) DEFAULT NULL,
client_dn VARCHAR(64) DEFAULT NULL,
permissions TEXT DEFAULT NULL COMMENT 'JSON-encoded permissions',
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_apiuser_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_endpoint (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'external_object') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
host VARCHAR(255) DEFAULT NULL,
port SMALLINT UNSIGNED DEFAULT NULL,
log_duration VARCHAR(32) DEFAULT NULL,
apiuser VARCHAR(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_endpoint_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_service (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
display_name VARCHAR(255) DEFAULT NULL,
host VARCHAR(255) DEFAULT NULL,
service_set VARCHAR(255) DEFAULT NULL,
check_command VARCHAR(255) DEFAULT NULL,
max_check_attempts MEDIUMINT UNSIGNED DEFAULT NULL,
check_period VARCHAR(255) DEFAULT NULL,
check_interval VARCHAR(8) DEFAULT NULL,
retry_interval VARCHAR(8) DEFAULT NULL,
check_timeout SMALLINT UNSIGNED DEFAULT NULL,
enable_notifications ENUM('y', 'n') DEFAULT NULL,
enable_active_checks ENUM('y', 'n') DEFAULT NULL,
enable_passive_checks ENUM('y', 'n') DEFAULT NULL,
enable_event_handler ENUM('y', 'n') DEFAULT NULL,
enable_flapping ENUM('y', 'n') DEFAULT NULL,
enable_perfdata ENUM('y', 'n') DEFAULT NULL,
event_command VARCHAR(255) DEFAULT NULL,
flapping_threshold_high SMALLINT UNSIGNED DEFAULT NULL,
flapping_threshold_low SMALLINT UNSIGNED DEFAULT NULL,
volatile ENUM('y', 'n') DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
command_endpoint VARCHAR(255) DEFAULT NULL,
notes TEXT DEFAULT NULL,
notes_url VARCHAR(255) DEFAULT NULL,
action_url VARCHAR(255) DEFAULT NULL,
icon_image VARCHAR(255) DEFAULT NULL,
icon_image_alt VARCHAR(255) DEFAULT NULL,
use_agent ENUM('y', 'n') DEFAULT NULL,
apply_for VARCHAR(255) DEFAULT NULL,
use_var_overrides ENUM('y', 'n') DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
-- template_choice VARCHAR(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars MEDIUMTEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
INDEX search_object_name (object_name),
INDEX search_display_name (display_name),
CONSTRAINT icinga_service_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_notification (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
apply_to ENUM('host', 'service') DEFAULT NULL,
host VARCHAR(255) DEFAULT NULL,
service VARCHAR(255) DEFAULT NULL,
times_begin INT(10) UNSIGNED DEFAULT NULL,
times_end INT(10) UNSIGNED DEFAULT NULL,
notification_interval INT(10) UNSIGNED DEFAULT NULL,
command VARCHAR(255) DEFAULT NULL,
period VARCHAR(255) DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
states TEXT DEFAULT NULL,
types TEXT DEFAULT NULL,
users TEXT DEFAULT NULL,
usergroups TEXT DEFAULT NULL,
imports TEXT DEFAULT NULL,
vars MEDIUMTEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_notification_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_scheduled_downtime (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
apply_to ENUM('host', 'service') DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
author VARCHAR(255) DEFAULT NULL,
comment TEXT DEFAULT NULL,
fixed ENUM('y', 'n') DEFAULT NULL,
duration INT(10) UNSIGNED DEFAULT NULL,
with_services ENUM('y', 'n') NULL DEFAULT NULL,
imports TEXT DEFAULT NULL,
ranges TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_scheduled_downtime_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE branched_icinga_dependency (
uuid VARBINARY(16) NOT NULL,
branch_uuid VARBINARY(16) NOT NULL,
branch_created ENUM('y', 'n') NOT NULL DEFAULT 'n',
branch_deleted ENUM('y', 'n') NOT NULL DEFAULT 'n',
object_name VARCHAR(255) DEFAULT NULL,
object_type ENUM('object', 'template', 'apply') DEFAULT NULL,
disabled ENUM('y', 'n') DEFAULT NULL,
apply_to ENUM('host', 'service') DEFAULT NULL,
parent_host VARCHAR(255) DEFAULT NULL,
parent_host_var VARCHAR(128) DEFAULT NULL,
parent_service VARCHAR(255) DEFAULT NULL,
child_host VARCHAR(255) DEFAULT NULL,
child_service VARCHAR(255) DEFAULT NULL,
disable_checks ENUM('y', 'n') DEFAULT NULL,
disable_notifications ENUM('y', 'n') DEFAULT NULL,
ignore_soft_states ENUM('y', 'n') DEFAULT NULL,
period VARCHAR(255) DEFAULT NULL,
zone VARCHAR(255) DEFAULT NULL,
assign_filter TEXT DEFAULT NULL,
parent_service_by_name VARCHAR(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
UNIQUE INDEX branch_object_name (branch_uuid, object_name),
INDEX search_object_name (object_name),
CONSTRAINT icinga_dependency_branch
FOREIGN KEY branch (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO director_schema_migration
(schema_version, migration_time)
VALUES (173, NOW());
VALUES (175, NOW());

View File

@ -0,0 +1,73 @@
ALTER TABLE icinga_zone ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_zone SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_zone ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX zone_uuid ON icinga_zone (uuid);
ALTER TABLE icinga_timeperiod ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_timeperiod SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_timeperiod ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX timeperiod_uuid ON icinga_timeperiod (uuid);
ALTER TABLE icinga_command ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_command SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_command ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX command_uuid ON icinga_command (uuid);
ALTER TABLE icinga_apiuser ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_apiuser SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_apiuser ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX apiuser_uuid ON icinga_apiuser (uuid);
ALTER TABLE icinga_endpoint ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_endpoint SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_endpoint ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX endpoint_uuid ON icinga_endpoint (uuid);
ALTER TABLE icinga_host ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_host SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_host ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX host_uuid ON icinga_host (uuid);
ALTER TABLE icinga_service ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_service SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_service ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX service_uuid ON icinga_service (uuid);
ALTER TABLE icinga_hostgroup ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_hostgroup SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_hostgroup ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX hostgroup_uuid ON icinga_hostgroup (uuid);
ALTER TABLE icinga_servicegroup ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_servicegroup SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_servicegroup ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX servicegroup_uuid ON icinga_servicegroup (uuid);
ALTER TABLE icinga_user ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_user SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_user ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX user_uuid ON icinga_user (uuid);
ALTER TABLE icinga_usergroup ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_usergroup SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_usergroup ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX usergroup_uuid ON icinga_usergroup (uuid);
ALTER TABLE icinga_notification ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_notification SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_notification ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX notification_uuid ON icinga_notification (uuid);
ALTER TABLE icinga_dependency ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_dependency SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_dependency ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX dependency_uuid ON icinga_dependency (uuid);
ALTER TABLE icinga_scheduled_downtime ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE icinga_scheduled_downtime SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE icinga_scheduled_downtime ALTER COLUMN uuid SET NOT NULL;
CREATE UNIQUE INDEX scheduled_downtime_uuid ON icinga_scheduled_downtime (uuid);
INSERT INTO director_schema_migration
(schema_version, migration_time)
VALUES (174, NOW());

View File

@ -0,0 +1,512 @@
CREATE TABLE director_branch (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
owner character varying(255) NOT NULL,
branch_name character varying(255) NOT NULL,
description text DEFAULT NULL,
ts_merge_request bigint DEFAULT NULL,
PRIMARY KEY(uuid)
);
CREATE UNIQUE INDEX branch_branch_name ON director_branch (branch_name);
CREATE TYPE enum_branch_action AS ENUM('create', 'modify', 'delete');
CREATE TABLE director_branch_activity (
timestamp_ns bigint NOT NULL,
object_uuid bytea NOT NULL CHECK(LENGTH(object_uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
action enum_branch_action NOT NULL,
object_table character varying(64) NOT NULL,
author character varying(255) NOT NULL,
former_properties text NOT NULL,
modified_properties text NOT NULL,
PRIMARY KEY (timestamp_ns),
CONSTRAINT branch_activity_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE INDEX branch_activity_object_uuid ON director_branch_activity (object_uuid);
CREATE INDEX branch_activity_branch_uuid ON director_branch_activity (branch_uuid);
CREATE TABLE branched_icinga_host (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name CHARACTER VARYING(255) DEFAULT NULL,
address character varying(255) DEFAULT NULL,
address6 character varying(45) DEFAULT NULL,
check_command character varying(255) DEFAULT NULL,
max_check_attempts integer DEFAULT NULL,
check_period character varying(255) DEFAULT NULL,
check_interval character varying(8) DEFAULT NULL,
retry_interval character varying(8) DEFAULT NULL,
check_timeout smallint DEFAULT NULL,
enable_notifications enum_boolean DEFAULT NULL,
enable_active_checks enum_boolean DEFAULT NULL,
enable_passive_checks enum_boolean DEFAULT NULL,
enable_event_handler enum_boolean DEFAULT NULL,
enable_flapping enum_boolean DEFAULT NULL,
enable_perfdata enum_boolean DEFAULT NULL,
event_command character varying(255) DEFAULT NULL,
flapping_threshold_high smallint default null,
flapping_threshold_low smallint default null,
volatile enum_boolean DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
command_endpoint character varying(255) DEFAULT NULL,
notes text DEFAULT NULL,
notes_url character varying(255) DEFAULT NULL,
action_url character varying(255) DEFAULT NULL,
icon_image character varying(255) DEFAULT NULL,
icon_image_alt character varying(255) DEFAULT NULL,
has_agent enum_boolean DEFAULT NULL,
master_should_connect enum_boolean DEFAULT NULL,
accept_config enum_boolean DEFAULT NULL,
api_key character varying(40) DEFAULT NULL,
-- template_choice character varying(255) DEFAULT NULL, -- TODO: Forbid them!
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_host_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX host_branch_object_name ON branched_icinga_host (branch_uuid, object_name);
CREATE INDEX branched_host_search_object_name ON branched_icinga_host (object_name);
CREATE INDEX branched_host_search_display_name ON branched_icinga_host (display_name);
CREATE TABLE branched_icinga_hostgroup (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
assign_filter text DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_hostgroup_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX hostgroup_branch_object_name ON branched_icinga_hostgroup (branch_uuid, object_name);
CREATE INDEX branched_hostgroup_search_object_name ON branched_icinga_hostgroup (object_name);
CREATE INDEX branched_hostgroup_search_display_name ON branched_icinga_hostgroup (display_name);
CREATE TABLE branched_icinga_servicegroup (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
assign_filter text DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_servicegroup_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX servicegroup_branch_object_name ON branched_icinga_servicegroup (branch_uuid, object_name);
CREATE INDEX branched_servicegroup_search_object_name ON branched_icinga_servicegroup (object_name);
CREATE INDEX branched_servicegroup_search_display_name ON branched_icinga_servicegroup (display_name);
CREATE TABLE branched_icinga_usergroup (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
assign_filter text DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_usergroup_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX usergroup_branch_object_name ON branched_icinga_usergroup (branch_uuid, object_name);
CREATE INDEX branched_usergroup_search_object_name ON branched_icinga_usergroup (object_name);
CREATE INDEX branched_usergroup_search_display_name ON branched_icinga_usergroup (display_name);
CREATE TABLE branched_icinga_user (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
email character varying(255) DEFAULT NULL,
pager character varying(255) DEFAULT NULL,
enable_notifications enum_boolean DEFAULT NULL,
period character varying(255) DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_user_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX user_branch_object_name ON branched_icinga_user (branch_uuid, object_name);
CREATE INDEX branched_user_search_object_name ON branched_icinga_user (object_name);
CREATE INDEX branched_user_search_display_name ON branched_icinga_user (display_name);
CREATE TABLE branched_icinga_zone (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
parent character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
is_global enum_boolean DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_zone_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX zone_branch_object_name ON branched_icinga_zone (branch_uuid, object_name);
CREATE INDEX branched_zone_search_object_name ON branched_icinga_zone (object_name);
CREATE TABLE branched_icinga_timeperiod (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
update_method character varying(64) DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
prefer_includes enum_boolean DEFAULT NULL,
imports TEXT DEFAULT NULL,
ranges TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_timeperiod_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX timeperiod_branch_object_name ON branched_icinga_timeperiod (branch_uuid, object_name);
CREATE INDEX branched_timeperiod_search_object_name ON branched_icinga_timeperiod (object_name);
CREATE INDEX branched_timeperiod_search_display_name ON branched_icinga_timeperiod (display_name);
CREATE TABLE branched_icinga_command (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean NOT NULL DEFAULT NULL,
methods_execute character varying(64) DEFAULT NULL,
command text DEFAULT NULL,
is_string enum_boolean DEFAULT NULL,
-- env text DEFAULT NULL,
timeout smallint DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
arguments TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_command_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX command_branch_object_name ON branched_icinga_command (branch_uuid, object_name);
CREATE INDEX branched_command_search_object_name ON branched_icinga_command (object_name);
CREATE TABLE branched_icinga_apiuser (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name CHARACTER VARYING(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean NOT NULL DEFAULT NULL,
password CHARACTER VARYING(255) DEFAULT NULL,
client_dn CHARACTER VARYING(64) DEFAULT NULL,
permissions TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_apiuser_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX apiuser_branch_object_name ON branched_icinga_apiuser (branch_uuid, object_name);
CREATE INDEX branched_apiuser_search_object_name ON branched_icinga_apiuser (object_name);
CREATE TABLE branched_icinga_endpoint (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
zone character varying(255) DEFAULT NULL,
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean NOT NULL DEFAULT NULL,
host character varying(255) DEFAULT NULL,
port d_smallint DEFAULT NULL,
log_duration character varying(32) DEFAULT NULL,
apiuser character varying(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_endpoint_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX endpoint_branch_object_name ON branched_icinga_endpoint (branch_uuid, object_name);
CREATE INDEX branched_endpoint_search_object_name ON branched_icinga_endpoint (object_name);
CREATE TABLE branched_icinga_service (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
host character varying(255) DEFAULT NULL,
service_set character varying(255) DEFAULT NULL,
check_command character varying(255) DEFAULT NULL,
max_check_attempts integer DEFAULT NULL,
check_period character varying(255) DEFAULT NULL,
check_interval character varying(8) DEFAULT NULL,
retry_interval character varying(8) DEFAULT NULL,
check_timeout smallint DEFAULT NULL,
enable_notifications enum_boolean DEFAULT NULL,
enable_active_checks enum_boolean DEFAULT NULL,
enable_passive_checks enum_boolean DEFAULT NULL,
enable_event_handler enum_boolean DEFAULT NULL,
enable_flapping enum_boolean DEFAULT NULL,
enable_perfdata enum_boolean DEFAULT NULL,
event_command character varying(255) DEFAULT NULL,
flapping_threshold_high smallint DEFAULT NULL,
flapping_threshold_low smallint DEFAULT NULL,
volatile enum_boolean DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
command_endpoint character varying(255) DEFAULT NULL,
notes text DEFAULT NULL,
notes_url character varying(255) DEFAULT NULL,
action_url character varying(255) DEFAULT NULL,
icon_image character varying(255) DEFAULT NULL,
icon_image_alt character varying(255) DEFAULT NULL,
use_agent enum_boolean DEFAULT NULL,
apply_for character varying(255) DEFAULT NULL,
use_var_overrides enum_boolean DEFAULT NULL,
assign_filter text DEFAULT NULL,
-- template_choice_id int DEFAULT NULL,
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_service_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX service_branch_object_name ON branched_icinga_service (branch_uuid, object_name);
CREATE INDEX branched_service_search_object_name ON branched_icinga_service (object_name);
CREATE INDEX branched_service_search_display_name ON branched_icinga_service (display_name);
CREATE TABLE branched_icinga_notification (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name CHARACTER VARYING(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
apply_to enum_host_service DEFAULT NULL,
host character varying(255) DEFAULT NULL,
service character varying(255) DEFAULT NULL,
times_begin integer DEFAULT NULL,
times_end integer DEFAULT NULL,
notification_interval integer DEFAULT NULL,
command character varying(255) DEFAULT NULL,
period character varying(255) DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
assign_filter text DEFAULT NULL,
states TEXT DEFAULT NULL,
types TEXT DEFAULT NULL,
users TEXT DEFAULT NULL,
usergroups TEXT DEFAULT NULL,
imports TEXT DEFAULT NULL,
vars TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_notification_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX notification_branch_object_name ON branched_icinga_notification (branch_uuid, object_name);
CREATE INDEX branched_notification_search_object_name ON branched_icinga_notification (object_name);
CREATE TABLE branched_icinga_scheduled_downtime (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
zone_id integer DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
apply_to enum_host_service DEFAULT NULL,
assign_filter text DEFAULT NULL,
author character varying(255) DEFAULT NULL,
comment text DEFAULT NULL,
fixed enum_boolean DEFAULT NULL,
duration int DEFAULT NULL,
with_services enum_boolean DEFAULT NULL,
imports TEXT DEFAULT NULL,
ranges TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_scheduled_downtime_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX scheduled_downtime_branch_object_name ON branched_icinga_scheduled_downtime (branch_uuid, object_name);
CREATE INDEX branched_scheduled_downtime_search_object_name ON branched_icinga_scheduled_downtime (object_name);
CREATE TABLE branched_icinga_dependency (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) NOT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean DEFAULT 'n',
apply_to enum_host_service NULL DEFAULT NULL,
parent_host character varying(255) DEFAULT NULL,
parent_host_var character varying(128) DEFAULT NULL,
parent_service character varying(255) DEFAULT NULL,
child_host character varying(255) DEFAULT NULL,
child_service character varying(255) DEFAULT NULL,
disable_checks enum_boolean DEFAULT NULL,
disable_notifications enum_boolean DEFAULT NULL,
ignore_soft_states enum_boolean DEFAULT NULL,
period_id integer DEFAULT NULL,
zone_id integer DEFAULT NULL,
assign_filter text DEFAULT NULL,
parent_service_by_name character varying(255),
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_dependency_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX dependency_branch_object_name ON branched_icinga_dependency (branch_uuid, object_name);
CREATE INDEX branched_dependency_search_object_name ON branched_icinga_dependency (object_name);
INSERT INTO director_schema_migration
(schema_version, migration_time)
VALUES (175, NOW());

View File

@ -311,6 +311,7 @@ CREATE TABLE director_setting (
CREATE TABLE icinga_zone (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
parent_id integer DEFAULT NULL,
object_name character varying(255) NOT NULL UNIQUE,
object_type enum_object_type_all NOT NULL,
@ -325,6 +326,7 @@ CREATE TABLE icinga_zone (
);
CREATE INDEX zone_parent ON icinga_zone (parent_id);
CREATE UNIQUE INDEX zone_uuid ON icinga_zone (uuid);
CREATE TABLE icinga_zone_inheritance (
@ -351,6 +353,7 @@ CREATE INDEX zone_inheritance_zone_parent ON icinga_zone_inheritance (parent_zon
CREATE TABLE icinga_timeperiod (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name character varying(255) NOT NULL,
display_name character varying(255) DEFAULT NULL,
update_method character varying(64) DEFAULT NULL,
@ -366,6 +369,7 @@ CREATE TABLE icinga_timeperiod (
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX timeperiod_uuid ON icinga_timeperiod (uuid);
CREATE UNIQUE INDEX timeperiod_object_name ON icinga_timeperiod (object_name, zone_id);
CREATE INDEX timeperiod_zone ON icinga_timeperiod (zone_id);
COMMENT ON COLUMN icinga_timeperiod.update_method IS 'Usually LegacyTimePeriod';
@ -453,6 +457,7 @@ CREATE INDEX director_job_setting_job ON director_job_setting (job_id);
CREATE TABLE icinga_command (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name character varying(255) NOT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean NOT NULL DEFAULT 'n',
@ -470,6 +475,7 @@ CREATE TABLE icinga_command (
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX command_uuid ON icinga_command (uuid);
CREATE UNIQUE INDEX command_object_name ON icinga_command (object_name);
CREATE INDEX command_zone ON icinga_command (zone_id);
COMMENT ON COLUMN icinga_command.object_type IS 'external_object is an attempt to work with existing commands';
@ -567,6 +573,7 @@ CREATE INDEX command_var_checksum ON icinga_command_var (checksum);
CREATE TABLE icinga_apiuser (
id BIGSERIAL,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name CHARACTER VARYING(255) NOT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean NOT NULL DEFAULT 'n',
@ -576,11 +583,13 @@ CREATE TABLE icinga_apiuser (
PRIMARY KEY (id)
);
CREATE UNIQUE INDEX apiuser_uuid ON icinga_apiuser (uuid);
COMMENT ON COLUMN icinga_apiuser.permissions IS 'JSON-encoded permissions';
CREATE TABLE icinga_endpoint (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
zone_id integer DEFAULT NULL,
object_name character varying(255) NOT NULL,
object_type enum_object_type_all NOT NULL,
@ -602,6 +611,7 @@ CREATE TABLE icinga_endpoint (
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX endpoint_uuid ON icinga_endpoint (uuid);
CREATE UNIQUE INDEX endpoint_object_name ON icinga_endpoint (object_name);
CREATE INDEX endpoint_zone ON icinga_endpoint (zone_id);
COMMENT ON COLUMN icinga_endpoint.host IS 'IP address / hostname of remote node';
@ -647,6 +657,7 @@ CREATE INDEX host_template_choice_required_template ON icinga_host_template_choi
CREATE TABLE icinga_host (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name character varying(255) NOT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean NOT NULL DEFAULT 'n',
@ -715,6 +726,7 @@ CREATE TABLE icinga_host (
);
CREATE UNIQUE INDEX host_uuid ON icinga_host (uuid);
CREATE UNIQUE INDEX object_name_host ON icinga_host (object_name, zone_id);
CREATE UNIQUE INDEX host_api_key ON icinga_host (api_key);
CREATE INDEX host_zone ON icinga_host (zone_id);
@ -834,6 +846,7 @@ CREATE INDEX service_template_choice_required_template ON icinga_service_templat
CREATE TABLE icinga_service (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name character varying(255) NOT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean DEFAULT 'n',
@ -912,6 +925,7 @@ CREATE TABLE icinga_service (
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX service_uuid ON icinga_service (uuid);
CREATE INDEX service_zone ON icinga_service (zone_id);
CREATE INDEX service_timeperiod ON icinga_service (check_period_id);
CREATE INDEX service_check_command ON icinga_service (check_command_id);
@ -1076,6 +1090,7 @@ CREATE INDEX service_set_var_checksum ON icinga_service_set_var (checksum);
CREATE TABLE icinga_hostgroup (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name character varying(255) NOT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean NOT NULL DEFAULT 'n',
@ -1084,6 +1099,7 @@ CREATE TABLE icinga_hostgroup (
PRIMARY KEY (id)
);
CREATE UNIQUE INDEX hostgroup_uuid ON icinga_hostgroup (uuid);
CREATE UNIQUE INDEX hostgroup_object_name ON icinga_hostgroup (object_name);
CREATE INDEX hostgroup_search_idx ON icinga_hostgroup (display_name);
@ -1113,6 +1129,7 @@ CREATE INDEX hostgroup_inheritance_hostgroup_parent ON icinga_hostgroup_inherita
CREATE TABLE icinga_servicegroup (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean NOT NULL DEFAULT 'n',
@ -1121,6 +1138,7 @@ CREATE TABLE icinga_servicegroup (
PRIMARY KEY (id)
);
CREATE UNIQUE INDEX servicegroup_uuid ON icinga_servicegroup (uuid);
CREATE UNIQUE INDEX servicegroup_object_name ON icinga_servicegroup (object_name);
CREATE INDEX servicegroup_search_idx ON icinga_servicegroup (display_name);
@ -1248,6 +1266,7 @@ CREATE INDEX hostgroup_parent_parent ON icinga_hostgroup_parent (parent_hostgrou
CREATE TABLE icinga_user (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean NOT NULL DEFAULT 'n',
@ -1270,6 +1289,7 @@ CREATE TABLE icinga_user (
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX user_uuid ON icinga_user (uuid);
CREATE UNIQUE INDEX user_object_name ON icinga_user (object_name, zone_id);
CREATE INDEX user_zone ON icinga_user (zone_id);
@ -1373,6 +1393,7 @@ COMMENT ON COLUMN icinga_user_field.user_id IS 'Makes only sense for templates';
CREATE TABLE icinga_usergroup (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name character varying(255) NOT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean NOT NULL DEFAULT 'n',
@ -1386,6 +1407,7 @@ CREATE TABLE icinga_usergroup (
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX usergroup_uuid ON icinga_usergroup (uuid);
CREATE UNIQUE INDEX usergroup_search_idx ON icinga_usergroup (display_name);
CREATE INDEX usergroup_object_name ON icinga_usergroup (object_name);
CREATE INDEX usergroup_zone ON icinga_usergroup (zone_id);
@ -1455,6 +1477,7 @@ CREATE INDEX usergroup_parent_parent ON icinga_usergroup_parent (parent_usergrou
CREATE TABLE icinga_notification (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name CHARACTER VARYING(255) DEFAULT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean NOT NULL DEFAULT 'n',
@ -1496,6 +1519,8 @@ CREATE TABLE icinga_notification (
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX notification_uuid ON icinga_notification (uuid);
CREATE TABLE icinga_notification_user (
notification_id integer NOT NULL,
@ -2004,6 +2029,7 @@ CREATE INDEX user_resolved_var_schecksum ON icinga_user_resolved_var (checksum);
CREATE TABLE icinga_dependency (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name character varying(255) NOT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean DEFAULT 'n',
@ -2053,6 +2079,7 @@ CREATE TABLE icinga_dependency (
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX dependency_uuid ON icinga_dependency (uuid);
CREATE INDEX dependency_parent_host ON icinga_dependency (parent_host_id);
CREATE INDEX dependency_parent_service ON icinga_dependency (parent_service_id);
CREATE INDEX dependency_child_host ON icinga_dependency (child_host_id);
@ -2133,6 +2160,7 @@ CREATE TABLE icinga_timeperiod_exclude (
CREATE TABLE icinga_scheduled_downtime (
id serial,
uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16),
object_name character varying(255) NOT NULL,
zone_id integer DEFAULT NULL,
object_type enum_object_type_all NOT NULL,
@ -2152,6 +2180,7 @@ CREATE TABLE icinga_scheduled_downtime (
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX scheduled_downtime_uuid ON icinga_scheduled_downtime (uuid);
CREATE UNIQUE INDEX scheduled_downtime_object_name ON icinga_scheduled_downtime (object_name);
CREATE INDEX scheduled_downtime_zone ON icinga_scheduled_downtime (zone_id);
@ -2199,6 +2228,515 @@ COMMENT ON COLUMN icinga_scheduled_downtime_range.range_type IS 'include -> rang
COMMENT ON COLUMN icinga_scheduled_downtime_range.merge_behaviour IS 'set -> = {}, add -> += {}, substract -> -= {}';
CREATE TABLE director_branch (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
owner character varying(255) NOT NULL,
branch_name character varying(255) NOT NULL,
description text DEFAULT NULL,
ts_merge_request bigint DEFAULT NULL,
PRIMARY KEY(uuid)
);
CREATE UNIQUE INDEX branch_branch_name ON director_branch (branch_name);
CREATE TYPE enum_branch_action AS ENUM('create', 'modify', 'delete');
CREATE TABLE director_branch_activity (
timestamp_ns bigint NOT NULL,
object_uuid bytea NOT NULL CHECK(LENGTH(object_uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
action enum_branch_action NOT NULL,
object_table character varying(64) NOT NULL,
author character varying(255) NOT NULL,
former_properties text NOT NULL,
modified_properties text NOT NULL,
PRIMARY KEY (timestamp_ns),
CONSTRAINT branch_activity_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE INDEX branch_activity_object_uuid ON director_branch_activity (object_uuid);
CREATE INDEX branch_activity_branch_uuid ON director_branch_activity (branch_uuid);
CREATE TABLE branched_icinga_host (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name CHARACTER VARYING(255) DEFAULT NULL,
address character varying(255) DEFAULT NULL,
address6 character varying(45) DEFAULT NULL,
check_command character varying(255) DEFAULT NULL,
max_check_attempts integer DEFAULT NULL,
check_period character varying(255) DEFAULT NULL,
check_interval character varying(8) DEFAULT NULL,
retry_interval character varying(8) DEFAULT NULL,
check_timeout smallint DEFAULT NULL,
enable_notifications enum_boolean DEFAULT NULL,
enable_active_checks enum_boolean DEFAULT NULL,
enable_passive_checks enum_boolean DEFAULT NULL,
enable_event_handler enum_boolean DEFAULT NULL,
enable_flapping enum_boolean DEFAULT NULL,
enable_perfdata enum_boolean DEFAULT NULL,
event_command character varying(255) DEFAULT NULL,
flapping_threshold_high smallint default null,
flapping_threshold_low smallint default null,
volatile enum_boolean DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
command_endpoint character varying(255) DEFAULT NULL,
notes text DEFAULT NULL,
notes_url character varying(255) DEFAULT NULL,
action_url character varying(255) DEFAULT NULL,
icon_image character varying(255) DEFAULT NULL,
icon_image_alt character varying(255) DEFAULT NULL,
has_agent enum_boolean DEFAULT NULL,
master_should_connect enum_boolean DEFAULT NULL,
accept_config enum_boolean DEFAULT NULL,
api_key character varying(40) DEFAULT NULL,
-- template_choice character varying(255) DEFAULT NULL, -- TODO: Forbid them!
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_host_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX host_branch_object_name ON branched_icinga_host (branch_uuid, object_name);
CREATE INDEX branched_host_search_object_name ON branched_icinga_host (object_name);
CREATE INDEX branched_host_search_display_name ON branched_icinga_host (display_name);
CREATE TABLE branched_icinga_hostgroup (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
assign_filter text DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_hostgroup_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX hostgroup_branch_object_name ON branched_icinga_hostgroup (branch_uuid, object_name);
CREATE INDEX branched_hostgroup_search_object_name ON branched_icinga_hostgroup (object_name);
CREATE INDEX branched_hostgroup_search_display_name ON branched_icinga_hostgroup (display_name);
CREATE TABLE branched_icinga_servicegroup (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
assign_filter text DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_servicegroup_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX servicegroup_branch_object_name ON branched_icinga_servicegroup (branch_uuid, object_name);
CREATE INDEX branched_servicegroup_search_object_name ON branched_icinga_servicegroup (object_name);
CREATE INDEX branched_servicegroup_search_display_name ON branched_icinga_servicegroup (display_name);
CREATE TABLE branched_icinga_usergroup (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
assign_filter text DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_usergroup_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX usergroup_branch_object_name ON branched_icinga_usergroup (branch_uuid, object_name);
CREATE INDEX branched_usergroup_search_object_name ON branched_icinga_usergroup (object_name);
CREATE INDEX branched_usergroup_search_display_name ON branched_icinga_usergroup (display_name);
CREATE TABLE branched_icinga_user (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
email character varying(255) DEFAULT NULL,
pager character varying(255) DEFAULT NULL,
enable_notifications enum_boolean DEFAULT NULL,
period character varying(255) DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_user_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX user_branch_object_name ON branched_icinga_user (branch_uuid, object_name);
CREATE INDEX branched_user_search_object_name ON branched_icinga_user (object_name);
CREATE INDEX branched_user_search_display_name ON branched_icinga_user (display_name);
CREATE TABLE branched_icinga_zone (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
parent character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
is_global enum_boolean DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_zone_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX zone_branch_object_name ON branched_icinga_zone (branch_uuid, object_name);
CREATE INDEX branched_zone_search_object_name ON branched_icinga_zone (object_name);
CREATE TABLE branched_icinga_timeperiod (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
update_method character varying(64) DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
prefer_includes enum_boolean DEFAULT NULL,
imports TEXT DEFAULT NULL,
ranges TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_timeperiod_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX timeperiod_branch_object_name ON branched_icinga_timeperiod (branch_uuid, object_name);
CREATE INDEX branched_timeperiod_search_object_name ON branched_icinga_timeperiod (object_name);
CREATE INDEX branched_timeperiod_search_display_name ON branched_icinga_timeperiod (display_name);
CREATE TABLE branched_icinga_command (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean NOT NULL DEFAULT NULL,
methods_execute character varying(64) DEFAULT NULL,
command text DEFAULT NULL,
is_string enum_boolean DEFAULT NULL,
-- env text DEFAULT NULL,
timeout smallint DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
arguments TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_command_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX command_branch_object_name ON branched_icinga_command (branch_uuid, object_name);
CREATE INDEX branched_command_search_object_name ON branched_icinga_command (object_name);
CREATE TABLE branched_icinga_apiuser (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name CHARACTER VARYING(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean NOT NULL DEFAULT NULL,
password CHARACTER VARYING(255) DEFAULT NULL,
client_dn CHARACTER VARYING(64) DEFAULT NULL,
permissions TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_apiuser_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX apiuser_branch_object_name ON branched_icinga_apiuser (branch_uuid, object_name);
CREATE INDEX branched_apiuser_search_object_name ON branched_icinga_apiuser (object_name);
CREATE TABLE branched_icinga_endpoint (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
zone character varying(255) DEFAULT NULL,
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean NOT NULL DEFAULT NULL,
host character varying(255) DEFAULT NULL,
port d_smallint DEFAULT NULL,
log_duration character varying(32) DEFAULT NULL,
apiuser character varying(255) DEFAULT NULL,
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_endpoint_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX endpoint_branch_object_name ON branched_icinga_endpoint (branch_uuid, object_name);
CREATE INDEX branched_endpoint_search_object_name ON branched_icinga_endpoint (object_name);
CREATE TABLE branched_icinga_service (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
display_name character varying(255) DEFAULT NULL,
host character varying(255) DEFAULT NULL,
service_set character varying(255) DEFAULT NULL,
check_command character varying(255) DEFAULT NULL,
max_check_attempts integer DEFAULT NULL,
check_period character varying(255) DEFAULT NULL,
check_interval character varying(8) DEFAULT NULL,
retry_interval character varying(8) DEFAULT NULL,
check_timeout smallint DEFAULT NULL,
enable_notifications enum_boolean DEFAULT NULL,
enable_active_checks enum_boolean DEFAULT NULL,
enable_passive_checks enum_boolean DEFAULT NULL,
enable_event_handler enum_boolean DEFAULT NULL,
enable_flapping enum_boolean DEFAULT NULL,
enable_perfdata enum_boolean DEFAULT NULL,
event_command character varying(255) DEFAULT NULL,
flapping_threshold_high smallint DEFAULT NULL,
flapping_threshold_low smallint DEFAULT NULL,
volatile enum_boolean DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
command_endpoint character varying(255) DEFAULT NULL,
notes text DEFAULT NULL,
notes_url character varying(255) DEFAULT NULL,
action_url character varying(255) DEFAULT NULL,
icon_image character varying(255) DEFAULT NULL,
icon_image_alt character varying(255) DEFAULT NULL,
use_agent enum_boolean DEFAULT NULL,
apply_for character varying(255) DEFAULT NULL,
use_var_overrides enum_boolean DEFAULT NULL,
assign_filter text DEFAULT NULL,
-- template_choice_id int DEFAULT NULL,
imports TEXT DEFAULT NULL,
groups TEXT DEFAULT NULL,
vars TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_service_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX service_branch_object_name ON branched_icinga_service (branch_uuid, object_name);
CREATE INDEX branched_service_search_object_name ON branched_icinga_service (object_name);
CREATE INDEX branched_service_search_display_name ON branched_icinga_service (display_name);
CREATE TABLE branched_icinga_notification (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name CHARACTER VARYING(255) DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
apply_to enum_host_service DEFAULT NULL,
host character varying(255) DEFAULT NULL,
service character varying(255) DEFAULT NULL,
times_begin integer DEFAULT NULL,
times_end integer DEFAULT NULL,
notification_interval integer DEFAULT NULL,
command character varying(255) DEFAULT NULL,
period character varying(255) DEFAULT NULL,
zone character varying(255) DEFAULT NULL,
assign_filter text DEFAULT NULL,
states TEXT DEFAULT NULL,
types TEXT DEFAULT NULL,
users TEXT DEFAULT NULL,
usergroups TEXT DEFAULT NULL,
imports TEXT DEFAULT NULL,
vars TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_notification_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX notification_branch_object_name ON branched_icinga_notification (branch_uuid, object_name);
CREATE INDEX branched_notification_search_object_name ON branched_icinga_notification (object_name);
CREATE TABLE branched_icinga_scheduled_downtime (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) DEFAULT NULL,
zone_id integer DEFAULT NULL,
object_type enum_object_type_all DEFAULT NULL,
disabled enum_boolean DEFAULT NULL,
apply_to enum_host_service DEFAULT NULL,
assign_filter text DEFAULT NULL,
author character varying(255) DEFAULT NULL,
comment text DEFAULT NULL,
fixed enum_boolean DEFAULT NULL,
duration int DEFAULT NULL,
with_services enum_boolean DEFAULT NULL,
imports TEXT DEFAULT NULL,
ranges TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_scheduled_downtime_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX scheduled_downtime_branch_object_name ON branched_icinga_scheduled_downtime (branch_uuid, object_name);
CREATE INDEX branched_scheduled_downtime_search_object_name ON branched_icinga_scheduled_downtime (object_name);
CREATE TABLE branched_icinga_dependency (
uuid bytea NOT NULL UNIQUE CHECK(LENGTH(uuid) = 16),
branch_uuid bytea NOT NULL CHECK(LENGTH(branch_uuid) = 16),
branch_created enum_boolean NOT NULL DEFAULT 'n',
branch_deleted enum_boolean NOT NULL DEFAULT 'n',
object_name character varying(255) NOT NULL,
object_type enum_object_type_all NOT NULL,
disabled enum_boolean DEFAULT 'n',
apply_to enum_host_service NULL DEFAULT NULL,
parent_host character varying(255) DEFAULT NULL,
parent_host_var character varying(128) DEFAULT NULL,
parent_service character varying(255) DEFAULT NULL,
child_host character varying(255) DEFAULT NULL,
child_service character varying(255) DEFAULT NULL,
disable_checks enum_boolean DEFAULT NULL,
disable_notifications enum_boolean DEFAULT NULL,
ignore_soft_states enum_boolean DEFAULT NULL,
period_id integer DEFAULT NULL,
zone_id integer DEFAULT NULL,
assign_filter text DEFAULT NULL,
parent_service_by_name character varying(255),
imports TEXT DEFAULT NULL,
set_null TEXT DEFAULT NULL,
PRIMARY KEY (branch_uuid, uuid),
CONSTRAINT icinga_dependency_branch
FOREIGN KEY (branch_uuid)
REFERENCES director_branch (uuid)
ON DELETE CASCADE
ON UPDATE CASCADE
);
CREATE UNIQUE INDEX dependency_branch_object_name ON branched_icinga_dependency (branch_uuid, object_name);
CREATE INDEX branched_dependency_search_object_name ON branched_icinga_dependency (object_name);
INSERT INTO director_schema_migration
(schema_version, migration_time)
VALUES (173, NOW());
VALUES (175, NOW());