schema: add UUIDs for datalist and datafield

fixes #2696
This commit is contained in:
Thomas Gelf 2023-03-07 18:29:30 +01:00
parent 6c611a5db4
commit b7e887b251
6 changed files with 89 additions and 54 deletions

View File

@ -2,28 +2,30 @@
namespace Icinga\Module\Director\Objects;
use gipfl\Json\JsonString;
use Icinga\Module\Director\Core\Json;
use Icinga\Module\Director\Data\Db\DbObjectWithSettings;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\DirectorObject\Automation\CompareBasketObject;
use Icinga\Module\Director\Exception\DuplicateKeyException;
use Icinga\Module\Director\Exception\JsonEncodeException;
use Icinga\Module\Director\Forms\IcingaServiceForm;
use Icinga\Module\Director\Hook\DataTypeHook;
use Icinga\Module\Director\Resolver\OverriddenVarsResolver;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
use InvalidArgumentException;
use Ramsey\Uuid\Uuid;
use stdClass;
use Zend_Form_Element as ZfElement;
class DirectorDatafield extends DbObjectWithSettings
{
protected $table = 'director_datafield';
protected $keyName = 'id';
protected $autoincKeyName = 'id';
protected $uuidColumn = 'uuid';
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'category_id' => null,
'varname' => null,
'caption' => null,
@ -124,8 +126,10 @@ class DirectorDatafield extends DbObjectWithSettings
public function export()
{
$plain = (object) $this->getProperties();
$plain->originalId = $plain->id;
unset($plain->id);
if ($uuid = $this->get('uuid')) {
$plain->uuid = Uuid::fromBytes($uuid)->toString();
}
$plain->settings = (object) $this->getSettings();
if (property_exists($plain->settings, 'datalist_id')) {
@ -144,63 +148,44 @@ class DirectorDatafield extends DbObjectWithSettings
}
/**
* @param $plain
* @param Db $db
* @param bool $replace
* @return DirectorDatafield
* @throws \Icinga\Exception\NotFoundError
* @throws JsonEncodeException
*/
public static function import($plain, Db $db, $replace = false)
public static function import(stdClass $plain, Db $db): DirectorDatafield
{
$properties = (array) $plain;
if (isset($properties['originalId'])) {
$id = $properties['originalId'];
unset($properties['originalId']);
} else {
$id = null;
}
if (isset($properties['settings']->datalist)) {
// Just try to load the list, import should fail if missing
$list = DirectorDatalist::load(
$properties['settings']->datalist,
$db
);
} else {
$list = null;
}
$compare = Json::decode(Json::encode($properties));
if ($id && static::exists($id, $db)) {
$existing = static::loadWithAutoIncId($id, $db);
$existingProperties = (array) $existing->export();
unset($existingProperties['originalId']);
if (CompareBasketObject::equals((object) $compare, (object) $existingProperties)) {
return $existing;
$dba = $db->getDbAdapter();
if ($uuid = $plain->uuid ?? null) {
$uuid = Uuid::fromString($uuid);
if ($candidate = DirectorDatafield::loadWithUniqueId($uuid, $db)) {
self::fixOptionalDatalistReference($plain, $db);
assert($candidate instanceof DirectorDatafield);
$candidate->setProperties((array) $plain);
return $candidate;
}
}
if ($list) {
unset($properties['settings']->datalist);
$properties['settings']->datalist_id = $list->get('id');
}
$dba = $db->getDbAdapter();
$query = $dba->select()
->from('director_datafield')
->where('varname = ?', $plain->varname);
$query = $dba->select()->from('director_datafield')->where('varname = ?', $plain->varname);
$candidates = DirectorDatafield::loadAll($db, $query);
foreach ($candidates as $candidate) {
$export = $candidate->export();
unset($export->originalId);
CompareBasketObject::normalize($export);
if (CompareBasketObject::equals($export, $compare)) {
if (CompareBasketObject::equals($export, $plain)) {
return $candidate;
}
}
self::fixOptionalDatalistReference($plain, $db);
return static::create($properties, $db);
return static::create((array) $plain, $db);
}
protected static function fixOptionalDatalistReference(stdClass $plain, Db $db)
{
if (isset($plain->settings->datalist)) {
// Just try to load the list, import should fail if missing
$list = DirectorDatalist::load($plain->settings->datalist, $db);
unset($plain->settings->datalist);
$plain->settings->datalist_id = $list->get('id');
}
}
protected function beforeStore()

View File

@ -11,16 +11,16 @@ use Icinga\Module\Director\Exception\DuplicateKeyException;
class DirectorDatalist extends DbObject implements ExportInterface
{
protected $table = 'director_datalist';
protected $keyName = 'list_name';
protected $autoincKeyName = 'id';
protected $uuidColumn = 'uuid';
protected $defaultProperties = array(
protected $defaultProperties = [
'id' => null,
'uuid' => null,
'list_name' => null,
'owner' => null
);
];
/** @var DirectorDatalistEntry[] */
protected $storedEntries;

View File

@ -0,0 +1,35 @@
ALTER TABLE director_datafield ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE director_datafield SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE director_datafield MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
ALTER TABLE director_datalist ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id;
SET @tmp_uuid = LOWER(CONCAT(
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-',
'4',
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
HEX(FLOOR(RAND() * 4 + 8)),
LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-',
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'),
LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0')
));
UPDATE director_datalist SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL;
ALTER TABLE director_datalist MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid);
INSERT INTO director_schema_migration
(schema_version, migration_time)
VALUES (186, NOW());

View File

@ -177,6 +177,7 @@ CREATE TABLE director_deployment_log (
CREATE TABLE director_datalist (
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
uuid VARBINARY(16) NOT NULL,
list_name VARCHAR(255) NOT NULL,
owner VARCHAR(255) NOT NULL,
PRIMARY KEY (id),
@ -207,6 +208,7 @@ CREATE TABLE director_datafield_category (
CREATE TABLE director_datafield (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
uuid VARBINARY(16) NOT NULL,
category_id INT(10) UNSIGNED DEFAULT NULL,
varname VARCHAR(64) NOT NULL COLLATE utf8_bin,
caption VARCHAR(255) NOT NULL,
@ -2443,4 +2445,4 @@ CREATE TABLE branched_icinga_dependency (
INSERT INTO director_schema_migration
(schema_version, migration_time)
VALUES (184, NOW());
VALUES (186, NOW());

View File

@ -0,0 +1,11 @@
ALTER TABLE director_datafield ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE director_datafield SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE director_datafield ALTER COLUMN uuid SET NOT NULL;
ALTER TABLE director_datalist ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16);
UPDATE director_datalist SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL;
ALTER TABLE director_datalist ALTER COLUMN uuid SET NOT NULL;
INSERT INTO director_schema_migration
(schema_version, migration_time)
VALUES (186, NOW());

View File

@ -246,6 +246,7 @@ CREATE INDEX start_time_idx ON director_deployment_log (start_time);
CREATE TABLE director_datalist (
id serial,
uuid bytea CHECK(LENGTH(uuid) = 16) NOT NULL,
list_name character varying(255) NOT NULL,
owner character varying(255) NOT NULL,
PRIMARY KEY (id)
@ -283,6 +284,7 @@ CREATE UNIQUE INDEX datafield_category_name ON director_datafield_category (cate
CREATE TABLE director_datafield (
id serial,
uuid bytea CHECK(LENGTH(uuid) = 16) NOT NULL,
category_id integer DEFAULT NULL,
varname character varying(64) NOT NULL,
caption character varying(255) NOT NULL,
@ -2782,4 +2784,4 @@ CREATE INDEX branched_dependency_search_object_name ON branched_icinga_dependenc
INSERT INTO director_schema_migration
(schema_version, migration_time)
VALUES (184, NOW());
VALUES (186, NOW());