diff --git a/application/forms/IcingaHostForm.php b/application/forms/IcingaHostForm.php index 05042360..706a7362 100644 --- a/application/forms/IcingaHostForm.php +++ b/application/forms/IcingaHostForm.php @@ -90,6 +90,11 @@ class IcingaHostForm extends DirectorObjectForm 'description' => $this->translate('One or more comma separated hostgroup names') )); + $this->addElement('text', 'imports', array( + 'label' => $this->translate('Imports'), + 'description' => $this->translate('The inherited host template names') + )); + $this->addElement('select', 'zone_id', array( 'label' => $this->translate('Cluster Zone'), 'description' => $this->translate('Check this host in this specific Icinga cluster zone') diff --git a/library/Director/Objects/IcingaHost.php b/library/Director/Objects/IcingaHost.php index 6235199c..feae5587 100644 --- a/library/Director/Objects/IcingaHost.php +++ b/library/Director/Objects/IcingaHost.php @@ -39,6 +39,8 @@ class IcingaHost extends IcingaObject protected $supportsGroups = true; + protected $supportsImports = true; + protected function renderCheck_command_id() { return $this->renderCommandProperty($this->check_command_id); diff --git a/library/Director/Objects/IcingaObject.php b/library/Director/Objects/IcingaObject.php index ccd3042b..13f6195b 100644 --- a/library/Director/Objects/IcingaObject.php +++ b/library/Director/Objects/IcingaObject.php @@ -19,12 +19,16 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer protected $supportsGroups = false; + protected $supportsImports = false; + private $type; private $vars; private $groups; + private $imports; + public function supportsCustomVars() { return $this->supportsCustomVars; @@ -35,6 +39,11 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this->supportsGroups; } + public function supportsImports() + { + return $this->supportsImports; + } + public function hasBeenModified() { if ($this->supportsCustomVars() && $this->vars !== null && $this->vars()->hasBeenModified()) { @@ -45,6 +54,10 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return true; } + if ($this->supportsImports() && $this->imports !== null && $this->imports()->hasBeenModified()) { + return true; + } + return parent::hasBeenModified(); } @@ -62,6 +75,20 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this->groups; } + public function imports() + { + $this->assertImportsSupport(); + if ($this->imports === null) { + if ($this->hasBeenLoadedFromDb()) { + $this->imports = IcingaObjectImports::loadForStoredObject($this); + } else { + $this->imports = new IcingaObjectImports($this); + } + } + + return $this->imports; + } + protected function assertCustomVarsSupport() { if (! $this->supportsCustomVars()) { @@ -86,6 +113,18 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this; } + protected function assertImportsSupport() + { + if (! $this->supportsImports()) { + throw new ProgrammingError( + 'Objects of type "%s" have no imports', + $this->getType() + ); + } + + return $this; + } + public function vars() { $this->assertCustomVarsSupport(); @@ -166,7 +205,11 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer protected function renderImports() { // TODO: parent_host ORDERed by weigth... - return ''; + if ($this->supportsImports()) { + return $this->imports()->toConfigString(); + } else { + return ''; + } } protected function renderProperties() diff --git a/library/Director/Objects/IcingaObjectImports.php b/library/Director/Objects/IcingaObjectImports.php new file mode 100644 index 00000000..43bc8c86 --- /dev/null +++ b/library/Director/Objects/IcingaObjectImports.php @@ -0,0 +1,298 @@ +object = $object; + } + + public function count() + { + return count($this->imports); + } + + public function rewind() + { + $this->position = 0; + } + + public function hasBeenModified() + { + return $this->modified; + } + + public function current() + { + if (! $this->valid()) { + return null; + } + + return $this->imports[$this->idx[$this->position]]; + } + + public function key() + { + return $this->idx[$this->position]; + } + + public function next() + { + ++$this->position; + } + + public function valid() + { + return array_key_exists($this->position, $this->idx); + } + + public function get($key) + { + if (array_key_exists($key, $this->imports)) { + return $this->imports[$key]; + } + + return null; + } + + public function set($import) + { + $existing = array_keys($this->imports); + $new = array(); + $class = $this->getImportClass(); + foreach ($import as $i) { + + if ($i instanceof $class) { + $new[] = $i->object_name; + } else { + $new[] = $i; + } + } + sort($existing); + sort($new); + if ($existing === $new) { + return $this; + } + + $this->imports = array(); + return $this->add($import); + } + + /** + * Magic isset check + * + * @return boolean + */ + public function __isset($import) + { + return array_key_exists($import, $this->imports); + } + + public function remove($import) + { + if (array_key_exists($import, $this->imports)) { + unset($this->imports[$import]); + } + + $this->modified = true; + $this->refreshIndex(); + } + + protected function refreshIndex() + { + ksort($this->imports); + $this->idx = array_keys($this->imports); + } + + public function add($import) + { + // TODO: only one query when adding array + if (is_array($import)) { + foreach ($import as $i) { + $this->add($i); + } + return $this; + } + + if (array_key_exists($import, $this->imports)) { + return $this; + } + + $class = $this->getImportClass(); + $connection = $this->object->getConnection(); + + if ($import instanceof $class) { + $this->imports[$import->object_name] = $import; + } elseif (is_string($import)) { + $query = $this->object->getDb()->select()->from( + $this->object->getTableName() + )->where('object_name = ?', $import); + $imports = $class::loadAll($connection, $query, 'object_name'); + } + if (! array_key_exists($import, $imports)) { + throw new ProgrammingError( + 'The import "%s" doesn\'t exists.', + $import + ); + } + + var_dump($imports);die; + $this->imports[$import] = $imports[$import]; + + $this->modified = true; + $this->refreshIndex(); + + return $this; + } + + protected function getImportTableName() + { + return $this->object->getTableName() . '_inheritance'; + } + + public function listImportNames() + { + return array_keys($this->imports); + } + + public function getType() + { + return $this->object->getShortTableName(); + } + + protected function loadFromDb() + { + $db = $this->object->getDb(); + $connection = $this->object->getConnection(); + + $type = $this->getType(); + + $table = $this->object->getTableName(); + $query = $db->select()->from( + array('o' => $table), + array() + )->join( + array('oi' => $table . '_inheritance'), + 'oi.' . $type . '_id = o.id', + array() + )->join( + array('i' => $table), + 'i.id = oi.parent_' . $type . '_id', + '*' + )->where('o.id = ?', (int) $this->object->id) + ->order('oi.weight'); + + $class = $this->getImportClass(); + $this->imports = $class::loadAll($connection, $query, 'object_name'); + $this->storedImports = $this->imports; + + return $this; + } + + /** + * Modification TODO + * + * @return $this + */ + public function store() + { + $storedGroups = array_keys($this->storedGroups); + $groups = array_keys($this->groups); + + $objectId = $this->object->id; + $type = $this->getType(); + + $objectCol = $type . '_id'; + $groupCol = $type . 'group_id'; + + $toDelete = array_diff($storedGroups, $groups); + foreach ($toDelete as $group) { + $where = sprintf( + $objectCol . ' = %d AND ' . $groupCol . ' = %d', + $objectId, + $this->storedGroups[$group]->id + ); + + $this->object->db->delete( + $this->getGroupMemberTableName(), + $where + ); + } + + $toAdd = array_diff($groups, $storedGroups); + foreach ($toAdd as $group) { + $this->object->db->insert( + $this->getGroupMemberTableName(), + array( + $objectCol => $objectId, + $groupCol => $this->groups[$group]->id + ) + ); + } + $this->storedGroups = $this->groups; + + return $this; + } + + protected function getImportClass() + { + return get_class($this->object); + } + + public static function loadForStoredObject(IcingaObject $object) + { + $imports = new static($object); + return $imports->loadFromDb(); + } + + public function toConfigString() + { + $ret = ''; + + foreach ($this->imports as $name => & $o) { + $ret .= ' import ' . c::renderString($o->object_name) . "\n"; + } + + if ($ret !== '') { + $ret .= "\n"; + } + return $ret; + } + + public function __toString() + { + try { + return $this->toConfigString(); + } catch (Exception $e) { + trigger_error($e); + $previousHandler = set_exception_handler(function () {}); + restore_error_handler(); + if ($previousHandler !== null) { + call_user_func($previousHandler, $e); + die(); + } else { + die($e->getMessage()); + } + } + } +} diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php index e38efac9..d82b61ea 100644 --- a/library/Director/Web/Form/DirectorObjectForm.php +++ b/library/Director/Web/Form/DirectorObjectForm.php @@ -48,7 +48,6 @@ abstract class DirectorObjectForm extends QuickForm $handled = array(); if ($object->supportsGroups()) { - if (array_key_exists('groups', $values)) { $object->groups()->set( preg_split('/\s*,\s*/', $values['groups'], -1, PREG_SPLIT_NO_EMPTY) @@ -57,6 +56,15 @@ abstract class DirectorObjectForm extends QuickForm } } + if ($object->supportsImports()) { + if (array_key_exists('imports', $values)) { + $object->imports()->set( + preg_split('/\s*,\s*/', $values['imports'], -1, PREG_SPLIT_NO_EMPTY) + ); + $handled['imports'] = true; + } + } + if ($this->object->supportsCustomVars()) { $vars = array(); $newvar = array( @@ -181,6 +189,12 @@ abstract class DirectorObjectForm extends QuickForm ); } + if ($this->object->supportsImports()) { + $this->getElement('imports')->setValue( + implode(', ', $this->object->imports()->listImportNames()) + ); + } + if ($this->object->supportsCustomVars()) { foreach ($this->object->vars() as $key => $value) { $this->addCustomVar($key, $value);