KEA update
This commit is contained in:
@@ -34,6 +34,7 @@ final class KeaHostMetadataRepository
|
||||
$this->ensureColumn('nexus_dhcp_host_meta', 'group_name', 'TEXT');
|
||||
$this->ensureColumn('nexus_dhcp_host_meta', 'desired_ip', 'TEXT');
|
||||
$this->ensureGroupSchema($driver);
|
||||
$this->ensureCheckSchema($driver);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,6 +59,7 @@ final class KeaHostMetadataRepository
|
||||
$this->ensureColumn('nexus_dhcp_host_meta', 'group_name', 'TEXT');
|
||||
$this->ensureColumn('nexus_dhcp_host_meta', 'desired_ip', 'TEXT');
|
||||
$this->ensureGroupSchema($driver);
|
||||
$this->ensureCheckSchema($driver);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,6 +84,7 @@ final class KeaHostMetadataRepository
|
||||
$this->ensureColumn('nexus_dhcp_host_meta', 'group_name', 'TEXT');
|
||||
$this->ensureColumn('nexus_dhcp_host_meta', 'desired_ip', 'TEXT');
|
||||
$this->ensureGroupSchema($driver);
|
||||
$this->ensureCheckSchema($driver);
|
||||
}
|
||||
|
||||
public function findByHostIds(array $hostIds): array
|
||||
@@ -222,9 +225,10 @@ final class KeaHostMetadataRepository
|
||||
|
||||
$groups = [];
|
||||
$stmt = $this->pdo->query(
|
||||
"SELECT id, name, description
|
||||
FROM nexus_dhcp_groups
|
||||
ORDER BY name ASC"
|
||||
"SELECT child.id, child.name, child.description, child.parent_id, parent.name AS parent_name
|
||||
FROM nexus_dhcp_groups child
|
||||
LEFT JOIN nexus_dhcp_groups parent ON parent.id = child.parent_id
|
||||
ORDER BY parent.name ASC, child.name ASC"
|
||||
);
|
||||
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
||||
$id = (int)$row['id'];
|
||||
@@ -232,6 +236,8 @@ final class KeaHostMetadataRepository
|
||||
'id' => $id,
|
||||
'name' => (string)$row['name'],
|
||||
'description' => (string)($row['description'] ?? ''),
|
||||
'parent_id' => $row['parent_id'] !== null ? (int)$row['parent_id'] : null,
|
||||
'parent_name' => (string)($row['parent_name'] ?? ''),
|
||||
'ranges' => [],
|
||||
];
|
||||
}
|
||||
@@ -257,33 +263,47 @@ final class KeaHostMetadataRepository
|
||||
return array_values($groups);
|
||||
}
|
||||
|
||||
public function saveGroup(string $name, string $description = ''): void
|
||||
public function saveGroup(string $name, string $description = '', string $parentName = ''): void
|
||||
{
|
||||
$name = trim($name);
|
||||
if ($name === '') {
|
||||
throw new \RuntimeException('Gruppenname fehlt.');
|
||||
}
|
||||
$parentName = trim($parentName);
|
||||
if ($parentName !== '' && strcasecmp($parentName, $name) === 0) {
|
||||
throw new \RuntimeException('Eine Gruppe kann nicht ihre eigene Untergruppe sein.');
|
||||
}
|
||||
$parentId = $parentName !== '' ? $this->groupIdByName($parentName) : null;
|
||||
if ($parentName !== '' && !$parentId) {
|
||||
throw new \RuntimeException('Uebergeordnete Gruppe wurde nicht gefunden.');
|
||||
}
|
||||
|
||||
$driver = (string)$this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
|
||||
if ($driver === 'pgsql' || $driver === 'sqlite') {
|
||||
$sql = "INSERT INTO nexus_dhcp_groups (name, description, updated_at)
|
||||
VALUES (:name, :description, CURRENT_TIMESTAMP)
|
||||
$sql = "INSERT INTO nexus_dhcp_groups (name, description, parent_id, updated_at)
|
||||
VALUES (:name, :description, :parent_id, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT(name) DO UPDATE SET
|
||||
description = excluded.description,
|
||||
parent_id = excluded.parent_id,
|
||||
updated_at = CURRENT_TIMESTAMP";
|
||||
} else {
|
||||
$sql = "INSERT INTO nexus_dhcp_groups (name, description, updated_at)
|
||||
VALUES (:name, :description, CURRENT_TIMESTAMP)
|
||||
$sql = "INSERT INTO nexus_dhcp_groups (name, description, parent_id, updated_at)
|
||||
VALUES (:name, :description, :parent_id, CURRENT_TIMESTAMP)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
description = VALUES(description),
|
||||
parent_id = VALUES(parent_id),
|
||||
updated_at = CURRENT_TIMESTAMP";
|
||||
}
|
||||
|
||||
$stmt = $this->pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
'name' => $name,
|
||||
'description' => $this->nullableString($description),
|
||||
]);
|
||||
$stmt->bindValue('name', $name);
|
||||
$stmt->bindValue('description', $this->nullableString($description));
|
||||
if ($parentId === null) {
|
||||
$stmt->bindValue('parent_id', null, PDO::PARAM_NULL);
|
||||
} else {
|
||||
$stmt->bindValue('parent_id', $parentId, PDO::PARAM_INT);
|
||||
}
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
public function addRange(string $groupName, string $startIp, string $endIp): void
|
||||
@@ -354,6 +374,89 @@ final class KeaHostMetadataRepository
|
||||
)));
|
||||
}
|
||||
|
||||
public function saveCheck(string $hostKey, string $checkType, string $status, array $result = [], ?string $nextCheckAt = null): void
|
||||
{
|
||||
$hostKey = trim($hostKey);
|
||||
$checkType = trim($checkType);
|
||||
$status = trim($status);
|
||||
if ($hostKey === '' || $checkType === '' || $status === '') {
|
||||
throw new \RuntimeException('Pruefdaten sind unvollstaendig.');
|
||||
}
|
||||
|
||||
$resultJson = json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if ($resultJson === false) {
|
||||
$resultJson = '{}';
|
||||
}
|
||||
|
||||
$driver = (string)$this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
|
||||
if ($driver === 'pgsql') {
|
||||
$stmt = $this->pdo->prepare(
|
||||
"INSERT INTO nexus_dhcp_device_checks (
|
||||
host_key, check_type, status, result_json, checked_at, next_check_at
|
||||
) VALUES (
|
||||
:host_key, :check_type, :status, CAST(:result_json AS jsonb), NOW(), :next_check_at
|
||||
)"
|
||||
);
|
||||
} else {
|
||||
$stmt = $this->pdo->prepare(
|
||||
"INSERT INTO nexus_dhcp_device_checks (
|
||||
host_key, check_type, status, result_json, checked_at, next_check_at
|
||||
) VALUES (
|
||||
:host_key, :check_type, :status, :result_json, CURRENT_TIMESTAMP, :next_check_at
|
||||
)"
|
||||
);
|
||||
}
|
||||
|
||||
$stmt->execute([
|
||||
'host_key' => $hostKey,
|
||||
'check_type' => $checkType,
|
||||
'status' => $status,
|
||||
'result_json' => $resultJson,
|
||||
'next_check_at' => $this->nullableString($nextCheckAt),
|
||||
]);
|
||||
}
|
||||
|
||||
public function latestChecks(array $hostKeys): array
|
||||
{
|
||||
$hostKeys = array_values(array_unique(array_filter(array_map(
|
||||
static fn(mixed $value): string => trim((string)$value),
|
||||
$hostKeys
|
||||
))));
|
||||
if ($hostKeys === [] || !$this->tableExists('nexus_dhcp_device_checks')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$params = [];
|
||||
$placeholders = [];
|
||||
foreach ($hostKeys as $idx => $hostKey) {
|
||||
$key = ':host_key_' . $idx;
|
||||
$placeholders[] = $key;
|
||||
$params[$key] = $hostKey;
|
||||
}
|
||||
|
||||
$stmt = $this->pdo->prepare(
|
||||
'SELECT host_key, check_type, status, result_json, checked_at
|
||||
FROM nexus_dhcp_device_checks
|
||||
WHERE host_key IN (' . implode(', ', $placeholders) . ')
|
||||
ORDER BY checked_at DESC, id DESC'
|
||||
);
|
||||
foreach ($params as $key => $value) {
|
||||
$stmt->bindValue($key, $value);
|
||||
}
|
||||
$stmt->execute();
|
||||
|
||||
$items = [];
|
||||
foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
||||
$hostKey = (string)$row['host_key'];
|
||||
$type = (string)$row['check_type'];
|
||||
if (!isset($items[$hostKey][$type])) {
|
||||
$items[$hostKey][$type] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function ensureGroupSchema(string $driver): void
|
||||
{
|
||||
if ($driver === 'pgsql') {
|
||||
@@ -362,9 +465,11 @@ final class KeaHostMetadataRepository
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
parent_id BIGINT REFERENCES nexus_dhcp_groups(id) ON DELETE SET NULL,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)"
|
||||
);
|
||||
$this->ensureColumn('nexus_dhcp_groups', 'parent_id', 'BIGINT');
|
||||
$this->pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_dhcp_group_ranges (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
@@ -383,9 +488,11 @@ final class KeaHostMetadataRepository
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
parent_id INTEGER,
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
)"
|
||||
);
|
||||
$this->ensureColumn('nexus_dhcp_groups', 'parent_id', 'INTEGER');
|
||||
$this->pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_dhcp_group_ranges (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@@ -403,9 +510,11 @@ final class KeaHostMetadataRepository
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(190) NOT NULL UNIQUE,
|
||||
description TEXT,
|
||||
parent_id BIGINT NULL,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
);
|
||||
$this->ensureColumn('nexus_dhcp_groups', 'parent_id', 'BIGINT NULL');
|
||||
$this->pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_dhcp_group_ranges (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
@@ -418,6 +527,60 @@ final class KeaHostMetadataRepository
|
||||
);
|
||||
}
|
||||
|
||||
private function ensureCheckSchema(string $driver): void
|
||||
{
|
||||
if ($driver === 'pgsql') {
|
||||
$this->pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_dhcp_device_checks (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
host_key TEXT NOT NULL,
|
||||
check_type TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
result_json JSONB,
|
||||
checked_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
next_check_at TIMESTAMPTZ
|
||||
)"
|
||||
);
|
||||
$this->pdo->exec(
|
||||
'CREATE INDEX IF NOT EXISTS idx_nexus_dhcp_device_checks_host_type
|
||||
ON nexus_dhcp_device_checks (host_key, check_type, checked_at)'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($driver === 'sqlite') {
|
||||
$this->pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_dhcp_device_checks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
host_key TEXT NOT NULL,
|
||||
check_type TEXT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
result_json TEXT,
|
||||
checked_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
next_check_at TEXT
|
||||
)"
|
||||
);
|
||||
$this->pdo->exec(
|
||||
'CREATE INDEX IF NOT EXISTS idx_nexus_dhcp_device_checks_host_type
|
||||
ON nexus_dhcp_device_checks (host_key, check_type, checked_at)'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->pdo->exec(
|
||||
"CREATE TABLE IF NOT EXISTS nexus_dhcp_device_checks (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
host_key VARCHAR(190) NOT NULL,
|
||||
check_type VARCHAR(80) NOT NULL,
|
||||
status VARCHAR(40) NOT NULL,
|
||||
result_json JSON,
|
||||
checked_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
next_check_at DATETIME NULL,
|
||||
INDEX idx_nexus_dhcp_device_checks_host_type (host_key, check_type, checked_at)
|
||||
)"
|
||||
);
|
||||
}
|
||||
|
||||
private function groupIdByName(string $name): int
|
||||
{
|
||||
$stmt = $this->pdo->prepare('SELECT id FROM nexus_dhcp_groups WHERE name = :name LIMIT 1');
|
||||
|
||||
@@ -94,6 +94,10 @@ final class KeaHostRepository
|
||||
user_context,
|
||||
dhcp4_subnet_id AS subnet_id,
|
||||
'reservation' AS source,
|
||||
NULL AS lease_state,
|
||||
NULL AS valid_lifetime,
|
||||
NULL AS lease_expires_at,
|
||||
NULL AS last_seen_at,
|
||||
host_id AS sort_id,
|
||||
{$sortExpr} AS sort_time
|
||||
FROM hosts
|
||||
@@ -114,7 +118,13 @@ final class KeaHostRepository
|
||||
|
||||
$macExpr = $this->hexExpression('hwaddr');
|
||||
$ipExpr = $this->ipv4Expression('address');
|
||||
$expireExpr = $this->driver() === 'pgsql' ? 'expire::text' : 'CAST(expire AS CHAR)';
|
||||
$driver = $this->driver();
|
||||
$expireExpr = $driver === 'pgsql' ? 'expire::text' : 'CAST(expire AS CHAR)';
|
||||
$lastSeenExpr = match ($driver) {
|
||||
'pgsql' => '(expire - make_interval(secs => valid_lifetime))::text',
|
||||
'mysql' => 'CAST(DATE_SUB(expire, INTERVAL valid_lifetime SECOND) AS CHAR)',
|
||||
default => 'NULL',
|
||||
};
|
||||
|
||||
$stmt = $this->pdo->prepare(
|
||||
"SELECT
|
||||
@@ -125,6 +135,10 @@ final class KeaHostRepository
|
||||
user_context,
|
||||
subnet_id,
|
||||
'lease' AS source,
|
||||
state AS lease_state,
|
||||
valid_lifetime,
|
||||
{$expireExpr} AS lease_expires_at,
|
||||
{$lastSeenExpr} AS last_seen_at,
|
||||
address AS sort_id,
|
||||
{$expireExpr} AS sort_time
|
||||
FROM lease4
|
||||
@@ -197,6 +211,10 @@ final class KeaHostRepository
|
||||
user_context,
|
||||
dhcp4_subnet_id AS subnet_id,
|
||||
'reservation' AS source,
|
||||
NULL AS lease_state,
|
||||
NULL AS valid_lifetime,
|
||||
NULL AS lease_expires_at,
|
||||
NULL AS last_seen_at,
|
||||
host_id AS sort_id,
|
||||
{$sortExpr} AS sort_time
|
||||
FROM hosts
|
||||
|
||||
Reference in New Issue
Block a user