2016-04-22 09:53:59 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Icinga\Module\Director\Job;
|
|
|
|
|
|
|
|
use Icinga\Application\Benchmark;
|
2016-05-25 11:37:38 +02:00
|
|
|
use Icinga\Exception\IcingaException;
|
2016-04-22 09:53:59 +02:00
|
|
|
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
|
|
|
use Icinga\Module\Director\Hook\JobHook;
|
2016-05-25 11:37:38 +02:00
|
|
|
use Icinga\Module\Director\Objects\DirectorDeploymentLog;
|
2016-04-22 09:53:59 +02:00
|
|
|
use Icinga\Module\Director\Util;
|
2016-05-25 11:37:38 +02:00
|
|
|
use Icinga\Module\Director\Web\Form\QuickForm;
|
2016-04-22 09:53:59 +02:00
|
|
|
|
|
|
|
class ConfigJob extends JobHook
|
|
|
|
{
|
2016-05-25 11:37:38 +02:00
|
|
|
protected $lastDeployment;
|
|
|
|
|
|
|
|
protected $api;
|
|
|
|
|
2016-04-22 09:53:59 +02:00
|
|
|
public function run()
|
|
|
|
{
|
2016-05-25 11:37:38 +02:00
|
|
|
$db = $this->db();
|
|
|
|
|
|
|
|
if ($this->shouldGenerate()) {
|
|
|
|
$config = IcingaConfig::generate($db);
|
|
|
|
} else {
|
|
|
|
$config = $this->loadLatestActivityConfig();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->shouldDeploy($config)) {
|
|
|
|
$this->deploy($config);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function api()
|
|
|
|
{
|
|
|
|
if ($this->api === null) {
|
|
|
|
$this->api = $this->db()->getDeploymentEndpoint()->api();
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->api;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function loadLatestActivityConfig()
|
|
|
|
{
|
|
|
|
$db = $this->db();
|
|
|
|
|
|
|
|
return IcingaConfig::loadByActivityChecksum(
|
|
|
|
$db->getLastActivityChecksum(),
|
|
|
|
$db
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function shouldGenerate()
|
|
|
|
{
|
|
|
|
return $this->getSetting('force_generate')
|
|
|
|
// -> last config?!
|
|
|
|
|| $this->db()->countActivitiesSinceLastDeployedConfig() > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function shouldDeploy(IcingaConfig $config)
|
|
|
|
{
|
|
|
|
$db = $this->db();
|
|
|
|
|
|
|
|
if ($this->getSetting('deploy_when_changed') !== 'y') {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
$api = $this->api();
|
|
|
|
$api->collectLogFiles($db);
|
|
|
|
|
|
|
|
if (! DirectorDeploymentLog::hasDeployments($db)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->isWithinGracePeriod()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->lastDeployment()->configEquals($config)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// $current = $api->getActiveChecksum($db);
|
|
|
|
// TODO: no current, but last deployment
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function deploy(IcingaConfig $config)
|
|
|
|
{
|
|
|
|
$db = $this->db();
|
|
|
|
$api = $this->api();
|
|
|
|
$api->wipeInactiveStages($db);
|
|
|
|
|
|
|
|
$checksum = $config->getHexChecksum();
|
|
|
|
if ($api->dumpConfig($config, $db)) {
|
|
|
|
$this->printf("Config '%s' has been deployed\n", $checksum);
|
|
|
|
$api->collectLogFiles($db);
|
|
|
|
} else {
|
|
|
|
$this->fail(sprintf("Failed to deploy config '%s'\n", $checksum));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getGracePeriodStart()
|
|
|
|
{
|
|
|
|
return time() - $this->getSetting('grace_period');
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function isWithinGracePeriod()
|
|
|
|
{
|
|
|
|
if ($deployment = $this->lastDeployment()) {
|
|
|
|
return $deployment->getDeploymentTimestamp() > $this->getGracePeriodStart();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function lastDeployment()
|
|
|
|
{
|
|
|
|
if ($this->lastDeployment === null) {
|
|
|
|
$this->lastDeployment = DirectorDeploymentLog::loadLatest($this->db());
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this->lastDeployment;
|
2016-04-22 09:53:59 +02:00
|
|
|
}
|
|
|
|
|
2016-05-17 16:05:00 +02:00
|
|
|
public static function addSettingsFormFields(QuickForm $form)
|
|
|
|
{
|
2016-05-25 11:37:38 +02:00
|
|
|
$form->addElement('select', 'force_generate', array(
|
|
|
|
'label' => $form->translate('Force rendering'),
|
|
|
|
'description' => $form->translate(
|
|
|
|
'Whether rendering should be forced. If not enforced, this'
|
|
|
|
. ' job re-renders the configuration only when there have been'
|
|
|
|
. ' activities since the last rendered config'
|
|
|
|
),
|
|
|
|
'value' => 'n',
|
|
|
|
'multiOptions' => array(
|
|
|
|
'y' => $form->translate('Yes'),
|
|
|
|
'n' => $form->translate('No'),
|
|
|
|
)
|
|
|
|
));
|
|
|
|
|
2016-05-17 16:05:00 +02:00
|
|
|
$form->addElement('select', 'deploy_when_changed', array(
|
|
|
|
'label' => $form->translate('Deploy modified config'),
|
|
|
|
'description' => $form->translate(
|
|
|
|
'This allows you to immediately deploy a modified configuration'
|
|
|
|
),
|
|
|
|
'value' => 'n',
|
|
|
|
'multiOptions' => array(
|
|
|
|
'y' => $form->translate('Yes'),
|
|
|
|
'n' => $form->translate('No'),
|
|
|
|
)
|
|
|
|
));
|
|
|
|
|
2016-05-25 11:37:38 +02:00
|
|
|
$form->addElement('text', 'grace_period', array(
|
|
|
|
'label' => $form->translate('Grace period'),
|
|
|
|
'description' => $form->translate(
|
|
|
|
'When deploying configuration, wait at least this amount of'
|
|
|
|
. ' seconds unless the next deployment should take place'
|
|
|
|
),
|
|
|
|
'value' => 600,
|
|
|
|
));
|
2016-05-17 16:05:00 +02:00
|
|
|
|
2016-05-25 11:37:38 +02:00
|
|
|
return $form;
|
2016-04-22 09:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public static function getDescription(QuickForm $form)
|
|
|
|
{
|
|
|
|
return $form->translate(
|
2016-05-17 16:05:00 +02:00
|
|
|
'The Config job allows you to generate and eventually deploy your'
|
|
|
|
. 'Icinga 2 configuration'
|
2016-04-22 09:53:59 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Re-render the current configuration
|
|
|
|
*/
|
2016-05-25 11:37:38 +02:00
|
|
|
public function renderConfig()
|
2016-04-22 09:53:59 +02:00
|
|
|
{
|
|
|
|
$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();
|
|
|
|
$this->printf(
|
|
|
|
"New config with checksum %s has been generated\n",
|
|
|
|
$checksum
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$checksum = $config->getHexChecksum();
|
|
|
|
$this->printf(
|
|
|
|
"Config with checksum %s already exists\n",
|
|
|
|
$checksum
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deploy the current configuration
|
|
|
|
*
|
|
|
|
* Does nothing if config didn't change unless you provide
|
|
|
|
* the --force parameter
|
|
|
|
*/
|
|
|
|
public function deployAction()
|
|
|
|
{
|
|
|
|
$api = $this->api();
|
|
|
|
$db = $this->db();
|
|
|
|
|
|
|
|
$checksum = $this->params->get('checksum');
|
|
|
|
if ($checksum) {
|
|
|
|
$config = IcingaConfig::load(Util::hex2binary($checksum), $db);
|
|
|
|
} else {
|
|
|
|
$config = IcingaConfig::generate($db);
|
|
|
|
$checksum = $config->getHexChecksum();
|
|
|
|
}
|
|
|
|
|
|
|
|
$api->wipeInactiveStages($db);
|
|
|
|
$current = $api->getActiveChecksum($db);
|
|
|
|
if ($current === $checksum) {
|
|
|
|
if ($this->params->get('force')) {
|
|
|
|
echo "Config matches active stage, deploying anyway\n";
|
|
|
|
} else {
|
|
|
|
echo "Config matches active stage, nothing to do\n";
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if ($api->dumpConfig($config, $db)) {
|
|
|
|
$this->printf("Config '%s' has been deployed\n", $checksum);
|
|
|
|
} else {
|
|
|
|
$this->fail(
|
|
|
|
sprintf("Failed to deploy config '%s'\n", $checksum)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|