pdo->prepare( 'SELECT host_id, dhcp_identifier, ipv4_address, hostname, user_context FROM hosts ORDER BY host_id DESC LIMIT :limit' ); $stmt->bindValue(':limit', $limit, PDO::PARAM_INT); $stmt->execute(); return $this->withMetadata($stmt->fetchAll(PDO::FETCH_ASSOC)); } catch (\PDOException $e) { if ($this->isMissingTable($e)) { throw new \RuntimeException( 'KEA schema not initialized. Enable APP_DB_AUTO_INIT or run kea-admin db-init pgsql.', 0, $e ); } throw $e; } } /** * Sucht einen Host anhand der MAC-Adresse (dhcp_identifier). */ public function findByMac(string $mac): ?array { // Hinweis: KEA speichert MACs in PostgreSQL oft als BYTEA. // Je nach Treiber-Konfiguration muss $mac hier ggf. als Hex-String (z.B. '\x...') // formatiert übergeben werden. try { $stmt = $this->pdo->prepare( 'SELECT host_id, dhcp_identifier, ipv4_address, hostname, user_context FROM hosts WHERE dhcp_identifier = :mac LIMIT 1' ); $stmt->execute(['mac' => $mac]); $row = $stmt->fetch(PDO::FETCH_ASSOC); return $row ?: null; } catch (\PDOException $e) { if ($this->isMissingTable($e)) { throw new \RuntimeException( 'KEA schema not initialized. Enable APP_DB_AUTO_INIT or run kea-admin db-init pgsql.', 0, $e ); } throw $e; } } private function isMissingTable(\PDOException $e): bool { return $e->getCode() === '42P01'; } /** * Erstellt eine neue Host-Reservierung inkl. Metadaten. * * @param string $mac MAC-Adresse * @param string $ip IPv4-Adresse * @param int $subnetId Die ID des Subnets (dhcp4_subnet_id), in dem die IP liegt * @param string|null $hostname Optionaler Hostname * @param array $metadata Zusätzliche Infos fuer die separate Nexus-DHCP-Metadatenbank. */ public function create(string $mac, string $ip, int $subnetId, ?string $hostname = null, array $metadata = []): int { // dhcp_identifier_type 1 = HW_ADDRESS (Ethernet) $stmt = $this->pdo->prepare( 'INSERT INTO hosts (dhcp_identifier, dhcp_identifier_type, dhcp4_subnet_id, ipv4_address, hostname) VALUES (:mac, 1, :subnetId, :ip, :hostname)' ); $stmt->execute([ 'mac' => $mac, 'subnetId' => $subnetId, 'ip' => $ip, 'hostname' => $hostname, ]); $hostId = $this->lastInsertIdSafe(); if ($this->metadata !== null && $metadata !== []) { $this->metadata->saveForHost($hostId, $mac, $ip, $metadata); } return $hostId; } private function withMetadata(array $hosts): array { if ($hosts === [] || $this->metadata === null) { return $hosts; } $metadataByHost = $this->metadata->findByHostIds(array_column($hosts, 'host_id')); foreach ($hosts as &$host) { $hostId = (int)($host['host_id'] ?? 0); $host['metadata'] = $metadataByHost[$hostId] ?? []; } unset($host); return $hosts; } private function driver(): string { return (string)$this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME); } private function lastInsertIdSafe(): int { $driver = $this->driver(); if ($driver === 'pgsql') { // KEA Standard-Sequenz für die hosts Tabelle $id = $this->pdo->lastInsertId('hosts_host_id_seq'); if ($id !== '') { return (int)$id; } } return (int)$this->pdo->lastInsertId(); } }