mirror of
https://github.com/Icinga/icingaweb2-module-director.git
synced 2025-07-31 01:34:12 +02:00
KickstartHelper: handle renamed master
* fix zone cleanup * delete obsolete endpoints * re-structure code * remove obsolete Db helper fixes #842
This commit is contained in:
parent
489d4ab1a3
commit
242bff4011
@ -591,26 +591,6 @@ class Db extends DbConnection
|
|||||||
return $this->enum('icinga_' . $type, null, $filters);
|
return $this->enum('icinga_' . $type, null, $filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function listExternal($type)
|
|
||||||
{
|
|
||||||
$table = IcingaObject::createByType($type)->getTableName();
|
|
||||||
|
|
||||||
$select = $this->db()->select()->from(
|
|
||||||
array('o' => $table),
|
|
||||||
array('object_name' => 'o.object_name')
|
|
||||||
)->where(
|
|
||||||
'object_type = ?',
|
|
||||||
'external_object'
|
|
||||||
)->order('o.object_name');
|
|
||||||
|
|
||||||
$res = $this->db()->fetchCol($select);
|
|
||||||
if (empty($res)) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_combine($res, $res);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fetchDistinctHostVars()
|
public function fetchDistinctHostVars()
|
||||||
{
|
{
|
||||||
$select = $this->db()->select()->distinct()->from(
|
$select = $this->db()->select()->distinct()->from(
|
||||||
|
@ -6,27 +6,38 @@ use Exception;
|
|||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
use Icinga\Exception\ConfigurationError;
|
use Icinga\Exception\ConfigurationError;
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
|
use Icinga\Module\Director\Exception\NestingError;
|
||||||
use Icinga\Module\Director\Objects\IcingaApiUser;
|
use Icinga\Module\Director\Objects\IcingaApiUser;
|
||||||
use Icinga\Module\Director\Objects\IcingaEndpoint;
|
use Icinga\Module\Director\Objects\IcingaEndpoint;
|
||||||
|
use Icinga\Module\Director\Objects\IcingaObject;
|
||||||
use Icinga\Module\Director\Objects\IcingaZone;
|
use Icinga\Module\Director\Objects\IcingaZone;
|
||||||
use Icinga\Module\Director\Core\CoreApi;
|
use Icinga\Module\Director\Core\CoreApi;
|
||||||
use Icinga\Module\Director\Core\RestApiClient;
|
use Icinga\Module\Director\Core\RestApiClient;
|
||||||
use Icinga\Module\Director\Db;
|
|
||||||
|
|
||||||
class KickstartHelper
|
class KickstartHelper
|
||||||
{
|
{
|
||||||
|
/** @var Db */
|
||||||
protected $db;
|
protected $db;
|
||||||
|
|
||||||
|
/** @var CoreApi */
|
||||||
protected $api;
|
protected $api;
|
||||||
|
|
||||||
|
/** @var IcingaApiUser */
|
||||||
protected $apiUser;
|
protected $apiUser;
|
||||||
|
|
||||||
|
/** @var IcingaEndpoint */
|
||||||
protected $deploymentEndpoint;
|
protected $deploymentEndpoint;
|
||||||
|
|
||||||
|
/** @var IcingaEndpoint[] */
|
||||||
protected $loadedEndpoints;
|
protected $loadedEndpoints;
|
||||||
|
|
||||||
|
/** @var IcingaEndpoint[] */
|
||||||
|
protected $removeEndpoints;
|
||||||
|
|
||||||
|
/** @var IcingaZone[] */
|
||||||
protected $loadedZones;
|
protected $loadedZones;
|
||||||
|
|
||||||
|
/** @var IcingaZone[] */
|
||||||
protected $removeZones;
|
protected $removeZones;
|
||||||
|
|
||||||
protected $config = array(
|
protected $config = array(
|
||||||
@ -37,11 +48,35 @@ class KickstartHelper
|
|||||||
'password' => null,
|
'password' => null,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KickstartHelper constructor.
|
||||||
|
* @param Db $db
|
||||||
|
*/
|
||||||
public function __construct(Db $db)
|
public function __construct(Db $db)
|
||||||
{
|
{
|
||||||
$this->db = $db;
|
$this->db = $db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger a complete kickstart run
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$this->fetchEndpoints()
|
||||||
|
->reconnectToDeploymentEndpoint()
|
||||||
|
->fetchZones()
|
||||||
|
->storeZones()
|
||||||
|
->storeEndpoints()
|
||||||
|
->removeEndpoints()
|
||||||
|
->removeZones()
|
||||||
|
->importCommands();
|
||||||
|
|
||||||
|
$this->apiUser()->store();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function isConfigured()
|
public function isConfigured()
|
||||||
{
|
{
|
||||||
$config = $this->fetchConfigFileSection();
|
$config = $this->fetchConfigFileSection();
|
||||||
@ -49,11 +84,17 @@ class KickstartHelper
|
|||||||
&& array_key_exists('username', $config);
|
&& array_key_exists('username', $config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return KickstartHelper
|
||||||
|
*/
|
||||||
public function loadConfigFromFile()
|
public function loadConfigFromFile()
|
||||||
{
|
{
|
||||||
return $this->setConfig($this->fetchConfigFileSection());
|
return $this->setConfig($this->fetchConfigFileSection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
protected function fetchConfigFileSection()
|
protected function fetchConfigFileSection()
|
||||||
{
|
{
|
||||||
return Config::module('director', 'kickstart')
|
return Config::module('director', 'kickstart')
|
||||||
@ -61,6 +102,11 @@ class KickstartHelper
|
|||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $config
|
||||||
|
* @return $this
|
||||||
|
* @throws ProgrammingError
|
||||||
|
*/
|
||||||
public function setConfig($config)
|
public function setConfig($config)
|
||||||
{
|
{
|
||||||
foreach ($config as $key => $value) {
|
foreach ($config as $key => $value) {
|
||||||
@ -81,12 +127,20 @@ class KickstartHelper
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function isRequired()
|
public function isRequired()
|
||||||
{
|
{
|
||||||
$stats = $this->db->getObjectSummary();
|
$stats = $this->db->getObjectSummary();
|
||||||
return (int) $stats['apiuser']->cnt_total === 0;
|
return (int) $stats['apiuser']->cnt_total === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $key
|
||||||
|
* @param mixed $default
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
protected function getValue($key, $default = null)
|
protected function getValue($key, $default = null)
|
||||||
{
|
{
|
||||||
if ($this->config[$key] === null) {
|
if ($this->config[$key] === null) {
|
||||||
@ -96,19 +150,9 @@ class KickstartHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run()
|
/**
|
||||||
{
|
* @return IcingaApiUser
|
||||||
$this->loadEndpoints()
|
*/
|
||||||
->reconnectToDeploymentEndpoint()
|
|
||||||
->loadZones()
|
|
||||||
->storeZones()
|
|
||||||
->storeEndpoints()
|
|
||||||
->removeZones()
|
|
||||||
->importCommands();
|
|
||||||
|
|
||||||
$this->apiUser()->store();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function apiUser()
|
protected function apiUser()
|
||||||
{
|
{
|
||||||
if ($this->apiUser === null) {
|
if ($this->apiUser === null) {
|
||||||
@ -133,64 +177,92 @@ class KickstartHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws ConfigurationError
|
* @param IcingaObject[] $objects
|
||||||
* @return self
|
* @return IcingaObject[]
|
||||||
*/
|
*/
|
||||||
protected function loadZones()
|
protected function sortByInheritance(array $objects)
|
||||||
|
{
|
||||||
|
$sorted = array();
|
||||||
|
|
||||||
|
$cnt = 0;
|
||||||
|
while (! empty($objects)) {
|
||||||
|
$cnt++;
|
||||||
|
if ($cnt > 20) {
|
||||||
|
$this->throwObjectLoop($objects);
|
||||||
|
}
|
||||||
|
$unset = array();
|
||||||
|
foreach ($objects as $key => $object) {
|
||||||
|
foreach ($object->getImports() as $parentName) {
|
||||||
|
if (! array_key_exists($parentName, $sorted)) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sorted[$object->getObjectName()] = $object;
|
||||||
|
$unset[] = $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($unset as $key) {
|
||||||
|
unset($objects[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param IcingaObject[] $objects
|
||||||
|
* @throws NestingError
|
||||||
|
*/
|
||||||
|
protected function throwObjectLoop(array $objects)
|
||||||
|
{
|
||||||
|
$names = array();
|
||||||
|
if (empty($objects)) {
|
||||||
|
$class = 'Nothing';
|
||||||
|
} else {
|
||||||
|
$class = preg_split('/\\\/', get_class(current($objects)));
|
||||||
|
$class = end($class);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$names[] = $object->getObjectName();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NestingError(
|
||||||
|
'Loop detected while resolving %s: %s',
|
||||||
|
$class,
|
||||||
|
implode(', ', $names)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function fetchZones()
|
||||||
{
|
{
|
||||||
$db = $this->db;
|
$db = $this->db;
|
||||||
$imports = array();
|
$this->loadedZones = $this->sortByInheritance(
|
||||||
$objects = array();
|
$this->api()->setDb($db)->getZoneObjects()
|
||||||
$children = array();
|
);
|
||||||
$root = array();
|
|
||||||
|
|
||||||
foreach ($this->api()->setDb($db)->getZoneObjects() as $object) {
|
|
||||||
if ($object->parent) {
|
|
||||||
$children[$object->parent][$object->object_name] = $object;
|
|
||||||
} else {
|
|
||||||
$root[$object->object_name] = $object;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($root as $name => $object) {
|
|
||||||
$objects[$name] = $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
$loop = 0;
|
|
||||||
while (! empty($children)) {
|
|
||||||
$loop++;
|
|
||||||
$unset = array();
|
|
||||||
foreach ($objects as $name => $object) {
|
|
||||||
if (array_key_exists($name, $children)) {
|
|
||||||
foreach ($children[$name] as $object) {
|
|
||||||
$objects[$object->object_name] = $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($children[$name]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($loop > 20) {
|
|
||||||
throw new ConfigurationError('Loop detected while importing zones');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->loadedZones = $objects;
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
protected function storeZones()
|
protected function storeZones()
|
||||||
{
|
{
|
||||||
$db = $this->db;
|
$db = $this->db;
|
||||||
$existing = $db->listExternal('zone');
|
$existing = IcingaObject::loadAllExternalObjectsByType('zone', $db);
|
||||||
|
|
||||||
foreach ($this->loadedZones as $name => $zone) {
|
foreach ($this->loadedZones as $name => $object) {
|
||||||
if ($zone::exists($name, $db)) {
|
if (array_key_exists($name, $existing)) {
|
||||||
$zone = $zone::load($name, $db)->replaceWith($zone);
|
$object = $existing[$name]->replaceWith($object);
|
||||||
|
unset($existing[$name]);
|
||||||
}
|
}
|
||||||
$zone->store();
|
|
||||||
unset($existing[$name]);
|
$object->store();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->removeZones = $existing;
|
$this->removeZones = $existing;
|
||||||
@ -198,45 +270,85 @@ class KickstartHelper
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
protected function removeZones()
|
protected function removeZones()
|
||||||
{
|
{
|
||||||
$db = $this->db;
|
foreach ($this->removeZones as $zone) {
|
||||||
|
$zone->delete();
|
||||||
foreach ($this->removeZones as $name) {
|
|
||||||
IcingaZone::load($name, $db)->delete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function loadEndpoints()
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function fetchEndpoints()
|
||||||
{
|
{
|
||||||
$db = $this->db;
|
$db = $this->db;
|
||||||
$master = $this->getValue('endpoint');
|
$this->loadedEndpoints = $this->sortByInheritance(
|
||||||
|
$this->api()->setDb($db)->getEndpointObjects()
|
||||||
|
);
|
||||||
|
|
||||||
$endpoints = array();
|
$master = $this->getValue('endpoint');
|
||||||
foreach ($this->api()->setDb($db)->getEndpointObjects() as $object) {
|
if (array_key_exists($master, $this->loadedEndpoints)) {
|
||||||
if ($object->object_name === $master) {
|
$apiuser = $this->apiUser();
|
||||||
$apiuser = $this->apiUser();
|
$apiuser->store();
|
||||||
$apiuser->store();
|
$object = $this->loadedEndpoints[$master];
|
||||||
$object->apiuser = $apiuser->object_name;
|
$object->apiuser = $apiuser->object_name;
|
||||||
$this->deploymentEndpoint = $object;
|
$this->deploymentEndpoint = $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function storeEndpoints()
|
||||||
|
{
|
||||||
|
$db = $this->db;
|
||||||
|
$existing = IcingaObject::loadAllExternalObjectsByType('endpoint', $db);
|
||||||
|
|
||||||
|
foreach ($this->loadedEndpoints as $name => $object) {
|
||||||
|
if (array_key_exists($name, $existing)) {
|
||||||
|
$object = $existing[$name]->replaceWith($object);
|
||||||
|
unset($existing[$name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$endpoints[$object->object_name] = $object;
|
$object->store();
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->loadedEndpoints = $endpoints;
|
$this->removeEndpoints = $existing;
|
||||||
|
|
||||||
|
$db->settings()->master_zone = $this->deploymentEndpoint->zone;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
protected function removeEndpoints()
|
||||||
|
{
|
||||||
|
foreach ($this->removeEndpoints as $endpoint) {
|
||||||
|
$endpoint->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return $this
|
||||||
|
* @throws ConfigurationError
|
||||||
|
*/
|
||||||
protected function reconnectToDeploymentEndpoint()
|
protected function reconnectToDeploymentEndpoint()
|
||||||
{
|
{
|
||||||
$db = $this->db;
|
|
||||||
$master = $this->getValue('endpoint');
|
$master = $this->getValue('endpoint');
|
||||||
|
|
||||||
if (!$this->deploymentEndpoint) {
|
if (! $this->deploymentEndpoint) {
|
||||||
throw new ConfigurationError(
|
throw new ConfigurationError(
|
||||||
'I found no Endpoint object called "%s" on %s:%d',
|
'I found no Endpoint object called "%s" on %s:%d',
|
||||||
$master,
|
$master,
|
||||||
@ -248,8 +360,8 @@ class KickstartHelper
|
|||||||
$ep = $this->deploymentEndpoint;
|
$ep = $this->deploymentEndpoint;
|
||||||
|
|
||||||
$epHost = $ep->get('host');
|
$epHost = $ep->get('host');
|
||||||
if (!$epHost) {
|
if (! $epHost) {
|
||||||
$epHost = $ep->object_name;
|
$epHost = $ep->getObjectName();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -271,26 +383,18 @@ class KickstartHelper
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function storeEndpoints()
|
/**
|
||||||
{
|
* Import existing commands as external objects
|
||||||
$db = $this->db;
|
*
|
||||||
|
* TODO: remove outdated ones
|
||||||
foreach ($this->loadedEndpoints as $name => $object) {
|
*
|
||||||
if ($object::exists($object->object_name, $db)) {
|
* @return $this
|
||||||
$object = $object::load($object->object_name, $db)->replaceWith($object);
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
$object->store();
|
|
||||||
}
|
|
||||||
|
|
||||||
$db->settings()->master_zone = $this->deploymentEndpoint->zone;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function importCommands()
|
protected function importCommands()
|
||||||
{
|
{
|
||||||
$db = $this->db;
|
$db = $this->db;
|
||||||
|
$zdb = $db->getDbAdapter();
|
||||||
|
$zdb->beginTransaction();
|
||||||
foreach ($this->api()->setDb($db)->getCheckCommandObjects() as $object) {
|
foreach ($this->api()->setDb($db)->getCheckCommandObjects() as $object) {
|
||||||
if ($object::exists($object->object_name, $db)) {
|
if ($object::exists($object->object_name, $db)) {
|
||||||
$new = $object::load($object->object_name, $db)->replaceWith($object);
|
$new = $object::load($object->object_name, $db)->replaceWith($object);
|
||||||
@ -310,30 +414,40 @@ class KickstartHelper
|
|||||||
|
|
||||||
$new->store();
|
$new->store();
|
||||||
}
|
}
|
||||||
|
$zdb->commit();
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setDb($db)
|
/**
|
||||||
|
* @param Db $db
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setDb(Db $db)
|
||||||
{
|
{
|
||||||
$this->db = $db;
|
$this->db = $db;
|
||||||
if ($this->object !== null) {
|
|
||||||
$this->object->setConnection($db);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
protected function getHost()
|
protected function getHost()
|
||||||
{
|
{
|
||||||
return $this->getValue('host', $this->getValue('endpoint'));
|
return $this->getValue('host', $this->getValue('endpoint'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
protected function getPort()
|
protected function getPort()
|
||||||
{
|
{
|
||||||
return (int) $this->getValue('port', 5665);
|
return (int) $this->getValue('port', 5665);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CoreApi
|
||||||
|
*/
|
||||||
protected function getDeploymentApi()
|
protected function getDeploymentApi()
|
||||||
{
|
{
|
||||||
unset($this->api);
|
unset($this->api);
|
||||||
@ -356,6 +470,9 @@ class KickstartHelper
|
|||||||
return $api;
|
return $api;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CoreApi
|
||||||
|
*/
|
||||||
protected function getConfiguredApi()
|
protected function getConfiguredApi()
|
||||||
{
|
{
|
||||||
unset($this->api);
|
unset($this->api);
|
||||||
@ -371,11 +488,17 @@ class KickstartHelper
|
|||||||
return $api;
|
return $api;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CoreApi
|
||||||
|
*/
|
||||||
protected function switchToDeploymentApi()
|
protected function switchToDeploymentApi()
|
||||||
{
|
{
|
||||||
return $this->api = $this->getDeploymentApi();
|
return $this->api = $this->getDeploymentApi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CoreApi
|
||||||
|
*/
|
||||||
protected function api()
|
protected function api()
|
||||||
{
|
{
|
||||||
if ($this->api === null) {
|
if ($this->api === null) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user