diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:43:12 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:43:12 +0000 |
commit | cd989f9c3aff968e19a3aeabc4eb9085787a6673 (patch) | |
tree | fbff2135e7013f196b891bbde54618eb050e4aaf /application/clicommands | |
parent | Initial commit. (diff) | |
download | icingaweb2-module-director-cd989f9c3aff968e19a3aeabc4eb9085787a6673.tar.xz icingaweb2-module-director-cd989f9c3aff968e19a3aeabc4eb9085787a6673.zip |
Adding upstream version 1.10.2.upstream/1.10.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
31 files changed, 1818 insertions, 0 deletions
diff --git a/application/clicommands/BasketCommand.php b/application/clicommands/BasketCommand.php new file mode 100644 index 0000000..dd2434f --- /dev/null +++ b/application/clicommands/BasketCommand.php @@ -0,0 +1,127 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Date\DateFormatter; +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\Core\Json; +use Icinga\Module\Director\DirectorObject\Automation\Basket; +use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshot; +use Icinga\Module\Director\DirectorObject\ObjectPurgeHelper; + +/** + * Export Director Config Objects + */ +class BasketCommand extends Command +{ + /** + * List configured Baskets + * + * USAGE + * + * icingacli director basket list + * + * OPTIONS + */ + public function listAction() + { + $db = $this->db()->getDbAdapter(); + $query = $db->select() + ->from('director_basket', 'basket_name') + ->order('basket_name'); + foreach ($db->fetchCol($query) as $name) { + echo "$name\n"; + } + } + + /** + * JSON-dump for objects related to the given Basket + * + * USAGE + * + * icingacli director basket dump --name <basket> + * + * OPTIONS + */ + public function dumpAction() + { + $basket = $this->requireBasket(); + $snapshot = BasketSnapshot::createForBasket($basket, $this->db()); + echo $snapshot->getJsonDump() . "\n"; + } + + /** + * Take a snapshot for the given Basket + * + * USAGE + * + * icingacli director basket snapshot --name <basket> + * + * OPTIONS + */ + public function snapshotAction() + { + $basket = $this->requireBasket(); + $snapshot = BasketSnapshot::createForBasket($basket, $this->db()); + $snapshot->store(); + $hexSum = bin2hex($snapshot->get('content_checksum')); + printf( + "Snapshot '%s' taken for Basket '%s' at %s\n", + substr($hexSum, 0, 7), + $basket->get('basket_name'), + DateFormatter::formatDateTime($snapshot->get('ts_create') / 1000) + ); + } + + /** + * Restore a Basket from JSON dump provided on STDIN + * + * USAGE + * + * icingacli director basket restore < basket-dump.json + * + * OPTIONS + * --purge <ObjectType>[,<ObjectType] Purge objects of the + * Given types. WARNING: this removes ALL objects that are + * not shipped with the given basket + * --force Purge refuses to purge Objects in case there are + * no Objects of a given ObjectType in the provided basket + * unless forced to do so + */ + public function restoreAction() + { + if ($purge = $this->params->get('purge')) { + $purge = explode(',', $purge); + ObjectPurgeHelper::assertObjectTypesAreEligibleForPurge($purge); + } + $json = file_get_contents('php://stdin'); + BasketSnapshot::restoreJson($json, $this->db()); + if ($purge) { + $this->purgeObjectTypes(Json::decode($json), $purge, $this->params->get('force')); + } + echo "Objects from Basket Snapshot have been restored\n"; + } + + protected function purgeObjectTypes($objects, array $types, $force = false) + { + $helper = new ObjectPurgeHelper($this->db()); + if ($force) { + $helper->force(); + } + foreach ($types as $type) { + list($className, $typeFilter) = BasketSnapshot::getClassAndObjectTypeForType($type); + $helper->purge( + isset($objects->$type) ? (array) $objects->$type : [], + $className, + $typeFilter + ); + } + } + + /** + */ + protected function requireBasket() + { + return Basket::load($this->params->getRequired('name'), $this->db()); + } +} diff --git a/application/clicommands/BenchmarkCommand.php b/application/clicommands/BenchmarkCommand.php new file mode 100644 index 0000000..6ccd8c8 --- /dev/null +++ b/application/clicommands/BenchmarkCommand.php @@ -0,0 +1,152 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Application\Benchmark; +use Icinga\Data\Filter\Filter; +use Icinga\Data\Filter\FilterChain; +use Icinga\Data\Filter\FilterExpression; +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\CustomVariable\CustomVariable; +use Icinga\Module\Director\Data\Db\IcingaObjectFilterRenderer; +use Icinga\Module\Director\Data\Db\IcingaObjectQuery; +use Icinga\Module\Director\Objects\HostGroupMembershipResolver; +use Icinga\Module\Director\Objects\IcingaHost; +use Icinga\Module\Director\Objects\IcingaHostVar; +use Icinga\Module\Director\Objects\IcingaVar; + +class BenchmarkCommand extends Command +{ + public function testflatfilterAction() + { + $q = new IcingaObjectQuery('host', $this->db()); + $filter = Filter::fromQueryString( + // 'host.vars.snmp_community="*ub*"&(host.vars.location="London"|host.vars.location="Berlin")' + // 'host.vars.snmp_community="*ub*"&(host.vars.location="FRA DC"|host.vars.location="NBG DC")' + 'host.vars.priority="*igh"&(host.vars.location="FRA DC"|host.vars.location="NBG DC")' + ); + IcingaObjectFilterRenderer::apply($filter, $q); + echo $q->getSql() . "\n"; + + print_r($q->listNames()); + } + + public function rerendervarsAction() + { + $conn = $this->db(); + $db = $conn->getDbAdapter(); + $db->beginTransaction(); + $query = $db->select()->from( + array('v' => 'icinga_var'), + array( + 'v.varname', + 'v.varvalue', + 'v.checksum', + 'v.rendered_checksum', + 'v.rendered', + 'format' => "('json')", + ) + ); + Benchmark::measure('Ready to fetch all vars'); + $rows = $db->fetchAll($query); + Benchmark::measure('Got vars, storing flat'); + foreach ($rows as $row) { + $var = CustomVariable::fromDbRow($row); + $rendered = $var->render(); + $checksum = sha1($rendered, true); + if ($checksum === $row->rendered_checksum) { + continue; + } + + $where = $db->quoteInto('checksum = ?', $row->checksum); + $db->update( + 'icinga_var', + array( + 'rendered' => $rendered, + 'rendered_checksum' => $checksum + ), + $where + ); + } + + $db->commit(); + } + + public function flattenvarsAction() + { + $conn = $this->db(); + $db = $conn->getDbAdapter(); + $db->beginTransaction(); + $query = $db->select()->from(['v' => 'icinga_host_var'], [ + 'v.host_id', + 'v.varname', + 'v.varvalue', + 'v.format', + 'v.checksum' + ]); + Benchmark::measure('Ready to fetch all vars'); + $rows = $db->fetchAll($query); + Benchmark::measure('Got vars, storing flat'); + + foreach ($rows as $row) { + $var = CustomVariable::fromDbRow($row); + $checksum = $var->checksum(); + if (! IcingaVar::exists($checksum, $conn)) { + IcingaVar::generateForCustomVar($var, $conn); + } + + if ($row->checksum === null) { + $where = $db->quoteInto('host_id = ?', $row->host_id) + . $db->quoteInto(' AND varname = ?', $row->varname); + $db->update('icinga_host_var', ['checksum' => $checksum], $where); + } + } + + $db->commit(); + } + + public function resolvehostgroupsAction() + { + $resolver = new HostGroupMembershipResolver($this->db()); + $resolver->refreshDb(); + } + + public function filterAction() + { + $flat = []; + + /** @var FilterChain|FilterExpression $filter */ + $filter = Filter::fromQueryString( + // 'object_name=*ic*2*&object_type=object' + 'vars.bpconfig=*' + ); + Benchmark::measure('ready'); + $objs = IcingaHost::loadAll($this->db()); + Benchmark::measure('db done'); + + foreach ($objs as $host) { + $flat[$host->get('id')] = (object) []; + foreach ($host->getProperties() as $k => $v) { + $flat[$host->get('id')]->$k = $v; + } + } + Benchmark::measure('objects ready'); + + $vars = IcingaHostVar::loadAll($this->db()); + Benchmark::measure('vars loaded'); + foreach ($vars as $var) { + if (! array_key_exists($var->get('host_id'), $flat)) { + // Templates? + continue; + } + $flat[$var->get('host_id')]->{'vars.' . $var->get('varname')} = $var->get('varvalue'); + } + Benchmark::measure('vars done'); + + foreach ($flat as $host) { + if ($filter->matches($host)) { + echo $host->object_name . "\n"; + } + } + } +} diff --git a/application/clicommands/CommandCommand.php b/application/clicommands/CommandCommand.php new file mode 100644 index 0000000..5c96442 --- /dev/null +++ b/application/clicommands/CommandCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Commands + * + * Use this command to show, create, modify or delete Icinga Command + * objects + */ +class CommandCommand extends ObjectCommand +{ +} diff --git a/application/clicommands/CommandsCommand.php b/application/clicommands/CommandsCommand.php new file mode 100644 index 0000000..9a74337 --- /dev/null +++ b/application/clicommands/CommandsCommand.php @@ -0,0 +1,14 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectsCommand; + +/** + * List Icinga Commands + * + * Use this command to list Icinga Command objects + */ +class CommandsCommand extends ObjectsCommand +{ +} diff --git a/application/clicommands/ConfigCommand.php b/application/clicommands/ConfigCommand.php new file mode 100644 index 0000000..e313aa4 --- /dev/null +++ b/application/clicommands/ConfigCommand.php @@ -0,0 +1,178 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Application\Benchmark; +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\Core\Json; +use Icinga\Module\Director\Deployment\ConditionalDeployment; +use Icinga\Module\Director\Deployment\DeploymentGracePeriod; +use Icinga\Module\Director\Deployment\DeploymentStatus; +use Icinga\Module\Director\IcingaConfig\IcingaConfig; +use Icinga\Module\Director\Import\SyncUtils; + +/** + * Generate, show and deploy Icinga 2 configuration + */ +class ConfigCommand extends Command +{ + /** + * Re-render the current configuration + */ + public function renderAction() + { + $profile = $this->params->shift('profile'); + if ($profile) { + $this->enableDbProfiler(); + } + + $config = new IcingaConfig($this->db()); + Benchmark::measure('Rendering config'); + if ($config->hasBeenModified()) { + Benchmark::measure('Config rendered, storing to db'); + $config->store(); + Benchmark::measure('All done'); + $checksum = $config->getHexChecksum(); + printf( + "New config with checksum %s has been generated\n", + $checksum + ); + } else { + $checksum = $config->getHexChecksum(); + printf( + "Config with checksum %s already exists\n", + $checksum + ); + } + + if ($profile) { + $this->dumpDbProfile(); + } + } + + protected function dumpDbProfile() + { + $profiler = $this->getDbProfiler(); + + $totalTime = $profiler->getTotalElapsedSecs(); + $queryCount = $profiler->getTotalNumQueries(); + $longestTime = 0; + $longestQuery = null; + + /** @var \Zend_Db_Profiler_Query $query */ + foreach ($profiler->getQueryProfiles() as $query) { + echo $query->getQuery() . "\n"; + if ($query->getElapsedSecs() > $longestTime) { + $longestTime = $query->getElapsedSecs(); + $longestQuery = $query->getQuery(); + } + } + + echo 'Executed ' . $queryCount . ' queries in ' . $totalTime . ' seconds' . "\n"; + echo 'Average query length: ' . $totalTime / $queryCount . ' seconds' . "\n"; + echo 'Queries per second: ' . $queryCount / $totalTime . "\n"; + echo 'Longest query length: ' . $longestTime . "\n"; + echo "Longest query: \n" . $longestQuery . "\n"; + } + + protected function getDbProfiler() + { + return $this->db()->getDbAdapter()->getProfiler(); + } + + protected function enableDbProfiler() + { + return $this->getDbProfiler()->setEnabled(true); + } + + /** + * Deploy the current configuration + * + * USAGE + * + * icingacli director config deploy [--checksum <checksum>] [--force] [--wait <seconds>] + * [--grace-period <seconds>] + * + * OPTIONS + * + * --checksum <checksum> Optionally deploy a specific configuration + * --force Force a deployment, even when the configuration + * hasn't changed + * --wait <seconds> Optionally wait until Icinga completed it's + * restart + * --grace-period <seconds> Do not deploy if a deployment took place + * less than <seconds> ago + */ + public function deployAction() + { + $db = $this->db(); + + $checksum = $this->params->get('checksum'); + if ($checksum) { + $config = IcingaConfig::load(hex2bin($checksum), $db); + } else { + $config = IcingaConfig::generate($db); + $checksum = $config->getHexChecksum(); + } + + $deployer = new ConditionalDeployment($db, $this->api()); + $deployer->force((bool) $this->params->get('force')); + if ($graceTime = $this->params->get('grace-period')) { + $deployer->setGracePeriod(new DeploymentGracePeriod((int) $graceTime, $db)); + if ($this->params->get('force')) { + fwrite(STDERR, "WARNING: force overrides Grace period\n"); + } + } + $deployer->refresh(); + + if ($deployment = $deployer->deploy($config)) { + if ($deployer->hasBeenForced()) { + echo $deployer->getNoDeploymentReason() . ", deploying anyway\n"; + } + printf("Config '%s' has been deployed\n", $checksum); + } else { + echo $deployer->getNoDeploymentReason() . "\n"; + return; + } + + if ($timeout = $this->getWaitTime()) { + $deployed = $deployer->waitForStartupAfterDeploy($deployment, $timeout); + if ($deployed !== true) { + $this->fail("Waiting for Icinga restart failed '%s': %s\n", $checksum, $deployed); + } + } + } + + /** + * Checks the deployments status + */ + public function deploymentstatusAction() + { + $db = $this->db(); + $api = $this->api(); + $status = new DeploymentStatus($db, $api); + $result = $status->getDeploymentStatus($this->params->get('configs'), $this->params->get('activities')); + if ($key = $this->params->get('key')) { + $result = SyncUtils::getSpecificValue($result, $key); + } + + if (is_string($result)) { + echo "$result\n"; + } else { + echo Json::encode($result, JSON_PRETTY_PRINT) . "\n"; + } + } + + protected function getWaitTime() + { + if ($timeout = $this->params->get('wait')) { + if (!ctype_digit($timeout)) { + $this->fail("--wait must be the number of seconds to wait'"); + } + + return (int) $timeout; + } + + return null; + } +} diff --git a/application/clicommands/CoreCommand.php b/application/clicommands/CoreCommand.php new file mode 100644 index 0000000..4927aa5 --- /dev/null +++ b/application/clicommands/CoreCommand.php @@ -0,0 +1,16 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\PlainObjectRenderer; + +class CoreCommand extends Command +{ + public function constantsAction() + { + foreach ($this->api()->getConstants() as $name => $value) { + printf("const %s = %s\n", $name, PlainObjectRenderer::render($value)); + } + } +} diff --git a/application/clicommands/DaemonCommand.php b/application/clicommands/DaemonCommand.php new file mode 100644 index 0000000..e89e1da --- /dev/null +++ b/application/clicommands/DaemonCommand.php @@ -0,0 +1,26 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\Daemon\BackgroundDaemon; + +class DaemonCommand extends Command +{ + /** + * Run the main Director daemon + * + * USAGE + * + * icingacli director daemon run [--db-resource <name>] + */ + public function runAction() + { + $this->app->getModuleManager()->loadEnabledModules(); + $daemon = new BackgroundDaemon(); + if ($dbResource = $this->params->get('db-resource')) { + $daemon->setDbResourceName($dbResource); + } + $daemon->run(); + } +} diff --git a/application/clicommands/DependencyCommand.php b/application/clicommands/DependencyCommand.php new file mode 100644 index 0000000..ff5cbdc --- /dev/null +++ b/application/clicommands/DependencyCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Dependencies + * + * Use this command to show, create, modify or delete Icinga Dependency + * objects + */ +class DependencyCommand extends ObjectCommand +{ +} diff --git a/application/clicommands/EndpointCommand.php b/application/clicommands/EndpointCommand.php new file mode 100644 index 0000000..f61f4fc --- /dev/null +++ b/application/clicommands/EndpointCommand.php @@ -0,0 +1,19 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Endpoints + * + * Use this command to show, create, modify or delete Icinga Endpoint + * objects + */ +class EndpointCommand extends ObjectCommand +{ + public function statusAction() + { + print_r($this->api()->getStatus()); + } +} diff --git a/application/clicommands/ExportCommand.php b/application/clicommands/ExportCommand.php new file mode 100644 index 0000000..2b2119d --- /dev/null +++ b/application/clicommands/ExportCommand.php @@ -0,0 +1,180 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\DirectorObject\Automation\ImportExport; + +/** + * Export Director Config Objects + */ +class ExportCommand extends Command +{ + /** + * Export all ImportSource definitions + * + * USAGE + * + * icingacli director export importsources [options] + * + * OPTIONS + * + * --no-pretty JSON is pretty-printed per default + * Use this flag to enforce unformatted JSON + */ + public function importsourcesAction() + { + $export = new ImportExport($this->db()); + echo $this->renderJson( + $export->serializeAllImportSources(), + !$this->params->shift('no-pretty') + ); + } + + /** + * Export all SyncRule definitions + * + * USAGE + * + * icingacli director export syncrules [options] + * + * OPTIONS + * + * --no-pretty JSON is pretty-printed per default + * Use this flag to enforce unformatted JSON + */ + public function syncrulesAction() + { + $export = new ImportExport($this->db()); + echo $this->renderJson( + $export->serializeAllSyncRules(), + !$this->params->shift('no-pretty') + ); + } + + /** + * Export all Job definitions + * + * USAGE + * + * icingacli director export jobs [options] + * + * OPTIONS + * + * --no-pretty JSON is pretty-printed per default + * Use this flag to enforce unformatted JSON + */ + public function jobsAction() + { + $export = new ImportExport($this->db()); + echo $this->renderJson( + $export->serializeAllJobs(), + !$this->params->shift('no-pretty') + ); + } + + /** + * Export all DataField definitions + * + * USAGE + * + * icingacli director export datafields [options] + * + * OPTIONS + * + * --no-pretty JSON is pretty-printed per default + * Use this flag to enforce unformatted JSON + */ + public function datafieldsAction() + { + $export = new ImportExport($this->db()); + echo $this->renderJson( + $export->serializeAllDataFields(), + !$this->params->shift('no-pretty') + ); + } + + /** + * Export all DataList definitions + * + * USAGE + * + * icingacli director export datalists [options] + * + * OPTIONS + * + * --no-pretty JSON is pretty-printed per default + * Use this flag to enforce unformatted JSON + */ + public function datalistsAction() + { + $export = new ImportExport($this->db()); + echo $this->renderJson( + $export->serializeAllDataLists(), + !$this->params->shift('no-pretty') + ); + } + + // /** + // * Export all IcingaHostGroup definitions + // * + // * USAGE + // * + // * icingacli director export hostgroup [options] + // * + // * OPTIONS + // * + // * --no-pretty JSON is pretty-printed per default + // * Use this flag to enforce unformatted JSON + // */ + // public function hostgroupAction() + // { + // $export = new ImportExport($this->db()); + // echo $this->renderJson( + // $export->serializeAllHostGroups(), + // !$this->params->shift('no-pretty') + // ); + // } + // + // /** + // * Export all IcingaServiceGroup definitions + // * + // * USAGE + // * + // * icingacli director export servicegroup [options] + // * + // * OPTIONS + // * + // * --no-pretty JSON is pretty-printed per default + // * Use this flag to enforce unformatted JSON + // */ + // public function servicegroupAction() + // { + // $export = new ImportExport($this->db()); + // echo $this->renderJson( + // $export->serializeAllServiceGroups(), + // !$this->params->shift('no-pretty') + // ); + // } + + /** + * Export all IcingaTemplateChoiceHost definitions + * + * USAGE + * + * icingacli director export hosttemplatechoices [options] + * + * OPTIONS + * + * --no-pretty JSON is pretty-printed per default + * Use this flag to enforce unformatted JSON + */ + public function hosttemplatechoicesAction() + { + $export = new ImportExport($this->db()); + echo $this->renderJson( + $export->serializeAllHostTemplateChoices(), + !$this->params->shift('no-pretty') + ); + } +} diff --git a/application/clicommands/HealthCommand.php b/application/clicommands/HealthCommand.php new file mode 100644 index 0000000..1635c50 --- /dev/null +++ b/application/clicommands/HealthCommand.php @@ -0,0 +1,80 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\CheckPlugin\PluginState; +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\Health; +use Icinga\Module\Director\Cli\PluginOutputBeautifier; + +/** + * Check Icinga Director Health + * + * Use this command as a CheckPlugin to monitor your Icinga Director health + */ +class HealthCommand extends Command +{ + /** + * Run health checks + * + * Use this command to run all or a specific set of Health Checks. + * + * USAGE + * + * icingacli director health check [options] + * + * OPTIONS + * + * --check <name> Run only a specific set of checks + * valid names: config, sync, import, jobs, deployment + * --db <name> Use a specific Icinga Web DB resource + * --watch <seconds> Refresh every <second>. For interactive use only + */ + public function checkAction() + { + $health = new Health(); + if ($name = $this->params->get('db')) { + $health->setDbResourceName($name); + } + + if ($name = $this->params->get('check')) { + $check = $health->getCheck($name); + echo PluginOutputBeautifier::beautify($check->getOutput(), $this->screen); + + exit($check->getState()->getNumeric()); + } else { + $state = new PluginState('OK'); + $checks = $health->getAllChecks(); + + $output = []; + foreach ($checks as $check) { + $state->raise($check->getState()); + $output[] = $check->getOutput(); + } + + if ($state->getNumeric() === 0) { + echo "Icinga Director: everything is fine\n\n"; + } else { + echo "Icinga Director: there are problems\n\n"; + } + + $out = PluginOutputBeautifier::beautify(implode("\n", $output), $this->screen); + echo $out; + + if (! $this->isBeingWatched()) { + exit($state->getNumeric()); + } + } + } + + /** + * Cli should provide this information, as it shifts the parameter + * + * @return bool + */ + protected function isBeingWatched() + { + global $argv; + return in_array('--watch', $argv); + } +} diff --git a/application/clicommands/HostCommand.php b/application/clicommands/HostCommand.php new file mode 100644 index 0000000..21ec5eb --- /dev/null +++ b/application/clicommands/HostCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Hosts + * + * Use this command to show, create, modify or delete Icinga Host + * objects + */ +class HostCommand extends ObjectCommand +{ +} diff --git a/application/clicommands/HostgroupCommand.php b/application/clicommands/HostgroupCommand.php new file mode 100644 index 0000000..88b17d9 --- /dev/null +++ b/application/clicommands/HostgroupCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Hostgroups + * + * Use this command to show, create, modify or delete Icinga Hostgroups + * objects + */ +class HostGroupCommand extends ObjectCommand +{ +} diff --git a/application/clicommands/HostgroupsCommand.php b/application/clicommands/HostgroupsCommand.php new file mode 100644 index 0000000..1007a05 --- /dev/null +++ b/application/clicommands/HostgroupsCommand.php @@ -0,0 +1,14 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectsCommand; + +/** + * Manage Icinga Hostgroups + * + * Use this command to list Icinga Hostgroup objects + */ +class HostgroupsCommand extends ObjectsCommand +{ +} diff --git a/application/clicommands/HostsCommand.php b/application/clicommands/HostsCommand.php new file mode 100644 index 0000000..3008284 --- /dev/null +++ b/application/clicommands/HostsCommand.php @@ -0,0 +1,14 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectsCommand; + +/** + * Manage Icinga Hosts + * + * Use this command to list Icinga Host objects + */ +class HostsCommand extends ObjectsCommand +{ +} diff --git a/application/clicommands/HousekeepingCommand.php b/application/clicommands/HousekeepingCommand.php new file mode 100644 index 0000000..974e28d --- /dev/null +++ b/application/clicommands/HousekeepingCommand.php @@ -0,0 +1,74 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Exception\MissingParameterException; +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\Db\Housekeeping; +use Icinga\Module\Director\Db\MembershipHousekeeping; + +class HousekeepingCommand extends Command +{ + protected $housekeeping; + + public function tasksAction() + { + if ($pending = $this->params->shift('pending')) { + $tasks = $this->housekeeping()->getPendingTaskSummary(); + } else { + $tasks = $this->housekeeping()->getTaskSummary(); + } + + $len = array_reduce( + $tasks, + function ($max, $task) { + return max( + $max, + strlen($task->title) + strlen($task->name) + 3 + ); + } + ); + + if (count($tasks)) { + print "\n"; + printf(" %-" . $len . "s | %s\n", 'Housekeeping task (name)', 'Count'); + printf("-%-" . $len . "s-|-------\n", str_repeat('-', $len)); + } + + foreach ($tasks as $task) { + printf( + " %-" . $len . "s | %5d\n", + sprintf('%s (%s)', $task->title, $task->name), + $task->count + ); + } + + if (count($tasks)) { + print "\n"; + } + } + + public function runAction() + { + if (!$job = $this->params->shift()) { + throw new MissingParameterException( + 'Job is required, say ALL to run all pending jobs' + ); + } + + if ($job === 'ALL') { + $this->housekeeping()->runAllTasks(); + } else { + $this->housekeeping()->runTask($job); + } + } + + protected function housekeeping() + { + if ($this->housekeeping === null) { + $this->housekeeping = new Housekeeping($this->db()); + } + + return $this->housekeeping; + } +} diff --git a/application/clicommands/ImportCommand.php b/application/clicommands/ImportCommand.php new file mode 100644 index 0000000..3edfff2 --- /dev/null +++ b/application/clicommands/ImportCommand.php @@ -0,0 +1,62 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\DirectorObject\Automation\ImportExport; +use Icinga\Module\Director\Objects\ImportSource; + +/** + * Export Director Config Objects + */ +class ImportCommand extends Command +{ + /** + * Import ImportSource definitions + * + * USAGE + * + * icingacli director import importsources < importsources.json + * + * OPTIONS + */ + public function importsourcesAction() + { + $json = file_get_contents('php://stdin'); + $import = new ImportExport($this->db()); + $count = $import->unserializeImportSources(json_decode($json)); + echo "$count Import Sources have been imported\n"; + } + + // /** + // * Import an ImportSource definition + // * + // * USAGE + // * + // * icingacli director import importsource < importsource.json + // * + // * OPTIONS + // */ + // public function importsourcection() + // { + // $json = file_get_contents('php://stdin'); + // $object = ImportSource::import(json_decode($json), $this->db()); + // $object->store(); + // printf("Import Source '%s' has been imported\n", $object->getObjectName()); + // } + + /** + * Import SyncRule definitions + * + * USAGE + * + * icingacli director import syncrules < syncrules.json + */ + public function syncrulesAction() + { + $json = file_get_contents('php://stdin'); + $import = new ImportExport($this->db()); + $count = $import->unserializeSyncRules(json_decode($json)); + echo "$count Sync Rules have been imported\n"; + } +} diff --git a/application/clicommands/ImportsourceCommand.php b/application/clicommands/ImportsourceCommand.php new file mode 100644 index 0000000..477fdf5 --- /dev/null +++ b/application/clicommands/ImportsourceCommand.php @@ -0,0 +1,168 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Application\Benchmark; +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\Core\Json; +use Icinga\Module\Director\Hook\ImportSourceHook; +use Icinga\Module\Director\Objects\ImportSource; + +/** + * Deal with Director Import Sources + * + * Use this command to check or trigger your defined Import Sources + */ +class ImportsourceCommand extends Command +{ + /** + * List defined Import Sources + * + * This shows a table with your defined Import Sources, their IDs and + * current state. As triggering Imports requires an ID, this is where + * you can look up the desired ID. + * + * USAGE + * + * icingacli director importsource list + */ + public function listAction() + { + $sources = ImportSource::loadAll($this->db()); + if (empty($sources)) { + echo "No Import Source has been defined\n"; + + return; + } + + printf("%4s | %s\n", 'ID', 'Import Source name'); + printf("-----+%s\n", str_repeat('-', 64)); + + foreach ($sources as $source) { + $state = $source->get('import_state'); + printf("%4d | %s\n", $source->get('id'), $source->get('source_name')); + printf(" | -> %s%s\n", $state, $state === 'failing' ? ': ' . $source->get('last_error_message') : ''); + } + } + + /** + * Check a given Import Source for changes + * + * This command fetches data from the given Import Source and compares it + * to the most recently imported data. + * + * USAGE + * + * icingacli director importsource check --id <id> + * + * OPTIONS + * + * --id <id> An Import Source ID. Use the list command to figure out + * --benchmark Show timing and memory usage details + */ + public function checkAction() + { + $source = $this->getImportSource(); + $source->checkForChanges(); + $this->showImportStateDetails($source); + } + + /** + * Fetch current data from a given Import Source + * + * This command fetches data from the given Import Source and outputs + * them as plain JSON + * + * USAGE + * + * icingacli director importsource fetch --id <id> + * + * OPTIONS + * + * --id <id> An Import Source ID. Use the list command to figure out + * --benchmark Show timing and memory usage details + */ + public function fetchAction() + { + $source = $this->getImportSource(); + $source->checkForChanges(); + $hook = ImportSourceHook::forImportSource($source); + Benchmark::measure('Ready to fetch data'); + $data = $hook->fetchData(); + $source->applyModifiers($data); + Benchmark::measure(sprintf('Got %d rows, ready to dump JSON', count($data))); + echo Json::encode($data, JSON_PRETTY_PRINT); + } + + /** + * Trigger an Import Run for a given Import Source + * + * This command fetches data from the given Import Source and stores it to + * the Director DB, so that the next related Sync Rule run can work with + * fresh data. In case data didn't change, nothing is going to be stored. + * + * USAGE + * + * icingacli director importsource run --id <id> + * + * OPTIONS + * + * --id <id> An Import Source ID. Use the list command to figure out + * --benchmark Show timing and memory usage details + */ + public function runAction() + { + $source = $this->getImportSource(); + + if ($source->runImport()) { + print "New data has been imported\n"; + $this->showImportStateDetails($source); + } else { + print "Nothing has been changed, imported data is still up to date\n"; + } + } + + /** + * @return ImportSource + */ + protected function getImportSource() + { + return ImportSource::loadWithAutoIncId( + (int) $this->params->getRequired('id'), + $this->db() + ); + } + + /** + * @param ImportSource $source + * @throws \Icinga\Exception\IcingaException + */ + protected function showImportStateDetails(ImportSource $source) + { + echo $this->getImportStateDescription($source) . "\n"; + } + + /** + * @param ImportSource $source + * @return string + * @throws \Icinga\Exception\IcingaException + */ + protected function getImportStateDescription(ImportSource $source) + { + switch ($source->get('import_state')) { + case 'unknown': + return "It's currently unknown whether we are in sync with this" + . ' Import Source. You should either check for changes or' + . ' trigger a new Import Run.'; + case 'in-sync': + return 'This Import Source is in sync'; + case 'pending-changes': + return 'There are pending changes for this Import Source. You' + . ' should trigger a new Import Run.'; + case 'failing': + return 'This Import Source failed: ' . $source->get('last_error_message'); + default: + return 'This Import Source has an invalid state: ' . $source->get('import_state'); + } + } +} diff --git a/application/clicommands/JobsCommand.php b/application/clicommands/JobsCommand.php new file mode 100644 index 0000000..1c6297f --- /dev/null +++ b/application/clicommands/JobsCommand.php @@ -0,0 +1,74 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Exception; +use gipfl\Cli\Process; +use gipfl\Protocol\JsonRpc\Connection; +use gipfl\Protocol\NetString\StreamWrapper; +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\Daemon\JsonRpcLogWriter as JsonRpcLogWriterAlias; +use Icinga\Module\Director\Daemon\Logger; +use Icinga\Module\Director\Objects\DirectorJob; +use React\EventLoop\Factory as Loop; +use React\EventLoop\LoopInterface; +use React\Stream\ReadableResourceStream; +use React\Stream\WritableResourceStream; + +class JobsCommand extends Command +{ + public function runAction() + { + $this->app->getModuleManager()->loadEnabledModules(); + $loop = Loop::create(); + if ($this->params->get('rpc')) { + $this->enableRpc($loop); + } + if ($this->params->get('rpc') && $jobId = $this->params->get('id')) { + $exitCode = 1; + $jobId = (int) $jobId; + $loop->futureTick(function () use ($jobId, $loop, &$exitCode) { + Process::setTitle('icinga::director::job'); + try { + $this->raiseLimits(); + $job = DirectorJob::loadWithAutoIncId($jobId, $this->db()); + Process::setTitle('icinga::director::job (' . $job->get('job_name') . ')'); + if ($job->run()) { + $exitCode = 0; + } else { + $exitCode = 1; + } + } catch (Exception $e) { + Logger::error($e->getMessage()); + $exitCode = 1; + } + $loop->futureTick(function () use ($loop) { + $loop->stop(); + }); + }); + } else { + Logger::error('This command is no longer available. Please check our Upgrading documentation'); + $exitCode = 1; + } + + $loop->run(); + exit($exitCode); + } + + protected function enableRpc(LoopInterface $loop) + { + // stream_set_blocking(STDIN, 0); + // stream_set_blocking(STDOUT, 0); + // print_r(stream_get_meta_data(STDIN)); + // stream_set_write_buffer(STDOUT, 0); + // ini_set('implicit_flush', 1); + $netString = new StreamWrapper( + new ReadableResourceStream(STDIN, $loop), + new WritableResourceStream(STDOUT, $loop) + ); + $jsonRpc = new Connection(); + $jsonRpc->handle($netString); + + Logger::replaceRunningInstance(new JsonRpcLogWriterAlias($jsonRpc)); + } +} diff --git a/application/clicommands/KickstartCommand.php b/application/clicommands/KickstartCommand.php new file mode 100644 index 0000000..80aa183 --- /dev/null +++ b/application/clicommands/KickstartCommand.php @@ -0,0 +1,88 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\KickstartHelper; + +/** + * Kickstart a Director installation + * + * Once you prepared your DB resource this command retrieves information about + * unapplied database migration and helps applying them. + */ +class KickstartCommand extends Command +{ + /** + * Check whether a kickstart run is required + * + * This is the case when there is a kickstart.ini in your Directors config + * directory and no ApiUser in your Director DB. + * + * This is mostly for automation, so one could create a Puppet manifest + * as follows: + * + * exec { 'Icinga Director Kickstart': + * path => '/usr/local/bin:/usr/bin:/bin', + * command => 'icingacli director kickstart run', + * onlyif => 'icingacli director kickstart required', + * require => Exec['Icinga Director DB migration'], + * } + * + * Exit code 0 means that a kickstart run is required, code 2 that it is + * not. + */ + public function requiredAction() + { + if ($this->kickstart()->isConfigured()) { + if ($this->kickstart()->isRequired()) { + if ($this->isVerbose) { + echo "Kickstart has been configured and should be triggered\n"; + } + + exit(0); + } else { + echo "Kickstart configured, execution is not required\n"; + exit(1); + } + } else { + echo "Kickstart has not been configured\n"; + exit(2); + } + } + + /** + * Trigger the kickstart helper + * + * This will connect to the endpoint configured in your kickstart.ini, + * store the given API user and import existing objects like zones, + * endpoints and commands. + * + * /etc/icingaweb2/modules/director/kickstart.ini could look as follows: + * + * [config] + * endpoint = "master-node.example.com" + * + * ; Host can be an IP address or a hostname. Equals to endpoint name + * ; if not set: + * host = "127.0.0.1" + * + * ; Port is 5665 if none given + * port = 5665 + * + * username = "director" + * password = "***" + * + */ + public function runAction() + { + $this->raiseLimits(); + $this->kickstart()->loadConfigFromFile()->run(); + exit(0); + } + + protected function kickstart() + { + return new KickstartHelper($this->db()); + } +} diff --git a/application/clicommands/MigrationCommand.php b/application/clicommands/MigrationCommand.php new file mode 100644 index 0000000..6a4d002 --- /dev/null +++ b/application/clicommands/MigrationCommand.php @@ -0,0 +1,66 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\Db\Migrations; + +/** + * Handle DB migrations + * + * This command retrieves information about unapplied database migration and + * helps applying them. + */ +class MigrationCommand extends Command +{ + /** + * Check whether there are pending migrations + * + * This is mostly for automation, so one could create a Puppet manifest + * as follows: + * + * exec { 'Icinga Director DB migration': + * command => 'icingacli director migration run', + * onlyif => 'icingacli director migration pending', + * } + * + * Exit code 0 means that there are pending migrations, code 1 that there + * are no such. Use --verbose for human readable output + */ + public function pendingAction() + { + if ($count = $this->migrations()->countPendingMigrations()) { + if ($this->isVerbose) { + if ($count === 1) { + echo "There is 1 pending migration\n"; + } else { + printf("There are %d pending migrations\n", $count); + } + } + + exit(0); + } else { + if ($this->isVerbose) { + echo "There are no pending migrations\n"; + } + + exit(1); + } + } + + /** + * Run any pending migrations + * + * All pending migrations will be silently applied + */ + public function runAction() + { + $this->migrations()->applyPendingMigrations(); + exit(0); + } + + protected function migrations() + { + return new Migrations($this->db()); + } +} diff --git a/application/clicommands/NotificationCommand.php b/application/clicommands/NotificationCommand.php new file mode 100644 index 0000000..bb5402a --- /dev/null +++ b/application/clicommands/NotificationCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Notifications + * + * Use this command to show, create, modify or delete Icinga Notification + * objects + */ +class NotificationCommand extends ObjectCommand +{ +} diff --git a/application/clicommands/ServiceCommand.php b/application/clicommands/ServiceCommand.php new file mode 100644 index 0000000..1bd21e7 --- /dev/null +++ b/application/clicommands/ServiceCommand.php @@ -0,0 +1,92 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Cli\Params; +use Icinga\Module\Director\Cli\ObjectCommand; +use Icinga\Module\Director\DirectorObject\Lookup\ServiceFinder; +use Icinga\Module\Director\Objects\IcingaHost; +use Icinga\Module\Director\Resolver\OverrideHelper; +use InvalidArgumentException; + +/** + * Manage Icinga Services + * + * Use this command to show, create, modify or delete Icinga Service + * objects + */ +class ServiceCommand extends ObjectCommand +{ + public function setAction() + { + if (($host = $this->params->get('host')) && $this->params->shift('allow-overrides')) { + if ($this->setServiceProperties($host)) { + return; + } + } + + parent::setAction(); + } + + protected function setServiceProperties($hostname) + { + $serviceName = $this->getName(); + $host = IcingaHost::load($hostname, $this->db()); + $service = ServiceFinder::find($host, $serviceName); + if ($service->requiresOverrides()) { + self::checkForOverrideSafety($this->params); + $properties = $this->remainingParams(); + unset($properties['host']); + OverrideHelper::applyOverriddenVars($host, $serviceName, $properties); + $this->persistChanges($host, 'Host', $hostname . " (Overrides for $serviceName)", 'modified'); + return true; + } + + return false; + } + + protected static function checkForOverrideSafety(Params $params) + { + if ($params->shift('replace')) { + throw new InvalidArgumentException('--replace is not available for Variable Overrides'); + } + $appends = self::stripPrefixedProperties($params, 'append-'); + $remove = self::stripPrefixedProperties($params, 'remove-'); + OverrideHelper::assertVarsForOverrides($appends); + OverrideHelper::assertVarsForOverrides($remove); + if (!empty($appends)) { + throw new InvalidArgumentException('--append- is not available for Variable Overrides'); + } + if (!empty($remove)) { + throw new InvalidArgumentException('--remove- is not available for Variable Overrides'); + } + // Alternative, untested: + // $this->appendToArrayProperties($object, $appends); + // $this->removeProperties($object, $remove); + } + + protected function load($name) + { + return parent::load($this->makeServiceKey($name)); + } + + protected function exists($name) + { + return parent::exists($this->makeServiceKey($name)); + } + + protected function makeServiceKey($name) + { + if ($host = $this->params->get('host')) { + return [ + 'object_name' => $name, + 'host_id' => IcingaHost::load($host, $this->db())->get('id'), + ]; + } else { + return [ + 'object_name' => $name, + 'object_type' => 'template', + ]; + } + } +} diff --git a/application/clicommands/ServicegroupCommand.php b/application/clicommands/ServicegroupCommand.php new file mode 100644 index 0000000..1c732d4 --- /dev/null +++ b/application/clicommands/ServicegroupCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Servicegroups + * + * Use this command to show, create, modify or delete Icinga Servicegroups + * objects + */ +class ServiceGroupCommand extends ObjectCommand +{ +} diff --git a/application/clicommands/ServicesetCommand.php b/application/clicommands/ServicesetCommand.php new file mode 100644 index 0000000..648a42c --- /dev/null +++ b/application/clicommands/ServicesetCommand.php @@ -0,0 +1,14 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +/** + * Manage Icinga Service Sets + * + * Use this command to show, create, modify or delete Icinga Service + * objects + */ +class ServicesetCommand extends ServiceCommand +{ + protected $type = 'ServiceSet'; +} diff --git a/application/clicommands/ServicesetsCommand.php b/application/clicommands/ServicesetsCommand.php new file mode 100644 index 0000000..54669d5 --- /dev/null +++ b/application/clicommands/ServicesetsCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectsCommand; + +/** + * Manage Icinga Service Sets + * + * Use this command to list Icinga Service Set objects + */ +class ServicesetsCommand extends ObjectsCommand +{ + protected $type = 'ServiceSet'; +} diff --git a/application/clicommands/SyncruleCommand.php b/application/clicommands/SyncruleCommand.php new file mode 100644 index 0000000..37a3f0e --- /dev/null +++ b/application/clicommands/SyncruleCommand.php @@ -0,0 +1,195 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\Command; +use Icinga\Module\Director\Objects\DirectorActivityLog; +use Icinga\Module\Director\Objects\IcingaObject; +use Icinga\Module\Director\Objects\SyncRule; +use RuntimeException; + +/** + * Deal with Director Sync Rules + * + * Use this command to check or trigger your defined Sync Rules + */ +class SyncruleCommand extends Command +{ + /** + * List defined Sync Rules + * + * This shows a table with your defined Sync Rules, their IDs and + * current state. As triggering a Sync requires an ID, this is where + * you can look up the desired ID. + * + * USAGE + * + * icingacli director syncrule list + */ + public function listAction() + { + $rules = SyncRule::loadAll($this->db()); + if (empty($rules)) { + echo "No Sync Rule has been defined\n"; + + return; + } + + printf("%4s | %s\n", 'ID', 'Sync Rule name'); + printf("-----+%s\n", str_repeat('-', 64)); + + foreach ($rules as $rule) { + $state = $rule->get('sync_state'); + printf("%4d | %s\n", $rule->get('id'), $rule->get('rule_name')); + printf(" | -> %s%s\n", $state, $state === 'failing' ? ': ' . $rule->get('last_error_message') : ''); + } + } + + /** + * Check a given Sync Rule for changes + * + * This command runs a complete Sync in memory but doesn't persist eventual changes. + * + * USAGE + * + * icingacli director syncrule check --id <id> + * + * OPTIONS + * + * --id <id> A Sync Rule ID. Use the list command to figure out + * --benchmark Show timing and memory usage details + */ + public function checkAction() + { + $rule = $this->getSyncRule(); + $hasChanges = $rule->checkForChanges(); + $this->showSyncStateDetails($rule); + if ($hasChanges) { + $mods = $this->getExpectedModificationCounts($rule); + printf( + "Expected modifications: %dx create, %dx modify, %dx delete\n", + $mods->modify, + $mods->create, + $mods->delete + ); + } + + exit($this->getSyncStateExitCode($rule)); + } + + protected function getExpectedModificationCounts(SyncRule $rule) + { + $modifications = $rule->getExpectedModifications(); + + $create = 0; + $modify = 0; + $delete = 0; + + /** @var IcingaObject $object */ + foreach ($modifications as $object) { + if ($object->hasBeenLoadedFromDb()) { + if ($object->shouldBeRemoved()) { + $delete++; + } else { + $modify++; + } + } else { + $create++; + } + } + + return (object) [ + DirectorActivityLog::ACTION_CREATE => $create, + DirectorActivityLog::ACTION_MODIFY => $modify, + DirectorActivityLog::ACTION_DELETE => $delete, + ]; + } + + /** + * Trigger a Sync Run for a given Sync Rule + * + * This command builds new objects according your Sync Rule, compares them + * with existing ones and persists eventual changes. + * + * USAGE + * + * icingacli director syncrule run --id <id> + * + * OPTIONS + * + * --id <id> A Sync Rule ID. Use the list command to figure out + * --benchmark Show timing and memory usage details + */ + public function runAction() + { + $rule = $this->getSyncRule(); + + if ($rule->applyChanges()) { + print "New data has been imported\n"; + $this->showSyncStateDetails($rule); + } else { + print "Nothing has been changed, imported data is still up to date\n"; + } + } + + /** + * @return SyncRule + */ + protected function getSyncRule() + { + return SyncRule::loadWithAutoIncId( + (int) $this->params->getRequired('id'), + $this->db() + ); + } + + /** + * @param SyncRule $rule + */ + protected function showSyncStateDetails(SyncRule $rule) + { + echo $this->getSyncStateDescription($rule) . "\n"; + } + + /** + * @param SyncRule $rule + * @return string + */ + protected function getSyncStateDescription(SyncRule $rule) + { + switch ($rule->get('sync_state')) { + case 'unknown': + return "It's currently unknown whether we are in sync with this rule." + . ' You should either check for changes or trigger a new Sync Run.'; + case 'in-sync': + return 'This Sync Rule is in sync'; + case 'pending-changes': + return 'There are pending changes for this Sync Rule. You should' + . ' trigger a new Sync Run.'; + case 'failing': + return 'This Sync Rule failed: '. $rule->get('last_error_message'); + default: + throw new RuntimeException('Invalid sync state: ' . $rule->get('sync_state')); + } + } + + /** + * @param SyncRule $rule + * @return string + */ + protected function getSyncStateExitCode(SyncRule $rule) + { + switch ($rule->get('sync_state')) { + case 'unknown': + return 3; + case 'in-sync': + return 0; + case 'pending-changes': + return 1; + case 'failing': + return 2; + default: + throw new RuntimeException('Invalid sync state: ' . $rule->get('sync_state')); + } + } +} diff --git a/application/clicommands/TimeperiodCommand.php b/application/clicommands/TimeperiodCommand.php new file mode 100644 index 0000000..352289a --- /dev/null +++ b/application/clicommands/TimeperiodCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Timeperiods + * + * Use this command to show, create, modify or delete Icinga Timeperiod + * objects + */ +class TimePeriodCommand extends ObjectCommand +{ +} diff --git a/application/clicommands/UserCommand.php b/application/clicommands/UserCommand.php new file mode 100644 index 0000000..9c4c9d4 --- /dev/null +++ b/application/clicommands/UserCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Users + * + * Use this command to show, create, modify or delete Icinga User + * objects + */ +class UserCommand extends ObjectCommand +{ +} diff --git a/application/clicommands/UsergroupCommand.php b/application/clicommands/UsergroupCommand.php new file mode 100644 index 0000000..04ba7c3 --- /dev/null +++ b/application/clicommands/UsergroupCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Usergroups + * + * Use this command to show, create, modify or delete Icinga Usergroup + * objects + */ +class UsergroupCommand extends ObjectCommand +{ +} diff --git a/application/clicommands/ZoneCommand.php b/application/clicommands/ZoneCommand.php new file mode 100644 index 0000000..a5c45f9 --- /dev/null +++ b/application/clicommands/ZoneCommand.php @@ -0,0 +1,15 @@ +<?php + +namespace Icinga\Module\Director\Clicommands; + +use Icinga\Module\Director\Cli\ObjectCommand; + +/** + * Manage Icinga Zones + * + * Use this command to show, create, modify or delete Icinga Zone + * objects + */ +class ZoneCommand extends ObjectCommand +{ +} |