mirror of
https://github.com/Icinga/icingaweb2-module-director.git
synced 2025-07-29 16:54:06 +02:00
config/diff: add full config diff capability
This commit is contained in:
parent
2ab802dcdb
commit
cfaa546c50
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use Icinga\Module\Director\ConfigDiff;
|
||||
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
||||
use Icinga\Module\Director\Util;
|
||||
use Icinga\Module\Director\Web\Controller\ActionController;
|
||||
@ -173,6 +174,56 @@ class ConfigController extends ActionController
|
||||
);
|
||||
}
|
||||
|
||||
public function diffAction()
|
||||
{
|
||||
$db = $this->db();
|
||||
$this->view->title = $this->translate('Config diff');
|
||||
|
||||
$tabs = $this->getTabs()->add('diff', array(
|
||||
'label' => $this->translate('Config diff'),
|
||||
'url' => $this->getRequest()->getUrl()
|
||||
))->activate('diff');
|
||||
|
||||
$leftSum = $this->view->leftSum = $this->params->get('left');
|
||||
$rightSum = $this->view->rightSum = $this->params->get('right');
|
||||
$left = IcingaConfig::load(Util::hex2binary($leftSum), $db);
|
||||
|
||||
$this->view->configs = $db->enumDeployedConfigs();
|
||||
if ($rightSum === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$right = IcingaConfig::load(Util::hex2binary($rightSum), $db);
|
||||
$this->view->table = $this
|
||||
->loadTable('ConfigFileDiff')
|
||||
->setConnection($this->db())
|
||||
->setLeftChecksum($leftSum)
|
||||
->setRightChecksum($rightSum);
|
||||
}
|
||||
|
||||
public function filediffAction()
|
||||
{
|
||||
$db = $this->db();
|
||||
$leftSum = $this->params->get('left');
|
||||
$rightSum = $this->params->get('right');
|
||||
$filename = $this->view->filename = $this->params->get('file_path');
|
||||
|
||||
$left = IcingaConfig::load(Util::hex2binary($leftSum), $db);
|
||||
$right = IcingaConfig::load(Util::hex2binary($rightSum), $db);
|
||||
|
||||
$leftFile = $left->getFile($filename);
|
||||
$rightFile = $right->getFile($filename);
|
||||
|
||||
$d = ConfigDiff::create($leftFile, $rightFile);
|
||||
|
||||
$this->view->title = sprintf(
|
||||
$this->translate('Config file "%s"'),
|
||||
$filename
|
||||
);
|
||||
|
||||
$this->view->output = $d->renderHtml();
|
||||
}
|
||||
|
||||
protected function overviewTabs()
|
||||
{
|
||||
$this->view->tabs = $this->getTabs()->add(
|
||||
|
151
application/tables/ConfigFileDiffTable.php
Normal file
151
application/tables/ConfigFileDiffTable.php
Normal file
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\Tables;
|
||||
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Module\Director\Web\Table\QuickTable;
|
||||
use Icinga\Module\Director\Util;
|
||||
|
||||
class ConfigFileDiffTable extends QuickTable
|
||||
{
|
||||
protected $leftChecksum;
|
||||
|
||||
protected $rightChecksum;
|
||||
|
||||
public function getColumns()
|
||||
{
|
||||
throw new ProgrammingError('Accessing getColumns() is not supported');
|
||||
}
|
||||
|
||||
protected function listTableClasses()
|
||||
{
|
||||
return array_merge(array('config-diff'), parent::listTableClasses());
|
||||
}
|
||||
|
||||
protected function getRowClasses($row)
|
||||
{
|
||||
return 'file-' . $row->file_action;
|
||||
}
|
||||
|
||||
protected function getActionUrl($row)
|
||||
{
|
||||
$params = array('file_path' => $row->file_path);
|
||||
|
||||
if ($row->file_checksum_left === $row->file_checksum_right) {
|
||||
$params['config_checksum'] = $row->config_checksum_right;
|
||||
} elseif ($row->file_checksum_left === null) {
|
||||
$params['config_checksum'] = $row->config_checksum_right;
|
||||
} elseif ($row->file_checksum_right === null) {
|
||||
$params['config_checksum'] = $row->config_checksum_left;
|
||||
} else {
|
||||
$params['left'] = $row->config_checksum_left;
|
||||
$params['right'] = $row->config_checksum_right;
|
||||
return $this->url('director/config/filediff', $params);
|
||||
}
|
||||
|
||||
return $this->url('director/config/file', $params);
|
||||
}
|
||||
|
||||
public function setLeftChecksum($checksum)
|
||||
{
|
||||
$this->leftChecksum = $checksum;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRightChecksum($checksum)
|
||||
{
|
||||
$this->rightChecksum = $checksum;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTitles()
|
||||
{
|
||||
$view = $this->view();
|
||||
return array(
|
||||
'file_action' => $view->translate('Action'),
|
||||
'file_path' => $view->translate('File'),
|
||||
);
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
$db = $this->connection()->getConnection();
|
||||
$query = clone($this->getBaseQuery());
|
||||
$query->reset('order');
|
||||
$this->applyFiltersToQuery($query);
|
||||
return $db->fetchOne($db->select()->from(
|
||||
array('cntsub' => $query),
|
||||
array('cnt' => 'COUNT(*)')
|
||||
));
|
||||
}
|
||||
|
||||
public function fetchData()
|
||||
{
|
||||
$db = $this->connection()->getConnection();
|
||||
$query = $this->getBaseQuery();
|
||||
|
||||
if ($this->hasLimit() || $this->hasOffset()) {
|
||||
$query->limit($this->getLimit(), $this->getOffset());
|
||||
}
|
||||
|
||||
$this->applyFiltersToQuery($query);
|
||||
|
||||
return $db->fetchAll($query);
|
||||
}
|
||||
|
||||
public function getBaseQuery()
|
||||
{
|
||||
$conn = $this->connection();
|
||||
$db = $conn->getConnection();
|
||||
|
||||
$left = $db->select()
|
||||
->from(
|
||||
array('cfl' => 'director_generated_config_file'),
|
||||
array(
|
||||
'file_path' => 'COALESCE(cfl.file_path, cfr.file_path)',
|
||||
'config_checksum_left' => $conn->dbHexFunc('cfl.config_checksum'),
|
||||
'config_checksum_right' => $conn->dbHexFunc('cfr.config_checksum'),
|
||||
'file_checksum_left' => $conn->dbHexFunc('cfl.file_checksum'),
|
||||
'file_checksum_right' => $conn->dbHexFunc('cfr.file_checksum'),
|
||||
'file_action' => '(CASE WHEN cfr.config_checksum IS NULL'
|
||||
. " THEN 'removed' WHEN cfl.file_checksum = cfr.file_checksum"
|
||||
. " THEN 'unmodified' ELSE 'modified' END)",
|
||||
)
|
||||
)->joinLeft(
|
||||
array('cfr' => 'director_generated_config_file'),
|
||||
$db->quoteInto(
|
||||
'cfl.file_path = cfr.file_path AND cfr.config_checksum = ?',
|
||||
$conn->quoteBinary(Util::hex2binary($this->rightChecksum))
|
||||
),
|
||||
array()
|
||||
)->where(
|
||||
'cfl.config_checksum = ?',
|
||||
$conn->quoteBinary(Util::hex2binary($this->leftChecksum))
|
||||
);
|
||||
|
||||
$right = $db->select()
|
||||
->from(
|
||||
array('cfl' => 'director_generated_config_file'),
|
||||
array(
|
||||
'file_path' => 'COALESCE(cfr.file_path, cfl.file_path)',
|
||||
'config_checksum_left' => $conn->dbHexFunc('cfl.config_checksum'),
|
||||
'config_checksum_right' => $conn->dbHexFunc('cfr.config_checksum'),
|
||||
'file_checksum_left' => $conn->dbHexFunc('cfl.file_checksum'),
|
||||
'file_checksum_right' => $conn->dbHexFunc('cfr.file_checksum'),
|
||||
'file_action' => "('created')",
|
||||
)
|
||||
)->joinRight(
|
||||
array('cfr' => 'director_generated_config_file'),
|
||||
$db->quoteInto(
|
||||
'cfl.file_path = cfr.file_path AND cfl.config_checksum = ?',
|
||||
$conn->quoteBinary(Util::hex2binary($this->leftChecksum))
|
||||
),
|
||||
array()
|
||||
)->where(
|
||||
'cfr.config_checksum = ?',
|
||||
$conn->quoteBinary(Util::hex2binary($this->rightChecksum))
|
||||
)->where('cfl.file_checksum IS NULL');
|
||||
|
||||
return $db->select()->union(array($left, $right))->order('file_path');
|
||||
}
|
||||
}
|
31
application/views/scripts/config/diff.phtml
Normal file
31
application/views/scripts/config/diff.phtml
Normal file
@ -0,0 +1,31 @@
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<h1><?= $this->escape($this->title) ?></h1>
|
||||
<span class="action-links" data-base-target="_next">
|
||||
<?= $this->addLink ?>
|
||||
</span>
|
||||
<form action="<?= $this->url ?>" method="GET">
|
||||
<?= $this->formSelect(
|
||||
'left',
|
||||
$this->leftSum,
|
||||
array('class' => 'autosubmit'),
|
||||
array(null => $this->translate('- please choose -')) + $this->configs
|
||||
)
|
||||
?>
|
||||
<?= $this->formSelect(
|
||||
'right',
|
||||
$this->rightSum,
|
||||
array('class' => 'autosubmit'),
|
||||
array(null => $this->translate('- please choose -')) + $this->configs
|
||||
)
|
||||
?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="content" data-base-target="_next">
|
||||
<?php if (count($this->table)): ?>
|
||||
<div>
|
||||
<?= $this->table->render() ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
11
application/views/scripts/config/filediff.phtml
Normal file
11
application/views/scripts/config/filediff.phtml
Normal file
@ -0,0 +1,11 @@
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<h1><?= $this->escape($this->title) ?></h1>
|
||||
<span class="action-links" data-base-target="_next">
|
||||
<?= $this->addLink ?>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="content" data-base-target="_next">
|
||||
<?= $this->output ?>
|
||||
</div>
|
@ -975,6 +975,50 @@ table.activity-log {
|
||||
}
|
||||
}
|
||||
|
||||
table.config-diff {
|
||||
|
||||
tr th:first-child {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
tr td:first-child {
|
||||
padding-left: 2em;
|
||||
&::before {
|
||||
font-family: 'ifont';
|
||||
// icon-help:
|
||||
content: '\e85b';
|
||||
float: left;
|
||||
font-weight: bold;
|
||||
margin-left: -1.5em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
tr.file-unmodified td:first-child::before {
|
||||
// icon-ok
|
||||
color: @color-ok;
|
||||
content: '\e803';
|
||||
}
|
||||
|
||||
tr.file-created td:first-child::before {
|
||||
// icon-plus
|
||||
color: @color-pending;
|
||||
content: '\e805';
|
||||
}
|
||||
|
||||
tr.file-removed td:first-child::before {
|
||||
// icon-cancel
|
||||
color: @color-critical;
|
||||
content: '\e804';
|
||||
}
|
||||
|
||||
tr.file-modified td:first-child::before {
|
||||
// icon-flapping
|
||||
color: @color-warning;
|
||||
content: '\e85d';
|
||||
}
|
||||
}
|
||||
|
||||
.tree li a {
|
||||
display: inline-block;
|
||||
padding-left: 2.4em;
|
||||
|
Loading…
x
Reference in New Issue
Block a user