1<?php 2/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */ 3 4namespace Icinga\Application; 5 6use Icinga\Application\Platform; 7use Icinga\Application\ApplicationBootstrap; 8use Icinga\Authentication\Auth; 9use Icinga\Cli\Params; 10use Icinga\Cli\Loader; 11use Icinga\Cli\Screen; 12use Icinga\Application\Logger; 13use Icinga\Application\Benchmark; 14use Icinga\Data\ConfigObject; 15use Icinga\Exception\ProgrammingError; 16use Icinga\User; 17 18require_once __DIR__ . '/ApplicationBootstrap.php'; 19 20class Cli extends ApplicationBootstrap 21{ 22 protected $isCli = true; 23 24 protected $params; 25 26 protected $showBenchmark = false; 27 28 protected $watchTimeout; 29 30 protected $cliLoader; 31 32 protected $verbose; 33 34 protected $debug; 35 36 protected function bootstrap() 37 { 38 $this->assertRunningOnCli(); 39 $this->setupLogging() 40 ->setupErrorHandling() 41 ->loadConfig() 42 ->setupTimezone() 43 ->setupInternationalization() 44 ->parseBasicParams() 45 ->setupLogger() 46 ->setupModuleManager() 47 ->setupUserBackendFactory() 48 ->loadSetupModuleIfNecessary() 49 ->setupFakeAuthentication(); 50 } 51 52 /** 53 * {@inheritdoc} 54 */ 55 protected function setupLogging() 56 { 57 Logger::create( 58 new ConfigObject( 59 array( 60 'log' => 'stderr' 61 ) 62 ) 63 ); 64 65 return $this; 66 } 67 68 /** 69 * {@inheritdoc} 70 */ 71 protected function setupLogger() 72 { 73 $config = new ConfigObject(); 74 $config->log = $this->params->shift('log', 'stderr'); 75 if ($config->log === 'file') { 76 $config->file = $this->params->shiftRequired('log-path'); 77 } elseif ($config->log === 'syslog') { 78 $config->application = 'icingacli'; 79 } 80 81 if ($this->params->get('verbose', false)) { 82 $config->level = Logger::INFO; 83 } elseif ($this->params->get('debug', false)) { 84 $config->level = Logger::DEBUG; 85 } else { 86 $config->level = Logger::WARNING; 87 } 88 89 Logger::create($config); 90 return $this; 91 } 92 93 protected function setupFakeAuthentication() 94 { 95 Auth::getInstance()->setUser(new User('cli')); 96 97 return $this; 98 } 99 100 public function cliLoader() 101 { 102 if ($this->cliLoader === null) { 103 $this->cliLoader = new Loader($this); 104 } 105 return $this->cliLoader; 106 } 107 108 protected function parseBasicParams() 109 { 110 $this->params = Params::parse(); 111 if ($this->params->shift('help')) { 112 $this->params->unshift('help'); 113 } 114 if ($this->params->shift('version')) { 115 $this->params->unshift('version'); 116 } 117 if ($this->params->shift('autocomplete')) { 118 $this->params->unshift('autocomplete'); 119 } 120 $watch = $this->params->shift('watch'); 121 if ($watch === true) { 122 $watch = 5; 123 } 124 if (preg_match('~^\d+$~', $watch)) { 125 $this->watchTimeout = (int) $watch; 126 } 127 128 $this->debug = (int) $this->params->get('debug'); 129 $this->verbose = (int) $this->params->get('verbose'); 130 131 $this->showBenchmark = (bool) $this->params->shift('benchmark'); 132 return $this; 133 } 134 135 public function getParams() 136 { 137 return $this->params; 138 } 139 140 public function dispatchModule($name, $basedir = null) 141 { 142 $this->getModuleManager()->loadModule($name, $basedir); 143 $this->cliLoader()->setModuleName($name); 144 $this->dispatch(); 145 } 146 147 public function dispatch() 148 { 149 Benchmark::measure('Dispatching CLI command'); 150 151 if ($this->watchTimeout === null) { 152 $this->dispatchOnce(); 153 } else { 154 $this->dispatchEndless(); 155 } 156 } 157 158 protected function dispatchOnce() 159 { 160 $loader = $this->cliLoader(); 161 $loader->parseParams(); 162 $result = $loader->dispatch(); 163 Benchmark::measure('All done'); 164 if ($this->showBenchmark) { 165 Benchmark::dump(); 166 } 167 if ($result === false) { 168 exit(3); 169 } 170 } 171 172 protected function dispatchEndless() 173 { 174 $loader = $this->cliLoader(); 175 $loader->parseParams(); 176 $screen = Screen::instance(); 177 178 while (true) { 179 Benchmark::measure('Watch mode - loop begins'); 180 ob_start(); 181 $params = clone($this->params); 182 $loader->dispatch($params); 183 Benchmark::measure('Dispatch done'); 184 if ($this->showBenchmark) { 185 Benchmark::dump(); 186 } 187 Benchmark::reset(); 188 $out = ob_get_contents(); 189 ob_end_clean(); 190 echo $screen->clear() . $out; 191 sleep($this->watchTimeout); 192 } 193 } 194 195 /** 196 * Fail if Icinga has not been called on CLI 197 * 198 * @throws ProgrammingError 199 * @return void 200 */ 201 private function assertRunningOnCli() 202 { 203 if (Platform::isCli()) { 204 return; 205 } 206 throw new ProgrammingError('Icinga is not running on CLI'); 207 } 208} 209