CLI interface: initial import
This commit is contained in:
parent
d1e61a1826
commit
a25cd80ec0
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Clicommands;
|
||||||
|
|
||||||
|
use Icinga\Cli\Command;
|
||||||
|
use Icinga\Cli\Documentation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Help for modules, commands and actions
|
||||||
|
*
|
||||||
|
* The help command shows help for a given command, module and also for a
|
||||||
|
* given module's command or a specific command's action.
|
||||||
|
*
|
||||||
|
* Usage: icingaweb help [<module>] [<command> [<action>]]
|
||||||
|
*/
|
||||||
|
class HelpCommand extends Command
|
||||||
|
{
|
||||||
|
protected $defaultActionName = 'show';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show help for modules, commands and actions [default]
|
||||||
|
*
|
||||||
|
* The help command shows help for a given command, module and also for a
|
||||||
|
* given module's command or a specific command's action.
|
||||||
|
*
|
||||||
|
* Usage: icingaweb help [<module>] [<command> [<action>]]
|
||||||
|
*/
|
||||||
|
public function showAction()
|
||||||
|
{
|
||||||
|
$module = null;
|
||||||
|
$command = null;
|
||||||
|
$action = null;
|
||||||
|
$loader = $this->app->cliLoader();
|
||||||
|
$command = $this->params->shift();
|
||||||
|
|
||||||
|
if ($loader->hasCommand($command)) {
|
||||||
|
$action = $this->params->shift();
|
||||||
|
if (! $loader->getCommandInstance($command)->hasActionName($action)) {
|
||||||
|
$action = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($loader->hasModule($command)) {
|
||||||
|
$module = $command;
|
||||||
|
$command = $this->params->shift();
|
||||||
|
if ($loader->hasModuleCommand($module, $command)) {
|
||||||
|
$action = $this->params->shift();
|
||||||
|
$mod = $loader->getModuleCommandInstance($module, $command);
|
||||||
|
if (! $mod->hasActionName($action)) {
|
||||||
|
$action = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$command = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$command = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo $this->docs()->usage($module, $command, $action);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,165 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Clicommands;
|
||||||
|
|
||||||
|
use Icinga\Cli\Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List and handle modules
|
||||||
|
*
|
||||||
|
* The module command allows you to handle your IcingaWeb modules
|
||||||
|
*
|
||||||
|
* Usage: icingaweb module [<action>] [<modulename>]
|
||||||
|
*/
|
||||||
|
class ModuleCommand extends Command
|
||||||
|
{
|
||||||
|
protected $modules;
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->modules = $this->app->getModuleManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all enabled modules
|
||||||
|
*
|
||||||
|
* If you are interested in all installed modules pass 'installed' (or
|
||||||
|
* even --installed) as a command parameter. If you enable --verbose even
|
||||||
|
* more details will be shown
|
||||||
|
*
|
||||||
|
* Usage: icingaweb module list [installed] [--verbose]
|
||||||
|
*/
|
||||||
|
public function listAction()
|
||||||
|
{
|
||||||
|
if ($type = $this->params->shift()) {
|
||||||
|
if (! in_array($type, array('enabled', 'installed'))) {
|
||||||
|
return $this->showUsage();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$type = 'enabled';
|
||||||
|
$this->params->shift('enabled');
|
||||||
|
if ($this->params->shift('installed')) {
|
||||||
|
$type = 'installed';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->hasRemainingParams()) {
|
||||||
|
return $this->showUsage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type === 'enabled') {
|
||||||
|
$modules = $this->modules->listEnabledModules();
|
||||||
|
} else {
|
||||||
|
$modules = $this->modules->listInstalledModules();
|
||||||
|
}
|
||||||
|
if (empty($modules)) {
|
||||||
|
echo "There are no modules installed\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($this->isVerbose) {
|
||||||
|
printf("%-14s %-9s DIRECTORY\n", 'MODULE', 'STATE');
|
||||||
|
} else {
|
||||||
|
printf("%-14s %-9s\n", 'MODULE', 'STATE');
|
||||||
|
}
|
||||||
|
foreach ($modules as $module) {
|
||||||
|
if ($this->isVerbose) {
|
||||||
|
$dir = ' ' . $this->modules->getModuleDir($module);
|
||||||
|
} else {
|
||||||
|
$dir = '';
|
||||||
|
}
|
||||||
|
printf(
|
||||||
|
"%-14s %-9s%s\n",
|
||||||
|
$module,
|
||||||
|
($type === 'enabled' || $this->modules->hasEnabled($module))
|
||||||
|
? 'enabled'
|
||||||
|
: 'disabled',
|
||||||
|
$dir
|
||||||
|
);
|
||||||
|
}
|
||||||
|
echo "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable a given module
|
||||||
|
*
|
||||||
|
* Usage: icingaweb module enable <module-name>
|
||||||
|
*/
|
||||||
|
public function enableAction()
|
||||||
|
{
|
||||||
|
if (! $module = $this->params->shift()) {
|
||||||
|
$module = $this->params->shift('module');
|
||||||
|
}
|
||||||
|
if (! $module || $this->hasRemainingParams()) {
|
||||||
|
return $this->showUsage();
|
||||||
|
}
|
||||||
|
$this->modules->enableModule($module);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable a given module
|
||||||
|
*
|
||||||
|
* Usage: icingaweb module disable <module-name>
|
||||||
|
*/
|
||||||
|
public function disableAction()
|
||||||
|
{
|
||||||
|
if (! $module = $this->params->shift()) {
|
||||||
|
$module = $this->params->shift('module');
|
||||||
|
}
|
||||||
|
if (! $module || $this->hasRemainingParams()) {
|
||||||
|
return $this->showUsage();
|
||||||
|
}
|
||||||
|
$this->modules->disableModule($module);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for a given module
|
||||||
|
*
|
||||||
|
* Does a lookup against your configured IcingaWeb app stores and tries to
|
||||||
|
* find modules matching your search string
|
||||||
|
*
|
||||||
|
* Usage: icingaweb module search <search-string>
|
||||||
|
*/
|
||||||
|
public function searchAction()
|
||||||
|
{
|
||||||
|
$this->fail("Not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install a given module
|
||||||
|
*
|
||||||
|
* Downloads a given module or installes a module from a given archive
|
||||||
|
*
|
||||||
|
* Usage: icingaweb module install <module-name>
|
||||||
|
* icingaweb module install </path/to/archive.tar.gz>
|
||||||
|
*/
|
||||||
|
public function installAction()
|
||||||
|
{
|
||||||
|
$this->fail("Not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a given module
|
||||||
|
*
|
||||||
|
* Removes the given module from your disk. Module configuration will be
|
||||||
|
* preserved
|
||||||
|
*
|
||||||
|
* Usage: icingaweb module remove <module-name>
|
||||||
|
*/
|
||||||
|
public function removeAction()
|
||||||
|
{
|
||||||
|
$this->fail("Not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Purge a given module
|
||||||
|
*
|
||||||
|
* Removes the given module from your disk. Also wipes configuration files
|
||||||
|
* and other data stored and/or generated by this module
|
||||||
|
*
|
||||||
|
* Usage: icingaweb module remove <module-name>
|
||||||
|
*/
|
||||||
|
public function purgeAction()
|
||||||
|
{
|
||||||
|
$this->fail("Not implemented yet");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Clicommands;
|
||||||
|
|
||||||
|
use Icinga\Cli\Command;
|
||||||
|
use Icinga\Application\TranslationHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translation command
|
||||||
|
*
|
||||||
|
* This command provides different utilities useful for translators. It
|
||||||
|
* allows to add new languages and also to refresh existing translations. All
|
||||||
|
* functionality is available for core components and for modules.
|
||||||
|
*
|
||||||
|
* This is another parapragh.
|
||||||
|
*/
|
||||||
|
class TranslationCommand extends Command
|
||||||
|
{
|
||||||
|
protected $translator;
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->translator = new TranslationHelper(
|
||||||
|
$this->application,
|
||||||
|
$this->params->get('locale', 'C'),
|
||||||
|
$this->params->get('module', 'monitoring') // bullshit. NULL?
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh translation catalogs
|
||||||
|
*
|
||||||
|
* Extracts all translatable strings for a given module (or core) from the
|
||||||
|
* Icingaweb source code, adds those to the existing catalog for the given
|
||||||
|
* locale and marks obsolete translations.
|
||||||
|
*
|
||||||
|
* Usage: icingaweb translation refresh --module <modulename> --locale <lc_LC>
|
||||||
|
*/
|
||||||
|
public function refreshAction()
|
||||||
|
{
|
||||||
|
$this->translator->createTemporaryFileList()->extractTexts();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Icinga\Application\Cli;
|
||||||
|
use Icinga\Cli\Params as CliParams;
|
||||||
|
use Icinga\Application\Benchmark;
|
||||||
|
|
||||||
|
set_include_path(
|
||||||
|
realpath(dirname(__FILE__) . '/../library/')
|
||||||
|
. ':' . get_include_path()
|
||||||
|
);
|
||||||
|
|
||||||
|
require_once 'Icinga/Application/Cli.php';
|
||||||
|
$app = Cli::start(dirname(__FILE__) . '/../config/')->dispatch();
|
||||||
|
|
|
@ -1,67 +1,158 @@
|
||||||
<?php
|
<?php
|
||||||
// {{{ICINGA_LICENSE_HEADER}}}
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
/**
|
|
||||||
* This file is part of Icinga 2 Web.
|
|
||||||
*
|
|
||||||
* Icinga 2 Web - Head for multiple monitoring backends.
|
|
||||||
* Copyright (C) 2013 Icinga Development Team
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License
|
|
||||||
* as published by the Free Software Foundation; either version 2
|
|
||||||
* of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*
|
|
||||||
* @copyright 2013 Icinga Development Team <info@icinga.org>
|
|
||||||
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
|
||||||
* @author Icinga Development Team <info@icinga.org>
|
|
||||||
*/
|
|
||||||
// {{{ICINGA_LICENSE_HEADER}}}
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
|
||||||
namespace Icinga\Application;
|
namespace Icinga\Application;
|
||||||
|
|
||||||
|
use Icinga\Application\Platform;
|
||||||
|
use Icinga\Application\ApplicationBootstrap;
|
||||||
|
use Icinga\Application\Modules\Manager as ModuleManager;
|
||||||
|
use Icinga\Cli\Params;
|
||||||
|
use Icinga\Cli\Loader;
|
||||||
|
use Icinga\Cli\Screen;
|
||||||
|
use Icinga\Application\Benchmark;
|
||||||
|
use Icinga\Exception\ProgrammingError;
|
||||||
|
|
||||||
// @codingStandardsIgnoreStart
|
// @codingStandardsIgnoreStart
|
||||||
require_once dirname(__FILE__). '/ApplicationBootstrap.php';
|
require_once dirname(__FILE__) . '/ApplicationBootstrap.php';
|
||||||
require_once dirname(__FILE__). '/../Exception/ProgrammingError.php';
|
require_once dirname(__FILE__). '/../Exception/ProgrammingError.php';
|
||||||
// @codingStandardsIgnoreStop
|
// @codingStandardsIgnoreStop
|
||||||
|
|
||||||
use Icinga\Exception\ProgrammingError;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bootstrapping on cli environment
|
|
||||||
*/
|
|
||||||
class Cli extends ApplicationBootstrap
|
class Cli extends ApplicationBootstrap
|
||||||
{
|
{
|
||||||
protected $isCli = true;
|
protected $isCli = true;
|
||||||
|
|
||||||
|
protected $params;
|
||||||
|
|
||||||
|
protected $showBenchmark = false;
|
||||||
|
|
||||||
|
protected $watchTimeout;
|
||||||
|
|
||||||
|
protected $cliLoader;
|
||||||
|
|
||||||
protected function bootstrap()
|
protected function bootstrap()
|
||||||
{
|
{
|
||||||
$this->assertRunningOnCli();
|
$this->assertRunningOnCli();
|
||||||
|
|
||||||
return $this->setupConfig()
|
return $this->setupConfig()
|
||||||
->setupErrorHandling()
|
->setupErrorHandling()
|
||||||
->setupTimezone();
|
->setupResourceFactory()
|
||||||
|
->setupModules()
|
||||||
|
->parseParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cliLoader()
|
||||||
|
{
|
||||||
|
if ($this->cliLoader === null) {
|
||||||
|
$this->cliLoader = new Loader($this);
|
||||||
|
}
|
||||||
|
return $this->cliLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup module loader
|
||||||
|
*
|
||||||
|
* TODO: This can be removed once broken bootstrapping has been fixed
|
||||||
|
* Loading the module manager and enabling all modules have former
|
||||||
|
* been two different tasks. CLI does NOT enable any module by default.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
protected function setupModules()
|
||||||
|
{
|
||||||
|
$this->moduleManager = new ModuleManager($this, $this->getConfigDir('enabledModules'));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter for module manager
|
||||||
|
*
|
||||||
|
* TODO: This can also be removed once fixed. Making everything private
|
||||||
|
* made this duplication necessary
|
||||||
|
*
|
||||||
|
* @return ModuleManager
|
||||||
|
*/
|
||||||
|
public function getModuleManager()
|
||||||
|
{
|
||||||
|
return $this->moduleManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function parseParams()
|
||||||
|
{
|
||||||
|
$this->params = Params::parse();
|
||||||
|
if ($this->params->shift('help')) {
|
||||||
|
$this->params->unshift('help');
|
||||||
|
}
|
||||||
|
$watch = $this->params->shift('watch');
|
||||||
|
if ($watch === true) {
|
||||||
|
$watch = 5;
|
||||||
|
}
|
||||||
|
if (preg_match('~^\d+$~', $watch)) {
|
||||||
|
$this->watchTimeout = (int) $watch;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->showBenchmark = (bool) $this->params->shift('benchmark');
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParams()
|
||||||
|
{
|
||||||
|
return $this->params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dispatch()
|
||||||
|
{
|
||||||
|
Benchmark::measure('Dispatching CLI command');
|
||||||
|
|
||||||
|
if ($this->watchTimeout === null) {
|
||||||
|
$this->dispatchOnce();
|
||||||
|
} else {
|
||||||
|
$this->dispatchEndless();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function dispatchOnce()
|
||||||
|
{
|
||||||
|
$loader = new Loader($this);
|
||||||
|
$loader->parseParams();
|
||||||
|
$loader->dispatch();
|
||||||
|
Benchmark::measure('All done');
|
||||||
|
if ($this->showBenchmark) {
|
||||||
|
Benchmark::dump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function dispatchEndless()
|
||||||
|
{
|
||||||
|
$loader = new Loader($this);
|
||||||
|
$loader->parseParams();
|
||||||
|
$screen = Screen::instance();
|
||||||
|
while (true) {
|
||||||
|
Benchmark::measure('Watch mode - loop begins');
|
||||||
|
echo $screen->clear();
|
||||||
|
$params = clone($this->params);
|
||||||
|
$loader->dispatch();
|
||||||
|
Benchmark::measure('Dispatch done');
|
||||||
|
if ($this->showBenchmark) {
|
||||||
|
Benchmark::dump();
|
||||||
|
}
|
||||||
|
Benchmark::reset();
|
||||||
|
$this->params = $params;
|
||||||
|
sleep($this->watchTimeout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fail if Icinga has not been called on CLI
|
* Fail if Icinga has not been called on CLI
|
||||||
*
|
*
|
||||||
* @throws \Exception
|
* @throws ProgrammingError
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function assertRunningOnCli()
|
private function assertRunningOnCli()
|
||||||
{
|
{
|
||||||
if (Platform::isCli()) {
|
if (Platform::isCli()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ProgrammingError('Icinga is not running on CLI');
|
throw new ProgrammingError('Icinga is not running on CLI');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Cli;
|
||||||
|
|
||||||
|
use Icinga\Cli\Loader;
|
||||||
|
use Icinga\Cli\Screen;
|
||||||
|
use Icinga\Application\ApplicationBootstrap as App;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
abstract class Command
|
||||||
|
{
|
||||||
|
protected $app;
|
||||||
|
protected $docs;
|
||||||
|
protected $params;
|
||||||
|
protected $screen;
|
||||||
|
protected $isVerbose;
|
||||||
|
protected $isDebugging;
|
||||||
|
|
||||||
|
protected $moduleName;
|
||||||
|
protected $commandName;
|
||||||
|
protected $actionName;
|
||||||
|
|
||||||
|
protected $defaultActionName = 'default';
|
||||||
|
|
||||||
|
public function __construct(App $app, $moduleName, $commandName, $actionName, $initialize = true)
|
||||||
|
{
|
||||||
|
$this->app = $app;
|
||||||
|
$this->moduleName = $moduleName;
|
||||||
|
$this->commandName = $commandName;
|
||||||
|
$this->actionName = $actionName;
|
||||||
|
$this->params = $app->getParams();
|
||||||
|
$this->screen = Screen::instance($app);
|
||||||
|
$this->isVerbose = $this->params->shift('verbose', false);
|
||||||
|
$this->isDebuging = $this->params->shift('debug', false);
|
||||||
|
if ($initialize) {
|
||||||
|
$this->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasRemainingParams()
|
||||||
|
{
|
||||||
|
return $this->params->count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fail($msg)
|
||||||
|
{
|
||||||
|
throw new Exception($msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultActionName()
|
||||||
|
{
|
||||||
|
return $this->defaultActionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasDefaultActionName()
|
||||||
|
{
|
||||||
|
return $this->hasActionName($this->defaultActionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasActionName($name)
|
||||||
|
{
|
||||||
|
$actions = $this->listActions();
|
||||||
|
return in_array($name, $actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listActions()
|
||||||
|
{
|
||||||
|
$actions = array();
|
||||||
|
foreach (get_class_methods($this) as $method) {
|
||||||
|
if (preg_match('~^([A-Za-z0-9]+)Action$~', $method, $m)) {
|
||||||
|
$actions[] = $m[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort($actions);
|
||||||
|
return $actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function docs()
|
||||||
|
{
|
||||||
|
if ($this->docs === null) {
|
||||||
|
$this->docs = new Documentation($this->app);
|
||||||
|
}
|
||||||
|
return $this->docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showUsage($action = null)
|
||||||
|
{
|
||||||
|
if ($action === null) {
|
||||||
|
$action = $this->actionName;
|
||||||
|
}
|
||||||
|
echo $this->docs()->usage(
|
||||||
|
$this->moduleName,
|
||||||
|
$this->commandName,
|
||||||
|
$action
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Cli;
|
||||||
|
|
||||||
|
use Icinga\Application\ApplicationBootstrap as App;
|
||||||
|
use Icinga\Cli\Documentation\CommentParser;
|
||||||
|
use ReflectionClass;
|
||||||
|
use ReflectionMethod;
|
||||||
|
|
||||||
|
class Documentation
|
||||||
|
{
|
||||||
|
protected $icinga;
|
||||||
|
|
||||||
|
public function __construct(App $app)
|
||||||
|
{
|
||||||
|
$this->app = $app;
|
||||||
|
$this->loader = $app->cliLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function usage($module = null, $command = null, $action = null)
|
||||||
|
{
|
||||||
|
if ($module !== null) {
|
||||||
|
return $this->moduleUsage($module, $command, $action);
|
||||||
|
}
|
||||||
|
if ($command !== null) {
|
||||||
|
return $this->commandUsage($command, $action);
|
||||||
|
}
|
||||||
|
return $this->globalUsage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function globalUsage()
|
||||||
|
{
|
||||||
|
$d = "USAGE: icingaweb [module] <command> [action] [options]\n\n"
|
||||||
|
. "Available commands:\n\n";
|
||||||
|
foreach ($this->loader->listCommands() as $command) {
|
||||||
|
$obj = $this->loader->getCommandInstance($command);
|
||||||
|
$d .= sprintf(
|
||||||
|
" %-14s %s\n",
|
||||||
|
$command,
|
||||||
|
$this->getClassTitle($obj)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$d .= "\nAvailable modules:\n\n";
|
||||||
|
foreach ($this->loader->listModules() as $module) {
|
||||||
|
$d .= ' ' . $module . "\n";
|
||||||
|
}
|
||||||
|
$d .= "\nGlobal options:\n\n"
|
||||||
|
. " --verbose Be verbose\n"
|
||||||
|
. " --debug Show debug output\n"
|
||||||
|
. " --benchmark Show benchmark summary\n"
|
||||||
|
. " --watch [s] Refresh output each <s> seconds (default: 5)\n"
|
||||||
|
;
|
||||||
|
$d .= "\nShow help on a specific command : icingaweb help <command>"
|
||||||
|
. "\nShow help on a specific module : icingaweb help <module>"
|
||||||
|
. "\n";
|
||||||
|
return $d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function moduleUsage($module, $command = null, $action = null)
|
||||||
|
{
|
||||||
|
$commands = $this->loader->listModuleCommands($module);
|
||||||
|
|
||||||
|
if (empty($commands)) {
|
||||||
|
return "The '$module' module does not provide any CLI commands\n";
|
||||||
|
}
|
||||||
|
$d = '';
|
||||||
|
if ($command) {
|
||||||
|
$obj = $this->loader->getModuleCommandInstance($module, $command);
|
||||||
|
}
|
||||||
|
if ($command === null) {
|
||||||
|
$d = "USAGE: icingaweb $module <command> [<action>] [options]\n\n"
|
||||||
|
. "Available commands:\n\n";
|
||||||
|
foreach ($commands as $command) {
|
||||||
|
$d .= ' ' . $command . "\n";
|
||||||
|
}
|
||||||
|
$d .= "\nShow help on a specific command: icingaweb help $module <command>\n";
|
||||||
|
} elseif ($action === null) {
|
||||||
|
$d .= $this->showCommandActions($obj, $command);
|
||||||
|
} else {
|
||||||
|
$d .= $this->getMethodDocumentation($obj, $action);
|
||||||
|
}
|
||||||
|
return $d;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function showCommandActions($command, $name)
|
||||||
|
{
|
||||||
|
$actions = $command->listActions();
|
||||||
|
$d = $this->getClassDocumentation($command)
|
||||||
|
. "Available actions:\n\n";
|
||||||
|
foreach ($actions as $action) {
|
||||||
|
$d .= sprintf(
|
||||||
|
" %-14s %s\n",
|
||||||
|
$action,
|
||||||
|
$this->getMethodTitle($command, $action)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$d .= "\nShow help on a specific action: icingaweb help $name <action>\n";
|
||||||
|
return $d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function commandUsage($command, $action = null)
|
||||||
|
{
|
||||||
|
$obj = $this->loader->getCommandInstance($command);
|
||||||
|
$d = "\n";
|
||||||
|
if ($action === null) {
|
||||||
|
$d .= $this->showCommandActions($obj, $command);
|
||||||
|
} else {
|
||||||
|
$d .= $this->getMethodDocumentation($obj, $action);
|
||||||
|
}
|
||||||
|
return $d;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getClassTitle($class)
|
||||||
|
{
|
||||||
|
$ref = new ReflectionClass($class);
|
||||||
|
$comment = new CommentParser($ref->getDocComment());
|
||||||
|
return $comment->getTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getClassDocumentation($class)
|
||||||
|
{
|
||||||
|
$ref = new ReflectionClass($class);
|
||||||
|
$comment = new CommentParser($ref->getDocComment());
|
||||||
|
return $comment->dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getMethodTitle($class, $method)
|
||||||
|
{
|
||||||
|
$ref = new ReflectionMethod($class, $method . 'Action');
|
||||||
|
$comment = new CommentParser($ref->getDocComment());
|
||||||
|
return $comment->getTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getMethodDocumentation($class, $method)
|
||||||
|
{
|
||||||
|
$ref = new ReflectionMethod($class, $method . 'Action');
|
||||||
|
$comment = new CommentParser($ref->getDocComment());
|
||||||
|
return $comment->dump();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Cli\Documentation;
|
||||||
|
|
||||||
|
class CommentParser
|
||||||
|
{
|
||||||
|
protected $raw;
|
||||||
|
protected $plain;
|
||||||
|
protected $title;
|
||||||
|
protected $paragraphs = array();
|
||||||
|
|
||||||
|
public function __construct($raw)
|
||||||
|
{
|
||||||
|
$this->raw = $raw;
|
||||||
|
if ($raw) {
|
||||||
|
$this->parse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle()
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function parse()
|
||||||
|
{
|
||||||
|
$plain = $this->raw;
|
||||||
|
|
||||||
|
// Strip comment start /**
|
||||||
|
$plain = preg_replace('~^/\s*\*\*\n~s', '', $plain);
|
||||||
|
|
||||||
|
// Strip comment end */
|
||||||
|
$plain = preg_replace('~\n\s*\*/\s*~s', "\n", $plain);
|
||||||
|
$p = null;
|
||||||
|
foreach (preg_split('~\n~', $plain) as $line) {
|
||||||
|
|
||||||
|
// Strip * at line start
|
||||||
|
$line = preg_replace('~^\s*\*\s?~', '', $line);
|
||||||
|
$line = rtrim($line);
|
||||||
|
if ($this->title === null) {
|
||||||
|
$this->title = $line;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($p === null && empty($this->paragraphs)) {
|
||||||
|
$p = & $this->paragraphs[];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($line === '') {
|
||||||
|
if ($p !== null) {
|
||||||
|
$p = & $this->paragraphs[];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($p === null) {
|
||||||
|
$p = $line;
|
||||||
|
} else {
|
||||||
|
if (substr($line, 0, 2) === ' ') {
|
||||||
|
$p .= "\n" . $line;
|
||||||
|
} else {
|
||||||
|
$p .= ' ' . $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($p === null) {
|
||||||
|
array_pop($this->paragraphs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dump()
|
||||||
|
{
|
||||||
|
$res = $this->title . "\n" . str_repeat('=', strlen($this->title)) . "\n\n";
|
||||||
|
foreach ($this->paragraphs as $p) {
|
||||||
|
$res .= wordwrap($p, 72) . "\n\n";
|
||||||
|
}
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,399 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Cli;
|
||||||
|
|
||||||
|
use Icinga\Application\ApplicationBootstrap as App;
|
||||||
|
use Icinga\Exception\ProgrammingError;
|
||||||
|
use Icinga\Cli\Params;
|
||||||
|
use Icinga\Cli\Screen;
|
||||||
|
use Icinga\Cli\Documentation;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Loader
|
||||||
|
{
|
||||||
|
protected $app;
|
||||||
|
|
||||||
|
protected $docs;
|
||||||
|
|
||||||
|
protected $commands;
|
||||||
|
|
||||||
|
protected $modules;
|
||||||
|
|
||||||
|
protected $moduleCommands = array();
|
||||||
|
|
||||||
|
protected $coreAppDir;
|
||||||
|
|
||||||
|
protected $screen;
|
||||||
|
|
||||||
|
protected $moduleName;
|
||||||
|
|
||||||
|
protected $commandName;
|
||||||
|
|
||||||
|
protected $actionName; // Should this better be moved to the Command?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [$command] = $class;
|
||||||
|
*/
|
||||||
|
protected $commandClassMap = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [$command] = $file;
|
||||||
|
*/
|
||||||
|
protected $commandFileMap = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [$module][$command] = $class;
|
||||||
|
*/
|
||||||
|
protected $moduleClassMap = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [$module][$command] = $file;
|
||||||
|
*/
|
||||||
|
protected $moduleFileMap = array();
|
||||||
|
|
||||||
|
protected $commandInstances = array();
|
||||||
|
|
||||||
|
protected $moduleInstances = array();
|
||||||
|
|
||||||
|
protected $lastSuggestions = array();
|
||||||
|
|
||||||
|
public function __construct(App $app)
|
||||||
|
{
|
||||||
|
$this->app = $app;
|
||||||
|
$this->coreAppDir = ICINGA_APPDIR . '/clicommands';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen shortcut
|
||||||
|
*
|
||||||
|
* @return Screen
|
||||||
|
*/
|
||||||
|
protected function screen()
|
||||||
|
{
|
||||||
|
if ($this->screen === null) {
|
||||||
|
$this->screen = Screen::instance();
|
||||||
|
}
|
||||||
|
return $this->screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Documentation shortcut
|
||||||
|
*
|
||||||
|
* @return Documentation
|
||||||
|
*/
|
||||||
|
protected function docs()
|
||||||
|
{
|
||||||
|
if ($this->docs === null) {
|
||||||
|
$this->docs = new Documentation($this->app);
|
||||||
|
}
|
||||||
|
return $this->docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show given message and exit
|
||||||
|
*
|
||||||
|
* @param string $msg message to show
|
||||||
|
*/
|
||||||
|
public function fail($msg)
|
||||||
|
{
|
||||||
|
printf("%s: %s\n", $this->screen()->colorize('ERROR', 'red'), $msg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommandInstance($command)
|
||||||
|
{
|
||||||
|
if (! array_key_exists($command, $this->commandInstances)) {
|
||||||
|
$this->assertCommandExists($command);
|
||||||
|
require_once $this->commandFileMap[$command];
|
||||||
|
$className = $this->commandClassMap[$command];
|
||||||
|
$this->commandInstances[$command] = new $className(
|
||||||
|
$this->app,
|
||||||
|
null,
|
||||||
|
$command,
|
||||||
|
null,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $this->commandInstances[$command];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getModuleCommandInstance($module, $command)
|
||||||
|
{
|
||||||
|
if (! array_key_exists($command, $this->moduleInstances[$module])) {
|
||||||
|
$this->assertModuleCommandExists($module, $command);
|
||||||
|
require_once $this->moduleFileMap[$module][$command];
|
||||||
|
$className = $this->moduleClassMap[$module][$command];
|
||||||
|
$this->moduleInstances[$module][$command] = new $className(
|
||||||
|
$this->app,
|
||||||
|
$module,
|
||||||
|
$command,
|
||||||
|
null,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $this->moduleInstances[$module][$command];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showLastSuggestions()
|
||||||
|
{
|
||||||
|
if (! empty($this->lastSuggestions)) {
|
||||||
|
foreach ($this->lastSuggestions as & $s) {
|
||||||
|
$s = $this->screen()->colorize($s, 'lightblue');
|
||||||
|
}
|
||||||
|
printf(
|
||||||
|
"Did you mean %s?\n",
|
||||||
|
implode(" or ", $this->lastSuggestions)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseParams(Params $params = null)
|
||||||
|
{
|
||||||
|
if ($params === null) {
|
||||||
|
$params = $this->app->getParams();
|
||||||
|
}
|
||||||
|
$first = $params->shift();
|
||||||
|
if (! $first) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$found = $this->resolveName($first);
|
||||||
|
if (! $found) {
|
||||||
|
$msg = "There is no such module or command: '$first'";
|
||||||
|
printf("%s: %s\n", $this->screen()->colorize('ERROR', 'red'), $msg);
|
||||||
|
$this->showLastSuggestions();
|
||||||
|
echo "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$obj = null;
|
||||||
|
if ($this->hasCommand($found)) {
|
||||||
|
$this->commandName = $found;
|
||||||
|
$obj = $this->getCommandInstance($this->commandName);
|
||||||
|
} elseif ($this->hasModule($found)) {
|
||||||
|
$this->moduleName = $found;
|
||||||
|
$command = $this->resolveModuleCommandName($found, $params->shift());
|
||||||
|
if ($command) {
|
||||||
|
$this->commandName = $command;
|
||||||
|
$obj = $this->getModuleCommandInstance(
|
||||||
|
$this->moduleName,
|
||||||
|
$this->commandName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($obj !== null) {
|
||||||
|
$action = $this->resolveObjectActionName(
|
||||||
|
$obj,
|
||||||
|
$params->getStandalone()
|
||||||
|
);
|
||||||
|
if ($obj->hasActionName($action)) {
|
||||||
|
$this->actionName = $action;
|
||||||
|
$params->shift();
|
||||||
|
} elseif ($obj->hasDefaultActionName()) {
|
||||||
|
$this->actionName = $obj->getDefaultActionName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleParams(Params $params = null)
|
||||||
|
{
|
||||||
|
$this->parseParams($params);
|
||||||
|
$this->dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dispatch()
|
||||||
|
{
|
||||||
|
if ($this->commandName === null) {
|
||||||
|
echo $this->docs()->usage($this->moduleName);
|
||||||
|
return false;
|
||||||
|
} elseif ($this->actionName === null) {
|
||||||
|
echo $this->docs()->usage($this->moduleName, $this->commandName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($this->moduleName) {
|
||||||
|
$this->app->getModuleManager()->loadModule($this->moduleName);
|
||||||
|
$obj = $this->getModuleCommandInstance(
|
||||||
|
$this->moduleName,
|
||||||
|
$this->commandName
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$obj = $this->getCommandInstance($this->commandName);
|
||||||
|
}
|
||||||
|
$obj->init();
|
||||||
|
return $obj->{$this->actionName . 'Action'}();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->fail($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function searchMatch($needle, $haystack)
|
||||||
|
{
|
||||||
|
$stack = $haystack;
|
||||||
|
$search = $needle;
|
||||||
|
$this->lastSuggestions = array();
|
||||||
|
while (strlen($search) > 0) {
|
||||||
|
$len = strlen($search);
|
||||||
|
foreach ($stack as & $s) {
|
||||||
|
$s = substr($s, 0, $len);
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = array_keys($stack, $search, true);
|
||||||
|
if (count($res) === 1) {
|
||||||
|
$found = $haystack[$res[0]];
|
||||||
|
if (substr($found, 0, strlen($needle)) === $needle) {
|
||||||
|
return $found;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} elseif (count($res) > 1) {
|
||||||
|
foreach ($res as $key) {
|
||||||
|
$this->lastSuggestions[] = $haystack[$key];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$search = substr($search, 0, -1);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveName($name)
|
||||||
|
{
|
||||||
|
return $this->searchMatch(
|
||||||
|
$name,
|
||||||
|
array_merge($this->listCommands(), $this->listModules())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveCommandName($name)
|
||||||
|
{
|
||||||
|
return $this->searchMatch($name, $this->listCommands());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveModuleName($name)
|
||||||
|
{
|
||||||
|
return $this->searchMatch($name, $this->listModules());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveModuleCommandName($module, $name)
|
||||||
|
{
|
||||||
|
return $this->searchMatch($name, $this->listModuleCommands($module));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resolveObjectActionName($obj, $name)
|
||||||
|
{
|
||||||
|
return $this->searchMatch($name, $obj->listActions());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function assertModuleExists($module)
|
||||||
|
{
|
||||||
|
if (! $this->hasModule($module)) {
|
||||||
|
throw new ProgrammingError(
|
||||||
|
sprintf('There is no such module: %s', $module)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function assertCommandExists($command)
|
||||||
|
{
|
||||||
|
if (! $this->hasCommand($command)) {
|
||||||
|
throw new ProgrammingError(
|
||||||
|
sprintf('There is no such command: %s', $command)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function assertModuleCommandExists($module, $command)
|
||||||
|
{
|
||||||
|
$this->assertModuleExists($module);
|
||||||
|
if (! $this->hasModuleCommand($module, $command)) {
|
||||||
|
throw new ProgrammingError(
|
||||||
|
sprintf("The module '%s' has no such command: %s", $module, $command)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasCommand($name)
|
||||||
|
{
|
||||||
|
return in_array($name, $this->listCommands());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasModule($name)
|
||||||
|
{
|
||||||
|
return in_array($name, $this->listModules());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasModuleCommand($module, $name)
|
||||||
|
{
|
||||||
|
return in_array($name, $this->listModuleCommands($module));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listModules()
|
||||||
|
{
|
||||||
|
if ($this->modules === null) {
|
||||||
|
$this->modules = array();
|
||||||
|
$this->modules = $this->app->getModuleManager()->listEnabledModules();
|
||||||
|
sort($this->modules);
|
||||||
|
}
|
||||||
|
return $this->modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function retrieveCommandsFromDir($dirname)
|
||||||
|
{
|
||||||
|
$commands = array();
|
||||||
|
if (! @file_exists($dirname) || ! is_readable($dirname)) {
|
||||||
|
return $commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
$base = opendir($dirname);
|
||||||
|
if ($base === false) {
|
||||||
|
return $commands;
|
||||||
|
}
|
||||||
|
while (false !== ($dir = readdir($base))) {
|
||||||
|
if ($dir[0] === '.') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (preg_match('~^([A-Za-z0-9]+)Command\.php$~', $dir, $m)) {
|
||||||
|
$cmd = strtolower($m[1]);
|
||||||
|
$commands[] = $cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort($commands);
|
||||||
|
return $commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listCommands()
|
||||||
|
{
|
||||||
|
if ($this->commands === null) {
|
||||||
|
$this->commands = array();
|
||||||
|
$ns = 'Icinga\\Clicommands\\';
|
||||||
|
$this->commands = $this->retrieveCommandsFromDir($this->coreAppDir);
|
||||||
|
foreach ($this->commands as $cmd) {
|
||||||
|
$this->commandClassMap[$cmd] = $ns . ucfirst($cmd) . 'Command';
|
||||||
|
$this->commandFileMap[$cmd] = $this->coreAppDir . '/' . ucfirst($cmd) . 'Command.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listModuleCommands($module)
|
||||||
|
{
|
||||||
|
if (! array_key_exists($module, $this->moduleCommands)) {
|
||||||
|
$ns = 'Icinga\\Module\\' . ucfirst($module) . '\\Clicommands\\';
|
||||||
|
$this->assertModuleExists($module);
|
||||||
|
$manager = $this->app->getModuleManager();
|
||||||
|
$manager->enableModule($module);
|
||||||
|
$dir = $manager->getModuleDir($module) . '/application/clicommands';
|
||||||
|
$this->moduleCommands[$module] = $this->retrieveCommandsFromDir($dir);
|
||||||
|
$this->moduleInstances[$module] = array();
|
||||||
|
foreach ($this->moduleCommands[$module] as $cmd) {
|
||||||
|
$this->moduleClassMap[$module][$cmd] = $ns . ucfirst($cmd) . 'Command';
|
||||||
|
$this->moduleFileMap[$module][$cmd] = $dir . '/' . ucfirst($cmd) . 'Command.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->moduleCommands[$module];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Cli;
|
||||||
|
|
||||||
|
class Params
|
||||||
|
{
|
||||||
|
protected $program;
|
||||||
|
protected $standalone = array();
|
||||||
|
protected $params = array();
|
||||||
|
|
||||||
|
public function __construct($argv)
|
||||||
|
{
|
||||||
|
$this->program = array_shift($argv);
|
||||||
|
for ($i = 0; $i < count($argv); $i++) {
|
||||||
|
if (substr($argv[$i], 0, 2) === '--') {
|
||||||
|
$key = substr($argv[$i], 2);
|
||||||
|
if (! isset($argv[$i + 1]) || substr($argv[$i + 1], 0, 2) === '--') {
|
||||||
|
$this->params[$key] = true;
|
||||||
|
} else {
|
||||||
|
$this->params[$key] = $argv[++$i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->standalone[] = $argv[$i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStandalone($pos = 0, $default = null)
|
||||||
|
{
|
||||||
|
if (isset($this->standalone[$pos])) {
|
||||||
|
return $this->standalone[$pos];
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count()
|
||||||
|
{
|
||||||
|
return count($this->standalone) + count($this->params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParams()
|
||||||
|
{
|
||||||
|
return $this->params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($key)
|
||||||
|
{
|
||||||
|
return $this->get($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function has($key)
|
||||||
|
{
|
||||||
|
return array_key_exists($key, $this->params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get($key, $default = null)
|
||||||
|
{
|
||||||
|
if ($this->has($key)) {
|
||||||
|
return $this->params[$key];
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set($key, $value)
|
||||||
|
{
|
||||||
|
$this->params[$key] = $value;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove($keys = array())
|
||||||
|
{
|
||||||
|
if (! is_array($keys)) {
|
||||||
|
$keys = array($keys);
|
||||||
|
}
|
||||||
|
foreach ($keys as $key) {
|
||||||
|
if (array_key_exists($key, $this->params)) {
|
||||||
|
unset($this->params[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function without($keys = array())
|
||||||
|
{
|
||||||
|
$params = clone($this);
|
||||||
|
return $params->remove($keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shift($key = null, $default = null)
|
||||||
|
{
|
||||||
|
if ($key === null) {
|
||||||
|
if (count($this->standalone) > 0) {
|
||||||
|
return array_shift($this->standalone);
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
$result = $this->get($key, $default);
|
||||||
|
$this->remove($key);
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unshift($key)
|
||||||
|
{
|
||||||
|
array_unshift($this->standalone, $key);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function parse($argv = null)
|
||||||
|
{
|
||||||
|
if ($argv === null) {
|
||||||
|
$argv = $GLOBALS['argv'];
|
||||||
|
}
|
||||||
|
$params = new self($argv);
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Cli;
|
||||||
|
|
||||||
|
use Icinga\Cli\Screen\AnsiScreen;
|
||||||
|
|
||||||
|
class Screen
|
||||||
|
{
|
||||||
|
protected static $instance;
|
||||||
|
|
||||||
|
public function instance()
|
||||||
|
{
|
||||||
|
if (self::$instance === null) {
|
||||||
|
self::$instance = new AnsiScreen();
|
||||||
|
}
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Cli\Screen;
|
||||||
|
|
||||||
|
use Icinga\Cli\Screen;
|
||||||
|
|
||||||
|
// @see http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||||
|
|
||||||
|
class AnsiScreen extends Screen
|
||||||
|
{
|
||||||
|
protected $isUtf8;
|
||||||
|
|
||||||
|
protected $fgColors = array(
|
||||||
|
'black' => '30',
|
||||||
|
'darkgray' => '1;30',
|
||||||
|
'red' => '31',
|
||||||
|
'lightred' => '1;31',
|
||||||
|
'green' => '32',
|
||||||
|
'lightgreen' => '1;32',
|
||||||
|
'brown' => '33',
|
||||||
|
'yellow' => '1;33',
|
||||||
|
'blue' => '34',
|
||||||
|
'lightblue' => '1;34',
|
||||||
|
'purple' => '35',
|
||||||
|
'lightpurple' => '1;35',
|
||||||
|
'cyan' => '36',
|
||||||
|
'lightcyan' => '1;36',
|
||||||
|
'lightgray' => '37',
|
||||||
|
'white' => '1;37',
|
||||||
|
);
|
||||||
|
|
||||||
|
protected $bgColors = array(
|
||||||
|
'black' => '40',
|
||||||
|
'red' => '41',
|
||||||
|
'green' => '42',
|
||||||
|
'brown' => '43',
|
||||||
|
'blue' => '44',
|
||||||
|
'purple' => '45',
|
||||||
|
'cyan' => '46',
|
||||||
|
'lightgray' => '47',
|
||||||
|
);
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getColumns()
|
||||||
|
{
|
||||||
|
$cols = (int) getenv('COLUMNS');
|
||||||
|
if (! $cols) {
|
||||||
|
// stty -a ?
|
||||||
|
$cols = (int) exec('tput cols');
|
||||||
|
}
|
||||||
|
if (! $cols) {
|
||||||
|
$cols = 80;
|
||||||
|
}
|
||||||
|
return $cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRows()
|
||||||
|
{
|
||||||
|
$rows = (int) getenv('ROWS');
|
||||||
|
if (! $rows) {
|
||||||
|
// stty -a ?
|
||||||
|
$rows = (int) exec('tput rows');
|
||||||
|
}
|
||||||
|
if (! $rows) {
|
||||||
|
$rows = 25;
|
||||||
|
}
|
||||||
|
return $rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasUtf8()
|
||||||
|
{
|
||||||
|
if ($this->isUtf8 === null) {
|
||||||
|
// null should equal 0 here, however seems to equal '' on some systems:
|
||||||
|
$current = setlocale(LC_ALL, 0);
|
||||||
|
|
||||||
|
$parts = preg_split('/;/', $current);
|
||||||
|
$lc_parts = array();
|
||||||
|
foreach ($parts as $part) {
|
||||||
|
if (strpos($part, '=') === false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
list($key, $val) = preg_split('/=/', $part, 2);
|
||||||
|
$lc_parts[$key] = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->isUtf8 = array_key_exists('LC_CTYPE', $lc_parts)
|
||||||
|
&& preg_match('~\.UTF-8$~i', $lc_parts['LC_CTYPE']);
|
||||||
|
}
|
||||||
|
return $this->isUtf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function clear()
|
||||||
|
{
|
||||||
|
return "\033[2J" // Clear the whole screen
|
||||||
|
. "\033[1;1H" // Move the cursor to row 1, column 1
|
||||||
|
. "\033[1S"; // Scroll whole page up by 1 line (why?)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function fgColor($color)
|
||||||
|
{
|
||||||
|
if (! array_key_exists($color, $this->fgColors)) {
|
||||||
|
throw new \Exception(sprintf('There is no such foreground color: %s', $color));
|
||||||
|
}
|
||||||
|
return $this->fgColors[$color];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function bgColor($color)
|
||||||
|
{
|
||||||
|
if (! array_key_exists($color, $this->bgColors)) {
|
||||||
|
throw new \Exception(sprintf('There is no such background color: %s', $color));
|
||||||
|
}
|
||||||
|
return $this->bgColors[$color];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function startColor($fgColor = null, $bgColor = null)
|
||||||
|
{
|
||||||
|
$escape = "ESC[";
|
||||||
|
$parts = array();
|
||||||
|
if ($fgColor !== null
|
||||||
|
&& $bgColor !== null
|
||||||
|
&& ! array_key_exists($bgColor, $this->bgColors)
|
||||||
|
&& array_key_exists($bgColor, $this->fgColors)
|
||||||
|
&& array_key_exists($fgColor, $this->bgColors)
|
||||||
|
) {
|
||||||
|
$parts[] = '7'; // reverse video, negative image
|
||||||
|
$parts[] = $this->bgColor($fgColor);
|
||||||
|
$parts[] = $this->fgColor($bgColor);
|
||||||
|
} else {
|
||||||
|
if ($fgColor !== null) {
|
||||||
|
$parts[] = $this->fgColor($fgColor);
|
||||||
|
}
|
||||||
|
if ($bgColor !== null) {
|
||||||
|
$parts[] = $this->bgColor($bgColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (empty($parts)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return "\033[" . implode(';', $parts) . 'm';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function underline($text)
|
||||||
|
{
|
||||||
|
return "\033[4m"
|
||||||
|
. $text
|
||||||
|
. "\033[0m"; // Reset color codes
|
||||||
|
}
|
||||||
|
|
||||||
|
public function colorize($text, $fgColor = null, $bgColor = null)
|
||||||
|
{
|
||||||
|
return $this->startColor($fgColor, $bgColor)
|
||||||
|
. $text
|
||||||
|
. "\033[0m"; // Reset color codes
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,280 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Clicommands;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Backend;
|
||||||
|
use Icinga\Module\Monitoring\Cli\CliUtils;
|
||||||
|
use Icinga\Util\Format;
|
||||||
|
use Icinga\Cli\Command;
|
||||||
|
use Icinga\File\Csv;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List and filter monitored objects
|
||||||
|
*
|
||||||
|
* This command allows you to search and visualize your monitored objects in
|
||||||
|
* different ways.
|
||||||
|
*
|
||||||
|
* USAGE
|
||||||
|
*
|
||||||
|
* icingaweb monitoring list [<type>] [options]
|
||||||
|
*
|
||||||
|
* OPTIONS
|
||||||
|
*
|
||||||
|
* --verbose Show detailled output
|
||||||
|
* --showsql Dump generated SQL query (DB backend only)
|
||||||
|
*
|
||||||
|
* --format <csv|json|<custom>>
|
||||||
|
* Dump columns in the given format. <custom> format allows $column$
|
||||||
|
* placeholders, e.g. --format '$host$: $service$'
|
||||||
|
*
|
||||||
|
* --<column> [filter]
|
||||||
|
* Filter given column by optional filter. Boolean (1/0) columns are true
|
||||||
|
* if no filter value is given.
|
||||||
|
*
|
||||||
|
* EXAMPLES
|
||||||
|
*
|
||||||
|
* icingaweb monitoring list --unhandled
|
||||||
|
* icingaweb monitoring list --host local* --service *disk*
|
||||||
|
* icingaweb monitoring list --format '$host_name$: $service_description$'
|
||||||
|
*/
|
||||||
|
class ListCommand extends Command
|
||||||
|
{
|
||||||
|
protected $backend;
|
||||||
|
protected $dumpSql;
|
||||||
|
protected $defaultActionName = 'status';
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->backend = Backend::createBackend($this->params->shift('backend'));
|
||||||
|
$this->dumpSql = $this->params->shift('showsql');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getQuery($table, $columns)
|
||||||
|
{
|
||||||
|
$limit = $this->params->shift('limit');
|
||||||
|
$format = $this->params->shift('format');
|
||||||
|
if ($format !== null) {
|
||||||
|
if ($this->params->has('columns')) {
|
||||||
|
$columnParams = preg_split(
|
||||||
|
'/,/',
|
||||||
|
$this->params->shift('columns')
|
||||||
|
);
|
||||||
|
$columns = array();
|
||||||
|
foreach ($columnParams as $col) {
|
||||||
|
if (false !== ($pos = strpos($col, '='))) {
|
||||||
|
$columns[substr($col, 0, $pos)] = substr($col, $pos + 1);
|
||||||
|
} else {
|
||||||
|
$columns[] = $col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->backend->select()->from($table, $columns);
|
||||||
|
if ($limit) {
|
||||||
|
$query->limit($limit, $this->params->shift('offset'));
|
||||||
|
}
|
||||||
|
foreach ($this->params->getParams() as $col => $filter) {
|
||||||
|
$query->where($col, $filter);
|
||||||
|
}
|
||||||
|
// $query->applyFilters($this->params->getParams());
|
||||||
|
if ($this->dumpSql) {
|
||||||
|
echo wordwrap($query->dump(), 72);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($format !== null) {
|
||||||
|
$this->showFormatted($query, $format, $columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function showFormatted($query, $format, $columns)
|
||||||
|
{
|
||||||
|
switch($format) {
|
||||||
|
case 'json':
|
||||||
|
echo json_encode($query->fetchAll());
|
||||||
|
break;
|
||||||
|
case 'csv':
|
||||||
|
Csv::fromQuery($query)->dump();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
preg_match_all('~\$([a-z0-9_-]+)\$~', $format, $m);
|
||||||
|
$words = array();
|
||||||
|
foreach ($columns as $key => $col) {
|
||||||
|
if (is_numeric($key)) {
|
||||||
|
if (in_array($col, $m[1])) {
|
||||||
|
$words[] = $col;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (in_array($key, $m[1])) {
|
||||||
|
$words[] = $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($query->fetchAll() as $row) {
|
||||||
|
$output = $format;
|
||||||
|
foreach ($words as $word) {
|
||||||
|
$output = preg_replace(
|
||||||
|
'~\$' . $word . '\$~',
|
||||||
|
$row->{$word},
|
||||||
|
$output
|
||||||
|
);
|
||||||
|
}
|
||||||
|
echo $output . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function statusAction()
|
||||||
|
{
|
||||||
|
$columns = array(
|
||||||
|
'host_name',
|
||||||
|
'host_state',
|
||||||
|
'host_output',
|
||||||
|
'host_handled',
|
||||||
|
'host_acknowledged',
|
||||||
|
'host_in_downtime',
|
||||||
|
'service_description',
|
||||||
|
'service_state',
|
||||||
|
'service_acknowledged',
|
||||||
|
'service_in_downtime',
|
||||||
|
'service_handled',
|
||||||
|
'service_output',
|
||||||
|
'service_last_state_change'
|
||||||
|
);
|
||||||
|
$query = $this->getQuery('status', $columns)
|
||||||
|
->order('host_name');
|
||||||
|
echo $this->renderQuery($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderQuery($query)
|
||||||
|
{
|
||||||
|
$out = '';
|
||||||
|
$last_host = null;
|
||||||
|
$screen = $this->screen;
|
||||||
|
$utils = new CliUtils($screen);
|
||||||
|
$maxCols = $screen->getColumns();
|
||||||
|
$rows = $query->fetchAll();
|
||||||
|
$count = $query->count();
|
||||||
|
$count = count($rows);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $count; $i++) {
|
||||||
|
$row = & $rows[$i];
|
||||||
|
|
||||||
|
$utils->setHostState($row->host_state);
|
||||||
|
if (! array_key_exists($i + 1, $rows)
|
||||||
|
|| $row->host_name !== $rows[$i + 1]->host_name
|
||||||
|
) {
|
||||||
|
$lastService = true;
|
||||||
|
} else {
|
||||||
|
$lastService = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hostUnhandled = ! ($row->host_state == 0 || $row->host_handled);
|
||||||
|
|
||||||
|
if ($row->host_name !== $last_host) {
|
||||||
|
if (isset($row->service_description)) {
|
||||||
|
$out .= "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$hostTxt = $utils->shortHostState();
|
||||||
|
if ($hostUnhandled) {
|
||||||
|
$out .= $utils->hostStateBackground(
|
||||||
|
sprintf(' %s ', $utils->shortHostState())
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$out .= sprintf(
|
||||||
|
'%s %s ',
|
||||||
|
$utils->hostStateBackground(' '),
|
||||||
|
$utils->shortHostState()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$out .= sprintf(
|
||||||
|
" %s%s: %s\n",
|
||||||
|
$screen->underline($row->host_name),
|
||||||
|
$screen->colorize($utils->objectStateFlags('host', $row), 'lightblue'),
|
||||||
|
$row->host_output
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($row->services_ok)) {
|
||||||
|
$out .= sprintf(
|
||||||
|
"%d services, %d problems (%d unhandled), %d OK\n",
|
||||||
|
$row->services_cnt,
|
||||||
|
$row->services_problem,
|
||||||
|
$row->services_problem_unhandled,
|
||||||
|
$row->services_ok
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$last_host = $row->host_name;
|
||||||
|
if (! isset($row->service_description)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$utils->setServiceState($row->service_state);
|
||||||
|
$serviceUnhandled = ! (
|
||||||
|
$row->service_state == 0 || $row->service_handled
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($lastService) {
|
||||||
|
$straight = ' ';
|
||||||
|
$leaf = '└';
|
||||||
|
} else {
|
||||||
|
$straight = '│';
|
||||||
|
$leaf = '├';
|
||||||
|
}
|
||||||
|
$out .= $utils->hostStateBackground(' ');
|
||||||
|
|
||||||
|
if ($serviceUnhandled) {
|
||||||
|
$out .= $utils->serviceStateBackground(
|
||||||
|
sprintf(' %s ', $utils->shortServiceState())
|
||||||
|
);
|
||||||
|
$emptyBg = ' ';
|
||||||
|
$emptySpace = '';
|
||||||
|
} else {
|
||||||
|
$out .= sprintf(
|
||||||
|
'%s %s ',
|
||||||
|
$utils->serviceStateBackground(' '),
|
||||||
|
$utils->shortServiceState()
|
||||||
|
);
|
||||||
|
$emptyBg = ' ';
|
||||||
|
$emptySpace = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
$emptyLine = "\n"
|
||||||
|
. $utils->hostStateBackground(' ')
|
||||||
|
. $utils->serviceStateBackground($emptyBg)
|
||||||
|
. $emptySpace
|
||||||
|
. ' ' . $straight . ' ';
|
||||||
|
|
||||||
|
$wrappedOutput = wordwrap(
|
||||||
|
preg_replace('~\@{3,}~', '@@@', $row->service_output),
|
||||||
|
$maxCols - 13
|
||||||
|
) . "\n";
|
||||||
|
$out .= sprintf(
|
||||||
|
" %1s─ %s%s (since %s)",
|
||||||
|
$leaf,
|
||||||
|
$screen->underline($row->service_description),
|
||||||
|
$screen->colorize($utils->objectStateFlags('service', $row), 'lightblue'),
|
||||||
|
Format::timeSince($row->service_last_state_change)
|
||||||
|
);
|
||||||
|
if ($this->isVerbose) {
|
||||||
|
$out .= $emptyLine . preg_replace(
|
||||||
|
'/\n/',
|
||||||
|
$emptyLine,
|
||||||
|
$wrappedOutput
|
||||||
|
) . "\n";
|
||||||
|
} else {
|
||||||
|
$out .= "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$out .= "\n";
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Clicommands;
|
||||||
|
|
||||||
|
use Icinga\Protocol\Nrpe\Connection;
|
||||||
|
use Icinga\Cli\Command;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NRPE
|
||||||
|
*/
|
||||||
|
class NrpeCommand extends Command
|
||||||
|
{
|
||||||
|
protected $defaultActionName = 'check';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute an NRPE command
|
||||||
|
*
|
||||||
|
* This command will execute an NRPE check, fire it against the given host
|
||||||
|
* and also pass through all your parameters. Output will be shown, exit
|
||||||
|
* code respected.
|
||||||
|
*
|
||||||
|
* USAGE
|
||||||
|
*
|
||||||
|
* icingaweb monitoring nrpe <host> <command> [--ssl] [nrpe options]
|
||||||
|
*
|
||||||
|
* EXAMPLE
|
||||||
|
*
|
||||||
|
* icingaweb monitoring nrpe 127.0.0.1 CheckMEM --ssl --MaxWarn 80% \
|
||||||
|
* --MaxCrit 90% --type physical
|
||||||
|
*/
|
||||||
|
public function checkAction()
|
||||||
|
{
|
||||||
|
$host = $this->params->shift();
|
||||||
|
if (! $host) {
|
||||||
|
echo $this->showUsage();
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
$command = $this->params->shift(null, '_NRPE_CHECK');
|
||||||
|
$port = $this->params->shift('port', 5666);
|
||||||
|
try {
|
||||||
|
$nrpe = new Connection($host, $port);
|
||||||
|
if ($this->params->shift('ssl')) {
|
||||||
|
$nrpe->useSsl();
|
||||||
|
}
|
||||||
|
$args = array();
|
||||||
|
foreach ($this->params->getParams() as $k => $v) {
|
||||||
|
$args[] = $k . '=' . $v;
|
||||||
|
}
|
||||||
|
echo $nrpe->sendCommand($command, $args) . "\n";
|
||||||
|
exit($nrpe->getLastReturnCode());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e->getMessage() . "\n";
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Cli;
|
||||||
|
|
||||||
|
use Icinga\Cli\Screen;
|
||||||
|
|
||||||
|
class CliUtils
|
||||||
|
{
|
||||||
|
protected $hostColors = array(
|
||||||
|
0 => array('black', 'lightgreen'),
|
||||||
|
1 => array('black', 'lightred'),
|
||||||
|
2 => array('black', 'brown'),
|
||||||
|
99 => array('black', 'lightgray'),
|
||||||
|
);
|
||||||
|
protected $serviceColors = array(
|
||||||
|
0 => array('black', 'lightgreen'),
|
||||||
|
1 => array('black', 'yellow'),
|
||||||
|
2 => array('black', 'lightred'),
|
||||||
|
3 => array('black', 'lightpurple'),
|
||||||
|
99 => array('black', 'lightgray'),
|
||||||
|
);
|
||||||
|
protected $hostStates = array(
|
||||||
|
0 => 'UP',
|
||||||
|
1 => 'DOWN',
|
||||||
|
2 => 'UNREACHABLE',
|
||||||
|
99 => 'PENDING',
|
||||||
|
);
|
||||||
|
|
||||||
|
protected $serviceStates = array(
|
||||||
|
0 => 'OK',
|
||||||
|
1 => 'WARNING',
|
||||||
|
2 => 'CRITICAL',
|
||||||
|
3 => 'UNKNOWN',
|
||||||
|
99 => 'PENDING',
|
||||||
|
);
|
||||||
|
|
||||||
|
protected $screen;
|
||||||
|
protected $hostState;
|
||||||
|
protected $serviceState;
|
||||||
|
|
||||||
|
public function __construct(Screen $screen)
|
||||||
|
{
|
||||||
|
$this->screen = $screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHostState($state)
|
||||||
|
{
|
||||||
|
$this->hostState = $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setServiceState($state)
|
||||||
|
{
|
||||||
|
$this->serviceState = $state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shortHostState($state = null)
|
||||||
|
{
|
||||||
|
if ($state === null) {
|
||||||
|
$state = $this->hostState;
|
||||||
|
}
|
||||||
|
return sprintf('%-4s', substr($this->hostStates[$state], 0, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function shortServiceState($state = null)
|
||||||
|
{
|
||||||
|
if ($state === null) {
|
||||||
|
$state = $this->serviceState;
|
||||||
|
}
|
||||||
|
return sprintf('%-4s', substr($this->serviceStates[$state], 0, 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hostStateBackground($text, $state = null)
|
||||||
|
{
|
||||||
|
if ($state === null) {
|
||||||
|
$state = $this->hostState;
|
||||||
|
}
|
||||||
|
return $this->screen->colorize(
|
||||||
|
$text,
|
||||||
|
$this->hostColors[$state][0],
|
||||||
|
$this->hostColors[$state][1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function serviceStateBackground($text, $state = null)
|
||||||
|
{
|
||||||
|
if ($state === null) {
|
||||||
|
$state = $this->serviceState;
|
||||||
|
}
|
||||||
|
return $this->screen->colorize(
|
||||||
|
$text,
|
||||||
|
$this->serviceColors[$state][0],
|
||||||
|
$this->serviceColors[$state][1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function objectStateFlags($type, & $row)
|
||||||
|
{
|
||||||
|
$extra = array();
|
||||||
|
if ($row->{$type . '_in_downtime'}) {
|
||||||
|
if ($this->screen->hasUtf8()) {
|
||||||
|
$extra[] = 'DOWNTIME ⌚';
|
||||||
|
} else {
|
||||||
|
$extra[] = 'DOWNTIME';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($row->{$type . '_acknowledged'}) {
|
||||||
|
if ($this->screen->hasUtf8()) {
|
||||||
|
$extra[] = 'ACK ✓';
|
||||||
|
} else {
|
||||||
|
$extra[] = 'ACK';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($extra)) {
|
||||||
|
$extra = '';
|
||||||
|
} else {
|
||||||
|
$extra = sprintf(' [ %s ]', implode(', ', $extra));
|
||||||
|
}
|
||||||
|
return $extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue