feat: capture network intent at host discovery #267
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/discover-networking"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Extend the interactive discovery flow so operators record not just the install disk for each host but how it should be networked (bond + mode + interface blacklist), and persist that alongside the role mapping. Downstream scores can consume the intent later; storage now holds at
most one mapping row per host.
What's new
Discovery UX polish
DB hygiene
Follow-up (not in this PR)
OKDSetupPersistNetworkBondScore / HostNetworkConfigurationScore still bond all detected interfaces implicitly — wiring them to read the new HostConfig.network_config is deliberately left for the next PR, once the on-disk shape has landed.
Extend DiscoverHostForRoleScore with three new interactive prompts after the installation-disk selection: - "Configure a network bond?" (only when host has >= 2 NICs), followed by a multi-select of bond members (min 2) and a bond-mode picker (LACP / active-backup / balance-rr / balance-xor / broadcast / balance-tlb / balance-alb). - "Blacklist any remaining interface?", with candidates limited to NICs not already claimed by the bond. The answers are persisted as a JSON-encoded NetworkConfig on a new host_role_mapping.network_config column. HostConfig now exposes network_config alongside installation_device so downstream scores can honor the user's intent. Also adds a new harmony_host_discovery example that discovers a single host on 192.168.40.0/24:25000.- PhysicalHost::summary() becomes terser and more informative: - Storage: "400 GB [8 GB, 477 GB]" (was "400 GB Storage (2 Disks [8 GB, 477 GB])"). Single-disk collapses to just the total. - Network: list every NIC as "[ip, mac]" with a count prefix (e.g. "3 NICs: [192.168.40.10, 98:fa:9b:03:17:6f], [00:e0:ed:7a:ec:4d], ..."). Single-NIC form drops the count and "s": "NIC: [ip, mac]". NICs without an IPv4 render as "[mac]". - Promote the inventory agent's Chipset { vendor, name } into a "system-product-name" label during host conversion (both MDNS and CIDR flows), so summary()'s first field shows "LENOVO 3136" instead of falling back to the HostCategory string ("Server"). Extracted into build_discovered_host_labels() to keep the two conversion sites in sync. When the chipset is blank, the old category fallback still applies. - Print a blank line before every interactive inquire prompt in the discovery flow (role pick, disk pick, bond confirm/multi-select/mode, blacklist confirm/multi-select) so prompts stand out from the preceding log output on the terminal.- SqliteInventoryRepository::save() now compares the incoming serde_json bytes against the latest stored `data` blob for this host_id. If byte-identical, the insert is skipped with an info log "Host '<id>' unchanged, skipping save". Genuine changes still produce a new version row, preserving the audit trail. Eliminates the unbounded row growth from repeated discovery (mDNS is continuous, CIDR scans often re-run). Addresses the long-standing FIXME in modules/inventory; the comment is now removed. - Reworded the caller-side log that fires after repo.save() from "Saved [new] host id X, summary: ..." to "Discovered host X, summary: ...". The old text claimed "Saved" even when the repo had actually skipped the insert, producing contradictory log lines on re-runs. - Harmonized every host-specific inquire prompt in the discovery flow behind a new print_host_header() helper: each prompt is now preceded by a blank line and a "Host: <summary>" banner, and the redundant host name inside the question text is stripped (disk prompt, bond confirm). The node-selection prompt is unchanged -- it picks *which* host, so there is no current host yet.- host_role_mapping now holds at most one row per host_id. SqliteInventoryRepository::save_role_mapping wraps a DELETE of any prior rows for the host and the INSERT of the new one in a single transaction, self-healing pre-existing duplicate rows along the way. - Before re-prompting for disk and networking, the discovery flow looks up the current role mapping via the new InventoryRepository::get_role_mapping(host_id) method. If one exists, the operator sees a summary (role, install disk, bond mode + interfaces, blacklist) and picks between "Update" and "Cancel"; cancelling skips the host entirely and continues the selection loop without touching the DB. New HostRoleMapping domain type carries the returned row back to the caller. - Network interfaces are sorted by name at the hwinfo-to-domain conversion step (both MDNS and CIDR flows), so f0 always appears before f1 in every downstream consumer — host summary, bond multi-select, blacklist multi-select. This also makes the byte-equality dedup in save() robust against the agent returning NICs in different sysfs-walk order across reboots. - PhysicalHost::summary() split into summary_parts_through_storage() + append_network_summary(), with a new public summary_short() variant that omits the NIC list. print_host_header() in the discovery prompts now uses summary_short() so the "Host: ..." banner fits on one line; full summaries still render in the node picker, logs, and Display impl. - Fix CPU summary rendering when the agent reports an empty model: single-CPU renders as "6c/6t", multi-CPU as "2x CPU (12c/24t)", no stray double-space in the pipe-separated summary. - Regenerate .sqlx offline cache for the new DELETE and SELECT queries.- Switch SqliteInventoryRepository to DELETE journal mode with create_if_missing, so `.sqlite-wal` / `.sqlite-shm` files no longer appear next to the DB. Existing WAL-mode DBs are checkpointed and converted on next open. - Print a blank line after prompt_network_config returns so the save logs don't stomp on the last answered question.