IcingaConfig: generate and store if modified

resolves #9434
This commit is contained in:
Alexander Fuhr 2015-06-17 19:03:23 +02:00
parent d7a816026f
commit a80c295314
2 changed files with 186 additions and 11 deletions

View File

@ -10,8 +10,35 @@ class IcingaConfig
{
protected $files = array();
protected function __construct()
protected $checksum;
protected $lastActivityChecksum;
/**
* @var \Zend_Db_Adapter_Abstract
*/
protected $db;
protected $connection;
protected $generationTime;
public static $table = 'director_generated_config';
protected function __construct(DbConnection $connection)
{
$this->connection = $connection;
$this->db = $connection->getDbAdapter();
}
public function getChecksum()
{
return $this->checksum;
}
public function getHexChecksum()
{
return current(unpack('H*', $this->checksum));
}
public function getFiles()
@ -19,15 +46,130 @@ class IcingaConfig
return $this->files;
}
public static function generate(DbConnection $db)
public function getFileNames()
{
$config = new static;
return $config->loadFromDb($db);
return array_keys($this->files);
}
protected function loadFromDb(DbConnection $db)
public function getMissingFiles($missing)
{
$this->db = $db;
$files = array();
foreach ($this->files as $name => $file) {
$files[] = $name . '=' . $file->getChecksum();
}
return $files;
}
public static function generate(DbConnection $connection)
{
$config = new static($connection);
return $config->storeIfModified();
}
protected function storeIfModified()
{
$this->generateFromDb();
$checksum = $this->calculateChecksum();
$exists = $this->db->fetchOne(
$this->db->select()->from(self::$table, 'COUNT(*)')->where('checksum = ?', $checksum)
);
if ((int) $exists === 0) {
$this->store();
}
return $this;
}
protected function calculateChecksum()
{
$files = array($this->getLastActivityHexChecksum());
$sortedFiles = $this->files;
ksort($sortedFiles);
/** @var IcingaConfigFile $file */
foreach ($sortedFiles as $name => $file) {
$files[] = $name . '=' . $file->getHexChecksum();
}
$this->checksum = sha1(implode(';', $files), true);
return $this->checksum;
}
public function getFilesChecksums()
{
$checksums = array();
/** @var IcingaConfigFile $file */
foreach ($this->files as $name => $file) {
$checksums[] = $file->getChecksum();
}
return $checksums;
}
protected function store()
{
$fileTable = IcingaConfigFile::$table;
$fileKey = IcingaConfigFile::$keyName;
$this->db->beginTransaction();
try {
$existingQuery = $this->db->select()
->from($fileTable, 'checksum')
->where('checksum IN (?)', $this->getFilesChecksums());
$existing = $this->db->fetchCol($existingQuery);
$missing = array_diff($this->getFilesChecksums(), $existing);
/** @var IcingaConfigFile $file */
foreach ($this->files as $name => $file) {
$checksum = $file->getChecksum();
if (! in_array($checksum, $missing)) {
continue;
}
$this->db->insert(
$fileTable,
array(
$fileKey => $checksum,
'content' => $file->getContent()
)
);
}
$this->db->insert(
self::$table,
array(
'duration' => $this->generationTime,
'last_activity_checksum' => $this->getLastActivityChecksum(),
'checksum' => $this->getChecksum(),
)
);
/** @var IcingaConfigFile $file */
foreach ($this->files as $name => $file) {
$this->db->insert(
'director_generated_config_file',
array(
'config_checksum' => $this->getChecksum(),
'file_checksum' => $file->getChecksum(),
'file_path' => $name,
)
);
}
$this->db->commit();
} catch (\Exception $e) {
$this->db->rollBack();
var_dump($e->getMessage());
}
return $this;
}
protected function generateFromDb()
{
$start = microtime(true);
$this
->createFileFromDb('zone')
->createFileFromDb('endpoint')
@ -40,18 +182,17 @@ class IcingaConfig
->createFileFromDb('user')
;
$this->generationTime = (microtime(true) - $start) * 1000;
return $this;
}
protected function createFileFromDb($type)
{
$class = 'Icinga\\Module\\Director\\Objects\\Icinga' . ucfirst($type);
$objects = $class::loadAll($this->db);
$objects = $class::loadAll($this->connection);
if (! empty($objects)) {
$class = 'Icinga\\Module\\Director\\IcingaConfig\\Icinga'
. ucfirst($type)
. 'sConfigFile';
$file = new IcingaConfigFile();
if ($type === 'command') {
$file->prepend("library \"methods\"\n\n");
@ -62,4 +203,30 @@ class IcingaConfig
return $this;
}
public function getLastActivityHexChecksum()
{
return current(unpack('H*', $this->getLastActivityChecksum()));
}
/**
* @return mixed
*/
public function getLastActivityChecksum()
{
if ($this->lastActivityChecksum === null) {
$query = $this->db->select()
->from('director_activity_log', 'checksum')
->order('change_time DESC')
->limit(1);
$this->lastActivityChecksum = $this->db->fetchOne($query);
}
return $this->lastActivityChecksum;
}
// TODO: wipe unused files
// DELETE f FROM director_generated_file f left join director_generated_config_file cf ON f.checksum = cf.file_checksum WHERE cf.file_checksum IS NULL;
}

View File

@ -6,6 +6,9 @@ use Icinga\Module\Director\Objects\IcingaObject;
class IcingaConfigFile
{
public static $table = 'director_generated_file';
public static $keyName = 'checksum';
protected $content;
public function prepend($content)
@ -19,11 +22,16 @@ class IcingaConfigFile
return $this->content;
}
public function getChecksum()
public function getHexChecksum()
{
return sha1($this->content);
}
public function getChecksum()
{
return sha1($this->content, true);
}
public function addObjects($objects)
{
foreach ($objects as $object) {