Introduces a higher-order topology that wraps two OPNSenseFirewall instances (primary + backup) and orchestrates score application across both. CARP VIPs get differentiated advskew values (primary=0, backup=configurable) while all other scores apply identically to both firewalls. Includes CarpVipScore, DhcpServer delegation, pair Score impls for all existing OPNsense scores, and opnsense_from_config() factory method. Also adds ROADMAP entries for generic firewall trait (10), delegation macro, integration tests, and named config instances (11). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
78 lines
3.7 KiB
Markdown
78 lines
3.7 KiB
Markdown
# Phase 11: Named Config Instances & Cross-Namespace Access
|
|
|
|
## Goal
|
|
|
|
Allow multiple instances of the same config type within a single namespace, identified by name. Also allow explicit namespace specification when retrieving config items, enabling cross-deployment orchestration.
|
|
|
|
## Context
|
|
|
|
The current `harmony_config` system identifies config items by type only (`T::KEY` from `#[derive(Config)]`). This works for singletons but breaks when you need multiple instances of the same type:
|
|
|
|
- **Firewall pair**: primary and backup need separate `OPNSenseApiCredentials` (different API keys for different devices)
|
|
- **Worker nodes**: each BMC has its own `IpmiCredentials` with different username/password
|
|
- **Firewall administrators**: multiple `OPNSenseApiCredentials` with different permission levels
|
|
- **Multi-tenant**: customer firewalls vs. NationTech infrastructure firewalls need separate credential sets
|
|
|
|
Using separate namespaces per device is not the answer — a firewall pair belongs to a single deployment, and forcing namespace switches for each device in a pair adds unnecessary friction.
|
|
|
|
Cross-namespace access is a separate but related need: the NT firewall pair and C1 customer firewall pair live in separate namespaces (the customer manages their own firewall), but NationTech needs read access to the C1 namespace for BINAT coordination.
|
|
|
|
## Tasks
|
|
|
|
### 11.1 Named config instances within a namespace
|
|
|
|
**Priority**: HIGH
|
|
**Status**: Not started
|
|
|
|
Extend the `Config` trait and `ConfigManager` to support an optional instance name:
|
|
|
|
```rust
|
|
// Current (singleton): gets "OPNSenseApiCredentials" from the active namespace
|
|
let creds = ConfigManager::get::<OPNSenseApiCredentials>().await?;
|
|
|
|
// New (named): gets "OPNSenseApiCredentials/fw-primary" from the active namespace
|
|
let primary_creds = ConfigManager::get_named::<OPNSenseApiCredentials>("fw-primary").await?;
|
|
let backup_creds = ConfigManager::get_named::<OPNSenseApiCredentials>("fw-backup").await?;
|
|
```
|
|
|
|
Storage key becomes `{T::KEY}/{instance_name}` (or similar). The unnamed `get()` remains unchanged for backward compatibility.
|
|
|
|
This needs to work across all config sources:
|
|
- `EnvSource`: `HARMONY_CONFIG_{KEY}_{NAME}` (e.g., `HARMONY_CONFIG_OPNSENSE_API_CREDENTIALS_FW_PRIMARY`)
|
|
- `SqliteSource`: composite key `{key}/{name}`
|
|
- `StoreSource` (OpenBao): path `{namespace}/{key}/{name}`
|
|
- `PromptSource`: prompt includes the instance name for clarity
|
|
|
|
### 11.2 Cross-namespace config access
|
|
|
|
**Priority**: MEDIUM
|
|
**Status**: Not started
|
|
|
|
Allow specifying an explicit namespace when retrieving a config item:
|
|
|
|
```rust
|
|
// Get from the active namespace (current behavior)
|
|
let nt_creds = ConfigManager::get::<OPNSenseApiCredentials>().await?;
|
|
|
|
// Get from a specific namespace
|
|
let c1_creds = ConfigManager::get_from_namespace::<OPNSenseApiCredentials>("c1").await?;
|
|
```
|
|
|
|
This enables orchestration across deployments: the NT deployment can read C1's firewall credentials for BINAT coordination without switching the global namespace.
|
|
|
|
For the `StoreSource` (OpenBao), this maps to reading from a different KV path prefix. For `SqliteSource`, it maps to a different database file or a namespace column. For `EnvSource`, it could use a different prefix (`HARMONY_CONFIG_C1_{KEY}`).
|
|
|
|
### 11.3 Update FirewallPairTopology to use named configs
|
|
|
|
**Priority**: MEDIUM
|
|
**Status**: Blocked by 11.1
|
|
|
|
Once named config instances are available, update `FirewallPairTopology::opnsense_from_config()` to use them:
|
|
|
|
```rust
|
|
let primary_creds = ConfigManager::get_named::<OPNSenseApiCredentials>("fw-primary").await?;
|
|
let backup_creds = ConfigManager::get_named::<OPNSenseApiCredentials>("fw-backup").await?;
|
|
```
|
|
|
|
This removes the current limitation of shared credentials between primary and backup.
|