Skip to content

Commit

Permalink
Merge branch 'feature/mandatory-daemon'
Browse files Browse the repository at this point in the history
fixes #1905
  • Loading branch information
Thomas-Gelf committed Sep 25, 2019
2 parents 7f79842 + 4ee3ef2 commit 7dbdb23
Show file tree
Hide file tree
Showing 39 changed files with 2,228 additions and 200 deletions.
26 changes: 26 additions & 0 deletions application/clicommands/DaemonCommand.php
Original file line number Diff line number Diff line change
@@ -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();
}
}
110 changes: 52 additions & 58 deletions application/clicommands/JobsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,78 +2,72 @@

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\Job\JobRunner;
use Icinga\Module\Director\Daemon\JsonRpcLogWriter as JsonRpcLogWriterAlias;
use Icinga\Module\Director\Daemon\Logger;
use Icinga\Module\Director\Objects\DirectorJob;
use Icinga\Application\Logger;
use Exception;
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()
{
$forever = $this->params->shift('forever');
if (! $forever && $this->params->getStandalone() === 'forever') {
$forever = true;
$this->params->shift();
$loop = Loop::create();
if ($this->params->get('rpc')) {
$this->enableRpc($loop);
}

$jobId = $this->params->shift();
if ($jobId) {
$this->raiseLimits();
$job = DirectorJob::loadWithAutoIncId($jobId, $this->db());
$job->run();
exit(0);
}

if ($forever) {
$this->runforever();
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 {
$this->runAllPendingJobs();
Logger::error('This command is no longer available. Please check our Upgrading documentation');
$exitCode = 1;
}
}

protected function runforever()
{
// We'll terminate ourselves after 24h for now:
$runUnless = time() + 86400;

// We'll exit in case more than 100MB of memory are still in use
// after the last job execution:
$maxMem = 100 * 1024 * 1024;

while (true) {
$this->runAllPendingJobs();
if (memory_get_usage() > $maxMem) {
exit(0);
}

if (time() > $runUnless) {
exit(0);
}

sleep(2);
}
$loop->run();
exit($exitCode);
}

protected function runAllPendingJobs()
protected function enableRpc(LoopInterface $loop)
{
$jobs = new JobRunner($this->db());

try {
if ($this->hasBeenDisabled()) {
return;
}
// 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);

$jobs->runPendingJobs();
} catch (Exception $e) {
Logger::error('Director Job Error: ' . $e->getMessage());
sleep(10);
}
}

protected function hasBeenDisabled()
{
return $this->db()->settings()->disable_all_jobs === 'y';
Logger::replaceRunningInstance(new JsonRpcLogWriterAlias($jsonRpc));
}
}
59 changes: 59 additions & 0 deletions application/controllers/DaemonController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace Icinga\Module\Director\Controllers;

use Icinga\Application\Icinga;
use Icinga\Module\Director\Daemon\RunningDaemonInfo;
use Icinga\Module\Director\Web\Tabs\MainTabs;
use Icinga\Module\Director\Web\Controller\ActionController;
use Icinga\Module\Director\Web\Widget\BackgroundDaemonDetails;
use Icinga\Module\Director\Web\Widget\Documentation;
use ipl\Html\Html;

class DaemonController extends ActionController
{
public function indexAction()
{
$this->setAutorefreshInterval(10);
$this->tabs(new MainTabs($this->Auth(), $this->getDbResourceName()))->activate('daemon');
$this->setTitle($this->translate('Director Background Daemon'));
// Avoiding layout issues:
$this->content()->add(Html::tag('h1', $this->translate('Director Background Daemon')));
// TODO: move dashboard titles into controls. Or figure out whether 2.7 "broke" this

$error = null;
try {
$db = $this->db()->getDbAdapter();
$daemons = $db->fetchAll(
$db->select()->from('director_daemon_info')->order('fqdn')->order('username')->order('pid')
);
} catch (\Exception $e) {
$daemons = [];
$error = $e->getMessage();
}

if (empty($daemons)) {
$documentation = new Documentation(Icinga::app(), $this->Auth());
$message = Html::sprintf($this->translate(
'The Icinga Director Background Daemon is not running.'
. ' Please check our %s in case you need step by step instructions'
. ' showing you how to fix this.'
), $documentation->getModuleLink(
$this->translate('documentation'),
'director',
'75-Background-Daemon',
$this->translate('Icinga Director Background Daemon')
));
$this->content()->add(Html::tag('p', ['class' => 'state-hint error'], [
$message,
($error ? [Html::tag('br'), Html::tag('strong', $error)] : ''),
]));
return;
}

foreach ($daemons as $daemon) {
$info = new RunningDaemonInfo($daemon);
$this->content()->add([new BackgroundDaemonDetails($info, $daemon) /*, $logWindow*/]);
}
}
}
30 changes: 2 additions & 28 deletions application/controllers/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Icinga\Module\Director\Controllers;

use Icinga\Module\Director\Web\Tabs\MainTabs;
use Icinga\Module\Director\Web\Widget\HealthCheckPluginOutput;
use Icinga\Module\Director\Dashboard\Dashboard;
use Icinga\Module\Director\Health;
Expand Down Expand Up @@ -45,22 +46,7 @@ public function indexAction()
$dashboard = Dashboard::loadByName($name, $this->db());
$this->tabs($dashboard->getTabs())->activate($name);
} else {
$this->tabs()->add('main', [
'label' => $this->translate('Overview'),
'url' => 'director'
])->activate('main');
if ($this->hasPermission('director/admin')) {
$this->tabs()->add('health', [
'label' => $this->translate('Health'),
'url' => 'director/health'
]);
$state = $this->getHealthState();
if ($state->isProblem()) {
$this->tabs()->get('health')->setTagParams([
'class' => 'state-' . strtolower($state->getName())
]);
}
}
$this->tabs(new MainTabs($this->Auth(), $this->getDbResourceName()))->activate('main');
}

$cntDashboards = 0;
Expand All @@ -83,16 +69,4 @@ public function indexAction()
$this->content()->add($msg);
}
}

/**
* @return \Icinga\Module\Director\CheckPlugin\PluginState
*/
protected function getHealthState()
{
$health = new Health();
$health->setDbResourceName($this->getDbResourceName());
$output = new HealthCheckPluginOutput($health);

return $output->getState();
}
}
10 changes: 2 additions & 8 deletions application/controllers/HealthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Icinga\Module\Director\Controllers;

use Icinga\Module\Director\Web\Tabs\MainTabs;
use ipl\Html\Html;
use Icinga\Module\Director\Web\Widget\HealthCheckPluginOutput;
use Icinga\Module\Director\Health;
Expand All @@ -12,14 +13,7 @@ class HealthController extends ActionController
public function indexAction()
{
$this->setAutorefreshInterval(10);
$this->tabs()->add('main', [
'label' => $this->translate('Overview'),
'url' => 'director'
])->add('health', [
'label' => $this->translate('Health'),
'url' => 'director/health'
])->activate('health');

$this->tabs(new MainTabs($this->Auth(), $this->getDbResourceName()))->activate('health');
$this->setTitle($this->translate('Director Health'));
$health = new Health();
$health->setDbResourceName($this->getDbResourceName());
Expand Down
9 changes: 5 additions & 4 deletions application/controllers/ImportsourceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Icinga\Module\Director\Controllers;

use Icinga\Exception\NotFoundError;
use Icinga\Module\Director\Forms\ImportRowModifierForm;
use Icinga\Module\Director\Forms\ImportSourceForm;
use Icinga\Module\Director\Web\ActionBar\AutomationObjectActionBar;
Expand Down Expand Up @@ -44,6 +43,9 @@ public function init()
}
}

/**
* @throws \Icinga\Exception\NotFoundError
*/
protected function addMainActions()
{
$this->actions(new AutomationObjectActionBar(
Expand All @@ -66,7 +68,6 @@ protected function addMainActions()
}

/**
* @throws \Icinga\Exception\IcingaException
* @throws \Icinga\Exception\NotFoundError
*/
public function indexAction()
Expand Down Expand Up @@ -95,7 +96,7 @@ public function addAction()
}

/**
* @throws NotFoundError
* @throws \Icinga\Exception\NotFoundError
*/
public function editAction()
{
Expand Down Expand Up @@ -239,7 +240,7 @@ public function editmodifierAction()

/**
* @return ImportSource
* @throws NotFoundError
* @throws \Icinga\Exception\NotFoundError
*/
protected function getImportSource()
{
Expand Down
1 change: 1 addition & 0 deletions application/controllers/JobController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class JobController extends ActionController
*/
public function indexAction()
{
$this->setAutorefreshInterval(10);
$job = $this->requireJob();
$this
->addJobTabs($job, 'show')
Expand Down
8 changes: 4 additions & 4 deletions application/controllers/SyncruleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,15 @@ protected function addPropertyHint(SyncRule $rule)
*/
protected function warning($msg)
{
$this->content()->add(Html::tag('p', ['class' => 'warning'], $msg));
$this->content()->add(Html::tag('p', ['class' => 'state-hint warning'], $msg));
}

/**
* @param $msg
*/
protected function error($msg)
{
$this->content()->add(Html::tag('p', ['class' => 'error'], $msg));
$this->content()->add(Html::tag('p', ['class' => 'state-hint error'], $msg));
}

/**
Expand All @@ -165,7 +165,7 @@ public function previewAction()
} catch (\Exception $e) {
$this->content()->add(
Html::tag('p', [
'class' => 'error'
'class' => 'state-hint error'
], $e->getMessage())
);

Expand All @@ -174,7 +174,7 @@ public function previewAction()

if (empty($modifications)) {
$this->content()->add(Html::tag('p', [
'class' => 'information'
'class' => 'state-hint ok'
], $this->translate('This Sync Rule is in sync and would currently not apply any changes')));

return;
Expand Down
Loading

0 comments on commit 7dbdb23

Please sign in to comment.