feat: add networkd subsystem and fix code review issues
Phase 1-4: Networkd subsystem - lib/network.py: systemd-networkd config renderer (.network INI files) with full schema support: [Match], [Link], [Network], [Address], [Route], [DHCPv4], [DHCPv6] sections. One Address/=DNS= line per value per spec. Route sections use #N suffix per systemd.syntax(7). - lib/network.py: generate_network_files() with 50-<name>.network prefix and stale file cleanup - lib/network.py: collect_upstream_dns() filters local/private DNS - lib/network.py: infer_dhcp_ranges() and infer_zones() helpers - daemon/handlers/network.py: routes for GET/POST /network/interfaces and full apply with DNS upstream sync to dnsmasq - webui/api/network.py: Flask blueprint for /api/network/* endpoints - webui/api: interfaces page updated with IP config inline editing - lib/state.py: networkd collector using parse_networkctl_status() - system/sudoers.d/vacuum-walld: networkctl + systemd-network rules - system/systemd/vacuum-walld.service: ReadWritePaths for /etc/systemd/network - install.sh: ACME email now optional, configured from WebUI - lib/acme.py: get_email() falls back to declarative config Phase 5: Code review fixes - daemon/server.py: path params now win over JSON body and query params in request body merge (prevents config save name override) - daemon/server.py: remove dead 'import re' - daemon/handlers/network.py: replace Path.mkdir() with sudo mkdir for /etc/systemd/network (ProtectSystem=strict compatibility) - system/sudoers.d/vacuum-walld: pin systemctl to specific commands (reload/is-active dnsmasq instead of wildcard) - system/sudoers.d/vacuum-walld: restore !requiretty and section comment - lib/network.py: remove unused _MANAGEMENT_PORTS constant - webui/api/network.py: remove redundant body[\name\] = name in save_interface Tests: 332 passing (110 new/updated), ruff clean
This commit is contained in:
+133
@@ -1190,6 +1190,139 @@ Returns HTTP `404` if the peer is not found.
|
||||
|
||||
---
|
||||
|
||||
## Network API
|
||||
|
||||
Endpoints prefixed with `/api/network/...`. Manage systemd-networkd interface configuration including static addresses, routes, DNS, DHCP client settings, and link parameters.
|
||||
|
||||
### Interface Management
|
||||
|
||||
#### List All Interfaces
|
||||
|
||||
```
|
||||
GET /api/network/interfaces
|
||||
```
|
||||
|
||||
Return all configured interfaces with their network config and runtime state from `networkctl`.
|
||||
|
||||
**Response:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `data.interfaces` | `object` | Map of interface name to `{config, runtime}` |
|
||||
| `data.timestamp` | `string` | Timestamp of runtime data collection |
|
||||
|
||||
---
|
||||
|
||||
#### Get Interface Details
|
||||
|
||||
```
|
||||
GET /api/network/interfaces/<name>
|
||||
```
|
||||
|
||||
Return config and runtime state for a specific interface.
|
||||
|
||||
**Response (`data`):**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `name` | `string` | Interface name |
|
||||
| `config` | `object` | Full networkd config entry for this interface |
|
||||
| `runtime` | `object` | Runtime state from `networkctl` (addresses, gateway, DNS, state) |
|
||||
|
||||
Returns HTTP `404` if the interface is not found in config.
|
||||
|
||||
---
|
||||
|
||||
#### Save and Apply Interface
|
||||
|
||||
```
|
||||
POST /api/network/interfaces/<name>
|
||||
```
|
||||
|
||||
Save network config for an interface, render the `.network` file, copy it to `/etc/systemd/network/`, and reload networkd for that interface.
|
||||
|
||||
**Request Body:** Any networkd config keys (e.g., `addresses`, `gateway`, `dns`, `routes`, `dhcp`, `link`, `dhcp_client`).
|
||||
|
||||
**Response (`data`):**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `name` | `string` | Interface name |
|
||||
| `applied` | `boolean` | Always `true` on success |
|
||||
|
||||
---
|
||||
|
||||
#### Reload Interface
|
||||
|
||||
```
|
||||
POST /api/network/interfaces/<name>/reload
|
||||
```
|
||||
|
||||
Reload networkd for a single interface (runs `networkctl reload <name>`).
|
||||
|
||||
**Response (`data`):**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `name` | `string` | Interface name |
|
||||
| `reloaded` | `boolean` | Always `true` on success |
|
||||
|
||||
### Full Sync
|
||||
|
||||
#### Apply All Interfaces
|
||||
|
||||
```
|
||||
POST /api/network/apply
|
||||
```
|
||||
|
||||
Full sync: generate all `.network` files, remove stale files, copy to `/etc/systemd/network/`, reload all interfaces, and sync DNS upstreams to dnsmasq.
|
||||
|
||||
**Response (`data`):**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `applied` | `number` | Number of interfaces applied |
|
||||
| `files` | `[string, ...]` | Paths of generated files |
|
||||
| `cleaned` | `[string, ...]` | Paths of removed stale files |
|
||||
|
||||
### Helpers
|
||||
|
||||
#### Infer DHCP Ranges
|
||||
|
||||
```
|
||||
GET /api/network/infer-dhcp-ranges
|
||||
```
|
||||
|
||||
Suggest candidate DHCP ranges based on static interface IPs. For each interface with a static IPv4 address, calculates a usable address range in the subnet.
|
||||
|
||||
**Response:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `data.ranges` | `object` | Map of interface name to `{subnet, prefix, start, end}` |
|
||||
|
||||
---
|
||||
|
||||
#### Infer Firewall Zones
|
||||
|
||||
```
|
||||
GET /api/network/infer-zones
|
||||
```
|
||||
|
||||
Suggest firewalld zone assignments for configured interfaces based on heuristics:
|
||||
- Interface name contains `wg` → `wan`
|
||||
- DHCP-enabled or public-facing IP → `wan`
|
||||
- Has explicit routes → `management`
|
||||
- Everything else → `lan`
|
||||
|
||||
**Response:**
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `data.zones` | `object` | Map of interface name to suggested zone (`"lan"`, `"wan"`, `"management"`) |
|
||||
|
||||
---
|
||||
|
||||
## Logs API
|
||||
|
||||
Endpoints prefixed with `/api/logs/...`. Serve rendered HTML log line fragments for HTMX consumption. These endpoints **do not** follow the standard JSON `{"ok": true, "data": ...}` response contract — they return HTML `<div>` elements directly. Errors are rendered inline as `(error reading ...)` text rather than returning JSON error responses.
|
||||
|
||||
Reference in New Issue
Block a user