KEA update
All checks were successful
Deploy / deploy-staging (push) Successful in 6s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-04-16 01:19:07 +02:00
parent 04ec9dc227
commit 9f2af4676d
8 changed files with 416 additions and 46 deletions

View File

@@ -20,6 +20,8 @@ $host = null;
$metadataRepo = null;
$groups = [];
$availableIpsByGroup = [];
$checks = [];
$hostKey = '';
try {
$pdo = modules()->modulePdo('kea', $fallback);
@@ -35,35 +37,54 @@ try {
if (!$host) {
throw new RuntimeException('KEA Eintrag wurde nicht gefunden.');
}
$hostKey = $source . ':' . (string)($host['host_id'] ?? $id);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$metadata = [
'real_name' => $_POST['real_name'] ?? '',
'device_name' => $_POST['device_name'] ?? '',
'owner' => $_POST['owner'] ?? '',
'location' => $_POST['location'] ?? '',
'device_type' => $_POST['device_type'] ?? '',
'group_name' => $_POST['group_name'] ?? '',
'desired_ip' => $_POST['desired_ip'] ?? '',
'notes' => $_POST['notes'] ?? '',
'tags' => [],
];
$desiredIp = trim((string)$metadata['desired_ip']);
if ($desiredIp !== '') {
$newHostId = $repo->reserveDisplayEntry($host, $desiredIp, $metadata);
$source = 'reservation';
$id = $newHostId;
$notice = 'Zusatzdaten gespeichert und KEA-Reservierung gesetzt.';
$action = (string)($_POST['action'] ?? 'save_metadata');
if ($action === 'dns_lookup') {
$ip = (string)($host['ipv4_address'] ?? '');
$hostname = trim((string)($host['metadata']['device_name'] ?? $host['hostname'] ?? ''));
$reverse = $ip !== '' ? gethostbyaddr($ip) : '';
$forward = $hostname !== '' ? gethostbyname($hostname) : '';
$success = ($reverse !== '' && $reverse !== $ip) || ($forward !== '' && $forward !== $hostname);
$metadataRepo->saveCheck($hostKey, 'dns', $success ? 'success' : 'warning', [
'ip' => $ip,
'hostname' => $hostname,
'reverse' => $reverse,
'forward' => $forward,
]);
$notice = $success ? 'DNS-Pruefung gespeichert.' : 'DNS-Pruefung gespeichert, aber kein eindeutiger Name gefunden.';
} else {
$metadataRepo->saveForHost(
$id,
(string)($host['dhcp_identifier'] ?? ''),
(string)($host['ipv4_address'] ?? ''),
$metadata
);
$notice = 'Zusatzdaten gespeichert.';
$metadata = [
'real_name' => $_POST['real_name'] ?? '',
'device_name' => $_POST['device_name'] ?? '',
'owner' => $_POST['owner'] ?? '',
'location' => $_POST['location'] ?? '',
'device_type' => $_POST['device_type'] ?? '',
'group_name' => $_POST['group_name'] ?? '',
'desired_ip' => $_POST['desired_ip'] ?? '',
'notes' => $_POST['notes'] ?? '',
'tags' => [],
];
$desiredIp = trim((string)$metadata['desired_ip']);
if ($desiredIp !== '') {
$newHostId = $repo->reserveDisplayEntry($host, $desiredIp, $metadata);
$source = 'reservation';
$id = $newHostId;
$notice = 'Zusatzdaten gespeichert und KEA-Reservierung gesetzt.';
} else {
$metadataRepo->saveForHost(
$id,
(string)($host['dhcp_identifier'] ?? ''),
(string)($host['ipv4_address'] ?? ''),
$metadata
);
$notice = 'Zusatzdaten gespeichert.';
}
}
$host = $repo->findDisplayByKey($source, $id) ?: $host;
$hostKey = $source . ':' . (string)($host['host_id'] ?? $id);
}
$usedIps = array_diff(
@@ -71,6 +92,7 @@ try {
[(string)($host['ipv4_address'] ?? ''), (string)($host['metadata']['desired_ip'] ?? '')]
);
$availableIpsByGroup = $metadataRepo->availableIpsByGroup($usedIps);
$checks = $metadataRepo->latestChecks([$hostKey])[$hostKey] ?? [];
} catch (Throwable $e) {
$error = $e->getMessage();
}
@@ -115,6 +137,7 @@ $selectedIp = (string)($metadata['desired_ip'] ?? '');
</div>
<form method="post" class="kea-edit-form">
<input type="hidden" name="action" value="save_metadata">
<input type="hidden" name="source" value="<?= e($source) ?>">
<input type="hidden" name="id" value="<?= e((string)$id) ?>">
@@ -168,6 +191,40 @@ $selectedIp = (string)($metadata['desired_ip'] ?? '');
</div>
</form>
</div>
<div class="kea-panel">
<div class="kea-panel__head">
<div>
<span class="pill">Pruefungen</span>
<h3>Gerätechecks</h3>
<p class="muted">Pruefergebnisse werden in der Nexus-DHCP-Datenbank gespeichert und koennen spaeter fuer Reports genutzt werden.</p>
</div>
</div>
<div class="kea-check-grid">
<div class="kea-check-card">
<h4>DNS / Hostname</h4>
<?php $dnsCheck = $checks['dns'] ?? null; ?>
<?php if ($dnsCheck): ?>
<?php $dnsResult = json_decode((string)($dnsCheck['result_json'] ?? '{}'), true) ?: []; ?>
<p class="muted">Status: <?= e((string)($dnsCheck['status'] ?? '')) ?> · <?= e((string)($dnsCheck['checked_at'] ?? '')) ?></p>
<p class="mono">Reverse: <?= e((string)($dnsResult['reverse'] ?? '-')) ?></p>
<p class="mono">Forward: <?= e((string)($dnsResult['forward'] ?? '-')) ?></p>
<?php else: ?>
<p class="muted">Noch keine DNS-Pruefung gespeichert.</p>
<?php endif; ?>
<form method="post" class="setup-actions">
<input type="hidden" name="action" value="dns_lookup">
<input type="hidden" name="source" value="<?= e($source) ?>">
<input type="hidden" name="id" value="<?= e((string)$id) ?>">
<button class="nav-link" type="submit">DNS jetzt pruefen</button>
</form>
</div>
<div class="kea-check-card">
<h4>Login-Erkennung</h4>
<p class="muted">Vorbereitet fuer spaetere HTTP/Port-Erkennung. Noch nicht automatisch aktiv, damit keine ungewollten Scans laufen.</p>
</div>
</div>
</div>
<script>
(() => {
const ipsByGroup = <?= json_encode($availableIpsByGroup, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;

View File

@@ -14,6 +14,7 @@ $error = null;
$notice = null;
$groups = [];
$availableIpsByGroup = [];
$usedIps = [];
try {
if (empty($metadataConfig['driver']) || empty($metadataConfig['dbname'])) {
@@ -26,7 +27,11 @@ try {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = (string)($_POST['action'] ?? '');
if ($action === 'save_group') {
$metadataRepo->saveGroup((string)($_POST['name'] ?? ''), (string)($_POST['description'] ?? ''));
$metadataRepo->saveGroup(
(string)($_POST['name'] ?? ''),
(string)($_POST['description'] ?? ''),
(string)($_POST['parent_name'] ?? '')
);
$notice = 'Gruppe gespeichert.';
} elseif ($action === 'add_range') {
$metadataRepo->addRange(
@@ -40,13 +45,35 @@ try {
$groups = $metadataRepo->listGroupsWithRanges();
$keaRepo = new KeaHostRepository(modules()->modulePdo('kea', $fallback), $metadataRepo);
$availableIpsByGroup = $metadataRepo->availableIpsByGroup(
array_merge($keaRepo->usedIpAddresses(), $metadataRepo->desiredIps()),
4096
);
$usedIps = array_merge($keaRepo->usedIpAddresses(), $metadataRepo->desiredIps());
$availableIpsByGroup = $metadataRepo->availableIpsByGroup($usedIps, 4096);
} catch (Throwable $e) {
$error = $e->getMessage();
}
$usedIpLookup = array_flip(array_filter(array_map('strval', $usedIps)));
$matrixForGroup = static function (array $group) use ($usedIpLookup): array {
$dots = [];
foreach (($group['ranges'] ?? []) as $range) {
$start = ip2long((string)($range['start_ip'] ?? ''));
$end = ip2long((string)($range['end_ip'] ?? ''));
if ($start === false || $end === false) {
continue;
}
for ($ip = $start; $ip <= $end && count($dots) < 512; $ip++) {
$address = long2ip($ip);
if ($address === false) {
continue;
}
$dots[] = [
'ip' => $address,
'used' => isset($usedIpLookup[$address]),
];
}
}
return $dots;
};
?>
<section class="kea-page">
<div class="section-head">
@@ -83,6 +110,15 @@ try {
<span>Beschreibung</span>
<input type="text" name="description">
</label>
<label class="setup-field">
<span>Uebergeordnete Gruppe</span>
<select name="parent_name">
<option value="">Keine</option>
<?php foreach ($groups as $group): ?>
<option value="<?= e((string)$group['name']) ?>"><?= e((string)$group['name']) ?></option>
<?php endforeach; ?>
</select>
</label>
<div class="setup-actions kea-edit-form__wide">
<button class="cta-button" type="submit">Gruppe speichern</button>
</div>
@@ -133,19 +169,22 @@ try {
<thead>
<tr>
<th>Gruppe</th>
<th>Untergruppe von</th>
<th>Beschreibung</th>
<th>Bereiche</th>
<th>Freie IPs</th>
<th>Matrix</th>
</tr>
</thead>
<tbody>
<?php if ($groups === []): ?>
<tr><td colspan="4" class="kea-empty">Noch keine Gruppen definiert.</td></tr>
<tr><td colspan="6" class="kea-empty">Noch keine Gruppen definiert.</td></tr>
<?php else: ?>
<?php foreach ($groups as $group): ?>
<?php $available = $availableIpsByGroup[(string)$group['name']] ?? []; ?>
<tr>
<td><?= e((string)$group['name']) ?></td>
<td><?= e((string)($group['parent_name'] ?: '-')) ?></td>
<td><?= e((string)($group['description'] ?? '-')) ?></td>
<td>
<?php if (($group['ranges'] ?? []) === []): ?>
@@ -157,6 +196,21 @@ try {
<?php endif; ?>
</td>
<td><?= e((string)count($available)) ?></td>
<td>
<?php $matrix = $matrixForGroup($group); ?>
<?php if ($matrix === []): ?>
<span class="muted">Kein Bereich</span>
<?php else: ?>
<div class="ip-matrix" aria-label="IP Matrix fuer <?= e((string)$group['name']) ?>">
<?php foreach ($matrix as $dot): ?>
<span
class="ip-dot <?= $dot['used'] ? 'is-used' : 'is-free' ?>"
title="<?= e((string)$dot['ip']) ?> · <?= $dot['used'] ? 'belegt' : 'frei' ?>"
></span>
<?php endforeach; ?>
</div>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>