- Add Hook interface (filter + execute contract) in server/hooks/hook.h
- Add HookRunner in server/hooks/hook_runner.h: spawns a detached thread
per matching hook, with try/catch protection against crashes
- Add DnsUpdaterHook in server/hooks/dns_updater_hook.{h,cpp}:
triggers on server name changes, logs in to Technitium, deletes the
old A record (ignores 404), and adds the new A record
Config via env vars: TECHNITIUM_HOST/PORT/USER/PASS/ZONE, DNS_TTL
- Add Database::get_nics_for_server() to resolve a server's IPv4 address
- Wire HookRunner into InventoryServer; cmd_edit_server now fires hooks
with before/after Server snapshots
- Update CMakeLists.txt to include dns_updater_hook.cpp
- Document env vars in Dockerfile
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
98 lines
5.5 KiB
C++
98 lines
5.5 KiB
C++
#pragma once
|
|
#include <cstdint>
|
|
#include <map>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
#include "common/models.h"
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// Database
|
|
// Thread-safe, file-backed inventory store.
|
|
//
|
|
// File format (text, one record per line):
|
|
// # device-inventory database
|
|
// META|next_server_id|next_part_type_id|next_part_id
|
|
// S|id|name|hostname|location|description
|
|
// PT|id|name|description
|
|
// MS|part_id|server_id|serial_or_NULL|last_updated|speed_mhz|size_mb|manufacturer|channel_config|other_info
|
|
// MSLOT|part_id|server_id|serial_or_NULL|last_updated|allowed_speed_mhz|allowed_size_mb|installed_stick_id_or_NULL
|
|
// CPU|part_id|server_id|serial_or_NULL|last_updated|name|manufacturer|speed_ghz|cores|threads
|
|
// CPUSLOT|part_id|server_id|serial_or_NULL|last_updated|form_factor|installed_cpu_id_or_NULL
|
|
// DISK|part_id|server_id|serial_or_NULL|last_updated|manufacturer|model|generation|conn_type|conn_speed|disk_speed|disk_size|disk_type|age_years|partition_ids_LS|partition_sizes_LS|vm_hostnames_LS|vm_server_ids_LS
|
|
// NIC|part_id|server_id|serial_or_NULL|last_updated|manufacturer|model|age_years|conn_type|conn_speed|mac|ips_LS|dhcp
|
|
//
|
|
// Lists within a field use LS ('\x02'). Pipe and backslash in text fields are
|
|
// escaped via escape()/unescape().
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
class Database {
|
|
public:
|
|
explicit Database(std::string path);
|
|
|
|
// Persist current inventory to disk (acquires lock)
|
|
bool save();
|
|
// Load (or reload) inventory from disk
|
|
bool load();
|
|
|
|
// ── Servers ───────────────────────────────────────────────────────────────
|
|
Server add_server(std::string name, std::string hostname,
|
|
std::string location, std::string description);
|
|
std::vector<Server> list_servers() const;
|
|
std::optional<Server> get_server(uint32_t id) const;
|
|
bool edit_server(uint32_t id, const std::string& field,
|
|
const std::string& value);
|
|
bool remove_server(uint32_t id);
|
|
|
|
// ── Part types (labels) ───────────────────────────────────────────────────
|
|
PartType add_part_type(std::string name, std::string description);
|
|
std::vector<PartType> list_part_types() const;
|
|
std::optional<PartType> get_part_type(uint32_t id) const;
|
|
bool edit_part_type(uint32_t id, const std::string& field,
|
|
const std::string& value);
|
|
bool remove_part_type(uint32_t id);
|
|
|
|
// ── Typed parts ───────────────────────────────────────────────────────────
|
|
// kv is a map of field-key → field-value strings (K_* constants from protocol.h)
|
|
uint32_t add_part(const std::string& type_name, uint32_t server_id,
|
|
const std::map<std::string,std::string>& kv);
|
|
// Insert or update: for nic match by mac, for others by serial
|
|
uint32_t upsert_part(const std::string& type_name, uint32_t server_id,
|
|
const std::map<std::string,std::string>& kv);
|
|
bool edit_part(uint32_t part_id, const std::map<std::string,std::string>& kv);
|
|
bool remove_part(uint32_t part_id);
|
|
|
|
// Wire-row format: type_name<FS>part_id<FS>server_id<FS>serial_or_NULL<FS>last_updated<FS>k1<FS>v1...
|
|
std::vector<std::string> list_parts(uint32_t server_id,
|
|
const std::string& type_filter = "") const;
|
|
std::string get_part_row(uint32_t part_id) const; // empty = not found
|
|
|
|
// Returns all NetworkCard records belonging to the given server.
|
|
std::vector<NetworkCard> get_nics_for_server(uint32_t server_id) const;
|
|
|
|
private:
|
|
std::string path_;
|
|
Inventory inv_;
|
|
mutable std::mutex mu_;
|
|
|
|
// Internal save without acquiring lock (caller must hold mu_)
|
|
bool save_nolock();
|
|
// Internal add_part without acquiring lock
|
|
uint32_t add_part_nolock(const std::string& type_name, uint32_t server_id,
|
|
const std::map<std::string,std::string>& kv);
|
|
|
|
uint32_t alloc_part_id(); // call while holding mu_
|
|
|
|
static std::string escape(const std::string& s);
|
|
static std::string unescape(const std::string& s);
|
|
static void apply_base(PartBase& p, const std::map<std::string,std::string>& kv);
|
|
|
|
// Per-type wire-row serializers
|
|
std::string serialize_memory_stick(const MemoryStick& m) const;
|
|
std::string serialize_memory_slot (const MemorySlot& m) const;
|
|
std::string serialize_cpu (const CPU& c) const;
|
|
std::string serialize_cpu_slot (const CPUSlot& c) const;
|
|
std::string serialize_disk (const Disk& d) const;
|
|
std::string serialize_nic (const NetworkCard& n) const;
|
|
};
|