2015-07-22 10:12:50 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace Icinga\Module\Director\Import;
|
|
|
|
|
|
|
|
use Icinga\Module\Director\Objects\ImportSource;
|
2015-08-28 23:47:35 +02:00
|
|
|
use Icinga\Module\Director\Util;
|
2015-07-22 10:12:50 +02:00
|
|
|
use Icinga\Module\Director\Web\Hook\ImportSourceHook;
|
2015-10-21 07:45:08 +02:00
|
|
|
use Icinga\Exception\IcingaException;
|
2015-07-22 10:12:50 +02:00
|
|
|
|
|
|
|
class Import
|
|
|
|
{
|
|
|
|
protected $db;
|
|
|
|
|
|
|
|
protected function __construct()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function run(ImportSource $source)
|
|
|
|
{
|
|
|
|
$import = new self();
|
|
|
|
return $import->importFromSource($source);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function importFromSource(ImportSource $source)
|
|
|
|
{
|
|
|
|
$connection = $source->getConnection();
|
|
|
|
$this->db = $db = $connection->getDbAdapter();
|
|
|
|
|
|
|
|
$keyColumn = $source->key_column;
|
|
|
|
$rows = array();
|
|
|
|
$props = array();
|
|
|
|
$rowsProps = array();
|
|
|
|
|
|
|
|
foreach (ImportSourceHook::loadByName($source->source_name, $connection)->fetchData() as $row) {
|
|
|
|
// TODO: Check for name collision
|
|
|
|
if (! isset($row->$keyColumn)) {
|
2015-10-21 07:45:08 +02:00
|
|
|
// TODO: re-enable errors
|
|
|
|
continue;
|
|
|
|
throw new IcingaException(
|
|
|
|
'No key column "%s" in row: %s',
|
|
|
|
$keyColumn,
|
|
|
|
json_encode($row)
|
2015-07-26 15:38:29 +02:00
|
|
|
);
|
2015-07-22 10:12:50 +02:00
|
|
|
}
|
2015-07-26 15:38:29 +02:00
|
|
|
|
2015-07-22 10:12:50 +02:00
|
|
|
$object_name = $row->$keyColumn;
|
|
|
|
$rowChecksums = array();
|
|
|
|
$keys = array_keys((array) $row);
|
|
|
|
sort($keys);
|
|
|
|
|
|
|
|
foreach ($keys as $key) {
|
2015-07-24 15:26:09 +02:00
|
|
|
|
|
|
|
// TODO: Specify how to treat NULL values. Ignoring for now.
|
|
|
|
if ($row->$key === null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-08-28 23:53:56 +02:00
|
|
|
$pval = $row->$key;
|
|
|
|
if (is_array($pval)) {
|
|
|
|
$pval = json_encode($pval);
|
|
|
|
$format = 'json';
|
|
|
|
} else {
|
|
|
|
$format = 'string';
|
|
|
|
}
|
|
|
|
|
|
|
|
$checksum = sha1(sprintf('%s=(%s)%s', $key, $format, $pval), true);
|
2015-07-22 10:12:50 +02:00
|
|
|
|
|
|
|
if (! array_key_exists($checksum, $props)) {
|
|
|
|
$props[$checksum] = array(
|
|
|
|
'checksum' => $checksum,
|
|
|
|
'property_name' => $key,
|
2015-08-28 23:53:56 +02:00
|
|
|
'property_value' => $pval,
|
|
|
|
'format' => $format
|
2015-07-22 10:12:50 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$rowChecksums[] = $checksum;
|
|
|
|
}
|
|
|
|
|
|
|
|
$checksum = sha1($object_name . ';' . implode(';', $rowChecksums), true);
|
|
|
|
if (array_key_exists($checksum, $rows)) {
|
|
|
|
die('WTF, collision?');
|
|
|
|
}
|
|
|
|
|
|
|
|
$rows[$checksum] = array(
|
|
|
|
'checksum' => $checksum,
|
|
|
|
'object_name' => $object_name
|
|
|
|
);
|
|
|
|
|
|
|
|
$rowsProps[$checksum] = $rowChecksums;
|
|
|
|
}
|
|
|
|
|
|
|
|
$rowSums = array_keys($rows);
|
|
|
|
$rowset = sha1(implode(';', $rowSums), true);
|
|
|
|
|
2015-08-28 23:47:35 +02:00
|
|
|
if ($this->rowSetExists($rowset)) {
|
|
|
|
if ($connection->getLatestImportedChecksum($source->id) === Util::binary2hex($rowset)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-22 10:12:50 +02:00
|
|
|
$db->beginTransaction();
|
|
|
|
if (! $this->rowSetExists($rowset)) {
|
|
|
|
|
2015-08-29 01:10:56 +02:00
|
|
|
if (empty($rowSums)) {
|
|
|
|
$newRows = array();
|
|
|
|
} else {
|
|
|
|
$newRows = $this->newChecksums('imported_row', $rowSums);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (empty($rowSums)) {
|
|
|
|
$newProperties = array();
|
|
|
|
} else {
|
|
|
|
$newProperties = $this->newChecksums('imported_property', array_keys($props));
|
|
|
|
}
|
2015-07-22 10:12:50 +02:00
|
|
|
|
2015-07-22 13:13:00 +02:00
|
|
|
$db->insert('imported_rowset', array('checksum' => $rowset));
|
2015-07-22 10:12:50 +02:00
|
|
|
|
2015-07-22 13:13:00 +02:00
|
|
|
foreach ($newProperties as $checksum) {
|
|
|
|
$db->insert('imported_property', $props[$checksum]);
|
|
|
|
}
|
2015-07-22 10:12:50 +02:00
|
|
|
|
2015-07-22 13:13:00 +02:00
|
|
|
foreach ($newRows as $checksum) {
|
|
|
|
$db->insert('imported_row', $rows[$checksum]);
|
|
|
|
foreach ($rowsProps[$checksum] as $propChecksum) {
|
|
|
|
$db->insert('imported_row_property', array(
|
|
|
|
'row_checksum' => $checksum,
|
|
|
|
'property_checksum' => $propChecksum
|
|
|
|
));
|
2015-07-22 10:12:50 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-22 13:13:00 +02:00
|
|
|
|
|
|
|
foreach (array_keys($rows) as $checksum) {
|
|
|
|
$db->insert(
|
|
|
|
'imported_rowset_row',
|
|
|
|
array(
|
|
|
|
'rowset_checksum' => $rowset,
|
|
|
|
'row_checksum' => $checksum
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2015-07-22 10:12:50 +02:00
|
|
|
}
|
|
|
|
$db->insert(
|
|
|
|
'import_run',
|
|
|
|
array(
|
|
|
|
'source_id' => $source->id,
|
2015-07-22 11:13:52 +02:00
|
|
|
'rowset_checksum' => $rowset,
|
2015-07-22 10:12:50 +02:00
|
|
|
'start_time' => date('Y-m-d H:i:s'),
|
|
|
|
'succeeded' => 'y'
|
|
|
|
)
|
|
|
|
);
|
|
|
|
$id = $db->lastInsertId();
|
|
|
|
$db->commit();
|
|
|
|
|
|
|
|
return $id;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function rowSetExists($checksum)
|
|
|
|
{
|
|
|
|
return count($this->newChecksums('imported_rowset', array($checksum))) === 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function newChecksums($table, $checksums)
|
|
|
|
{
|
|
|
|
$db = $this->db;
|
|
|
|
|
|
|
|
$existing = $db->fetchCol(
|
|
|
|
$db->select()->from($table, 'checksum')->where('checksum IN (?)', $checksums)
|
|
|
|
);
|
|
|
|
|
|
|
|
return array_diff($checksums, $existing);
|
|
|
|
}
|
|
|
|
}
|