Branch: remove outdated classes

This commit is contained in:
Thomas Gelf 2021-10-05 22:04:23 +02:00
parent 5483093959
commit f7d100ea24
4 changed files with 0 additions and 654 deletions

View File

@ -1,89 +0,0 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Module\Director\Data\Json;
use Icinga\Module\Director\Db;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
class BranchActivityStore
{
protected $connection;
protected $db;
protected $table = 'director_branch_activity';
public function __construct(Db $connection)
{
$this->connection = $connection;
$this->db = $connection->getDbAdapter();
}
public function count(UuidInterface $branchUuid)
{
$query = $this->db->select()
->from($this->table, ['cnt' => 'COUNT(*)'])
->where('branch_uuid = ?', $branchUuid->getBytes());
return (int) $this->db->fetchOne($query);
}
public function loadAll(UuidInterface $branchUuid)
{
$query = $this->db->select()
->from($this->table)
->where('branch_uuid = ?', $branchUuid->getBytes())
->order('change_time DESC');
return $this->db->fetchAll($query);
}
public static function objectModificationForDbRow($row)
{
$modification = ObjectModification::fromSerialization(json_decode($row->change_set));
return $modification;
}
/**
* Must be run in a transaction!
*
* @param ObjectModification $modification
* @param UuidInterface $branchUuid
* @throws \Icinga\Module\Director\Exception\JsonEncodeException
* @throws \Zend_Db_Adapter_Exception
*/
public function persistModification(ObjectModification $modification, UuidInterface $branchUuid)
{
$db = $this->db;
$last = $db->fetchOne(
$db->select()
->from('director_branch_activity', 'checksum')
->order('change_time DESC')
->order('uuid') // Just in case, this gives a guaranteed order
);
// TODO: eventually implement more checks, allow only one change per millisecond
// alternatively use last change_time plus one, when now < change_time
if (strlen($last) !== 20) {
$last = '';
}
$binaryUuid = Uuid::uuid4()->getBytes();
$timestampMs = $this->now();
$encoded = Json::encode($modification);
// HINT: checksums are useless! -> merge only
$this->db->insert('director_branch_activity', [
'uuid' => $binaryUuid,
'branch_uuid' => $branchUuid->getBytes(),
'change_set' => $encoded, // TODO: rename -> object_modification
'change_time' => $timestampMs, // TODO: ns!!
'checksum' => sha1("$last/$binaryUuid/$timestampMs/$encoded", true),
'parent_checksum' => $last === '' ? null : $last,
]);
}
protected function now()
{
return floor(microtime(true) * 1000);
}
}

View File

@ -1,267 +0,0 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
use Icinga\Module\Director\Data\Json;
use Icinga\Module\Director\Db;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;
class BranchModificationStore
{
// TODO: Ranges is weird. key = scheduled_downtime_id, range_type, range_key
const ENCODED_ARRAYS = ['imports', 'groups', 'ranges'];
const ENCODED_DICTIONARIES = ['vars', 'arguments'];
protected $connection;
protected $db;
protected $shortType;
protected $table;
public function __construct(Db $connection, $shortType)
{
$this->connection = $connection;
$this->shortType = $shortType;
$this->table = "branched_icinga_$shortType";
$this->db = $connection->getDbAdapter();
}
public function loadAll(UuidInterface $branchUuid)
{
return $this->db->fetchAll($this->select()->where('branch_uuid = ?', $branchUuid->getBytes()));
}
public function eventuallyLoadModification($objectId, UuidInterface $branchUuid)
{
if ($objectId) {
$row = $this->fetchOptional($objectId, $branchUuid);
} else {
return null;
}
if ($row) {
$id = (int) $objectId;
$class = DbObjectTypeRegistry::classByType($this->shortType);
if ($row->deleted === 'y') {
return ObjectModification::delete($class, $id, static::cleanupRow($row));
}
if ($row->created === 'y') {
return ObjectModification::create($class, $row->object_name, static::cleanupRow($row));
}
// TODO: Former properties null? DB Problem.
return ObjectModification::modify($class, $id, null, static::filterNull(static::cleanupRow($row)));
}
return null;
}
public function loadOptionalModificationByName($objectName, UuidInterface $branchUuid)
{
$row = $this->fetchOptionalByName($objectName, $branchUuid);
if ($row) {
$class = DbObjectTypeRegistry::classByType($this->shortType);
if ($row->created === 'y') {
return ObjectModification::create($class, $row->object_name, static::cleanupRow($row));
}
if ($row->deleted === 'y') {
throw new \RuntimeException('Delete for a probably non-existing object? Not sure');
// return ObjectModification::delete($class, $row->object_name, ...);
}
// Hint: this is not correct. Former properties are missing. We finish up here, when loading renamed objects.
return ObjectModification::modify($class, $row->object_name, [], static::filterNull(static::cleanupRow($row)));
// TODO: better exception, handle this in the frontend
//throw new \RuntimeException('Got a modification for a probably non-existing object');
}
return null;
}
protected function filterNull($row)
{
return (object) array_filter((array) $row, function ($value) {
return $value !== null;
});
}
protected function cleanupRow($row)
{
unset($row->object_id, $row->class, $row->branch_uuid, $row->uuid, $row->created, $row->deleted);
return $row;
}
protected function fetchOptional($objectId, UuidInterface $branchUuid)
{
return $this->optionalRow($this->select()
->where('object_id = ?', $objectId)
->where('branch_uuid = ?', $branchUuid->getBytes()));
}
protected function fetchOptionalByName($objectName, UuidInterface $branchUuid)
{
return $this->optionalRow($this->select()
->where('object_name = ?', $objectName)
->where('branch_uuid = ?', $branchUuid->getBytes()));
}
protected function optionalRow($query)
{
if ($row = $this->db->fetchRow($query)) {
$this->decodeEncodedProperties($row);
return $row;
}
return null;
}
protected function select()
{
return $this->db->select()->from($this->table);
}
protected function decodeEncodedProperties($row)
{
foreach (array_merge(self::ENCODED_ARRAYS, self::ENCODED_DICTIONARIES) as $encodedProperty) {
// vars, imports and groups might be null or not set at all (if not supported)
if (! empty($row->$encodedProperty)) {
$row->$encodedProperty = Json::decode($row->$encodedProperty);
}
}
}
protected function prepareModificationForStore(ObjectModification $modification)
{
// TODO.
}
public function store(ObjectModification $modification, $objectId, UuidInterface $branchUuid)
{
if ($properties = $modification->getProperties()) {
$properties = (array) $properties->jsonSerialize();
} else {
$properties = [];
}
// Former properties are not needed, as they are dealt with in persistModification.
if ($objectId) {
$existing = $this->fetchOptional($objectId, $branchUuid);
} else {
$existing = null;
}
foreach (self::ENCODED_DICTIONARIES as $deepProperty) {
if (isset($properties[$deepProperty])) {
// TODO: flags
$properties[$deepProperty] = Json::encode($properties[$deepProperty]);
}
}
/* TODO: Nothing should be flat here, verify and remove this comment
foreach (self::ENCODED_DICTIONARIES as $property) {
$this->combineAndEncodeFlatDictionaries($properties, $existing, $property);
}
*/
foreach (self::ENCODED_ARRAYS as $deepProperty) {
if (isset($properties[$deepProperty])) {
// TODO: flags
$properties[$deepProperty] = Json::encode($properties[$deepProperty]);
}
}
$this->connection->runFailSafeTransaction(function () use (
$existing,
$modification,
$objectId,
$branchUuid,
$properties
) {
if ($existing) {
if ($modification->isDeletion()) {
$this->deleteExisting($existing->uuid);
$this->delete($objectId, $branchUuid);
} elseif ($existing->deleted === 'y') {
$this->deleteExisting($existing->uuid);
$this->create($objectId, $branchUuid, $properties);
} else {
$this->update($existing->uuid, $properties);
}
} else {
if ($modification->isCreation()) {
$this->create($objectId, $branchUuid, $properties);
} elseif ($modification->isDeletion()) {
$this->delete($objectId, $branchUuid);
} else {
$this->createModification($objectId, $branchUuid, $properties);
}
}
$activities = new BranchActivityStore($this->connection);
$activities->persistModification($modification, $branchUuid);
});
}
protected function combineAndEncodeFlatDictionaries(&$properties, $existing, $prefix)
{
if ($existing && ! empty($existing->$prefix)) {
// $vars = (array) Json::decode($existing->vars);
$vars = (array) ($existing->$prefix);
} else {
$vars = [];
}
$length = strlen($prefix) + 1;
foreach ($properties as $key => $value) {
if (substr($key, 0, $length) === "$prefix.") {
$vars[substr($key, $length)] = $value;
}
}
if (! empty($vars)) {
foreach (array_keys($vars) as $key) {
unset($properties["$prefix.$key"]);
}
$properties[$prefix] = Json::encode((object) $vars); // TODO: flags!
}
}
protected function deleteExisting($binaryUuid)
{
$this->db->delete($this->table, $this->db->quoteInto('uuid = ?', $binaryUuid));
}
protected function create($objectId, UuidInterface $branchUuid, $properties)
{
$this->db->insert($this->table, [
'branch_uuid' => $branchUuid->getBytes(),
'uuid' => Uuid::uuid4()->getBytes(),
'object_id' => $objectId,
'created' => 'y',
] + (array) $properties);
}
protected function delete($objectId, UuidInterface $branchUuid)
{
$this->db->insert($this->table, [
'branch_uuid' => $branchUuid->getBytes(),
'uuid' => Uuid::uuid4()->getBytes(),
'object_id' => $objectId,
'deleted' => 'y',
]);
}
protected function createModification($objectId, UuidInterface $branchUuid, $properties)
{
$this->db->insert($this->table, [
'branch_uuid' => $branchUuid->getBytes(),
'uuid' => Uuid::uuid4()->getBytes(),
'object_id' => $objectId,
] + (array) $properties);
}
protected function update($binaryUuid, $properties)
{
$this->db->update($this->table, [
'uuid' => Uuid::uuid4()->getBytes(),
] + (array) $properties, $this->db->quoteInto('uuid = ?', $binaryUuid));
}
}

View File

@ -1,142 +0,0 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Exception\ProgrammingError;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\IcingaObject;
class IcingaObjectModification
{
/**
* @param DbObject $object
* @return ObjectModification
*/
public static function getModification(DbObject $object)
{
if ($object->shouldBeRemoved()) {
return static::delete($object);
}
if ($object->hasBeenLoadedFromDb()) {
return static::modify($object);
}
return static::create($object);
}
protected static function fixForeignKeys($object)
{
// TODO: Generic, _name?? Lookup?
$keys = [
'check_command_name',
'check_period_name',
'event_command_name',
'command_endpoint_name',
'zone_name',
'host_name',
];
foreach ($keys as $key) {
if (property_exists($object, $key)) {
$object->{substr($key, 0, -5)} = $object->$key;
unset($object->$key);
}
}
}
public static function applyModification(ObjectModification $modification, DbObject $object = null, Db $db = null)
{
if ($modification->isDeletion()) {
$object->markForRemoval();
} elseif ($modification->isCreation()) {
/** @var string|DbObject $class */
$class = $modification->getClassName();
$properties = $modification->getProperties()->jsonSerialize();
self::fixForeignKeys($properties);
$object = $class::create((array) $properties, $db);
} else {
// TODO: Add "reset Properties", those that have been nulled
$properties = (array) $modification->getProperties()->jsonSerialize();
foreach (BranchModificationStore::ENCODED_DICTIONARIES as $property) {
self::flattenProperty($properties, $property);
}
if ($object === null) {
echo '<pre>';
debug_print_backtrace();
echo '</pre>';
exit;
}
foreach ($properties as $key => $value) {
$object->set($key, $value);
}
}
// Just to be on the safe side
if ($db) {
$object->setConnection($db);
}
return $object;
}
public static function delete(DbObject $object)
{
return ObjectModification::delete(
get_class($object),
self::getKey($object),
$object->toPlainObject(false, true)
);
}
public static function create(DbObject $object)
{
return ObjectModification::create(
get_class($object),
self::getKey($object),
$object->toPlainObject(false, true)
);
}
protected static function getKey(DbObject $object)
{
return $object->getKeyParams();
}
protected static function flattenProperty(array &$properties, $property)
{
// TODO: dots in varnames -> throw or escape?
if (isset($properties[$property])) {
foreach ((array) $properties[$property] as $key => $value) {
$properties["$property.$key"] = $value;
}
unset($properties[$property]);
}
}
public static function modify(DbObject $object)
{
if (! $object instanceof IcingaObject) {
throw new ProgrammingError('Plain object helpers for DbObject must be implemented');
}
$old = (array) $object->getPlainUnmodifiedObject();
$new = (array) $object->toPlainObject(false, true);
$unchangedKeys = [];
foreach (BranchModificationStore::ENCODED_DICTIONARIES as $property) {
self::flattenProperty($old, $property);
self::flattenProperty($new, $property);
}
foreach ($old as $key => $value) {
if (array_key_exists($key, $new) && $value === $new[$key]) {
$unchangedKeys[] = $key;
}
}
foreach ($unchangedKeys as $key) {
unset($old[$key]);
unset($new[$key]);
}
return ObjectModification::modify(get_class($object), self::getKey($object), $old, $new);
}
}

View File

@ -1,156 +0,0 @@
<?php
namespace Icinga\Module\Director\Db\Branch;
use Icinga\Module\Director\Data\DataArrayHelper;
use Icinga\Module\Director\Data\Serializable;
use Icinga\Module\Director\Data\SerializableValue;
use InvalidArgumentException;
class ObjectModification implements Serializable
{
const ACTION_CREATE = 'create';
const ACTION_MODIFY = 'modify';
const ACTION_DELETE = 'delete';
protected static $serializationProperties = [
'class',
'key',
'action',
'properties',
'formerProperties',
];
/** @var string */
protected $class;
/** @var \stdClass */
protected $key;
/** @var string */
protected $action;
/** @var SerializableValue|null */
protected $properties;
/** @var SerializableValue|null */
protected $formerProperties;
public function __construct(
$class,
$key,
$action,
SerializableValue $properties = null,
SerializableValue $formerProperties = null
) {
$this->class = $class;
$this->key = $key;
$this->assertValidAction($action);
$this->action = $action;
$this->properties = $properties;
$this->formerProperties = $formerProperties;
}
public static function delete($class, $key, $formerProperties)
{
return new static(
$class,
$key,
self::ACTION_DELETE,
null,
SerializableValue::wantSerializable($formerProperties)
);
}
public static function create($class, $key, $properties)
{
return new static($class, $key, self::ACTION_CREATE, SerializableValue::wantSerializable($properties));
}
public static function modify($class, $key, $formerProperties, $properties)
{
return new static(
$class,
$key,
self::ACTION_MODIFY,
SerializableValue::wantSerializable($properties),
SerializableValue::wantSerializable($formerProperties)
);
}
protected function assertValidAction($action)
{
if ($action !== self::ACTION_MODIFY
&& $action !== self::ACTION_CREATE
&& $action !== self::ACTION_DELETE
) {
throw new InvalidArgumentException("Valid action expected, got $action");
}
}
public function isDeletion()
{
return $this->action === self::ACTION_DELETE;
}
public function isCreation()
{
return $this->action === self::ACTION_CREATE;
}
public function isModification()
{
return $this->action === self::ACTION_MODIFY;
}
public function getAction()
{
return $this->action;
}
public function jsonSerialize()
{
return (object) [
'class' => $this->class,
'key' => $this->key,
'action' => $this->action,
'properties' => $this->properties,
'formerProperties' => $this->formerProperties,
];
}
public function getProperties()
{
return $this->properties;
}
public function getFormerProperties()
{
return $this->formerProperties;
}
public function getClassName()
{
return $this->class;
}
public function getKeyParams()
{
return $this->key;
}
public static function fromSerialization($value)
{
$value = DataArrayHelper::wantArray($value);
DataArrayHelper::failOnUnknownProperties($value, self::$serializationProperties);
DataArrayHelper::requireProperties($value, ['class', 'key', 'action']);
return new static(
$value['class'],
$value['key'],
$value['action'],
isset($value['properties']) ? SerializableValue::fromSerialization($value['properties']) : null,
isset($value['formerProperties']) ? SerializableValue::fromSerialization($value['formerProperties']) : null
);
}
}