Feature Specification: Resource network
Created: 2026-10-07
Status: Implemented
Input: Reconstructed from the code of core/resources/network/ and the setup wiring at 093e68b6f, pull requests #1184, #1205, #1235 and #1238.
User Scenarios & Testing (mandatory)
The network resource turns the network facts of one machine into its operating system configuration: host name, domain, resolvers, static addresses and default gateways. It has a policy only. No component requests it, and the policy ignores requests. It wraps no contract. An address that NetBox allocates takes the place of the address in the settings. On an incus node, the node reads that address at run time from the incus guest API. The shared resource rules are in the resource family spec.
User Story 1 - Configure a machine from its roster entry (Priority: P1)
A hosting provider lists a machine in the roster with its name and its IPv4 and IPv6 facts. The setup gives these facts to the policy of the node, adds the group domain, and, where the group's own DNS nodes hold the apex, adds the addresses of these DNS nodes as resolvers.
Why this priority: a node without its address and name cannot join the deployment.
Independent Test: a unit test of the rendered module (host name check, resolver order, address split), and a unit test of the values that the setup gives the policy.
Acceptance Scenarios:
- Given an address in CIDR form, When the module evaluates, Then the interface holds that address with that prefix length.
- Given an address without a prefix length, When the module evaluates, Then the interface uses the usual prefix length of its family (a
/24for IPv4, a/64for IPv6). - Given a name that is not a valid host label (for example an IP address), When the module evaluates, Then the machine keeps the default host name of the system.
User Story 2 - Fit the routes to the uplink (Priority: P1)
The uplink type is a property of the hosting provider's topology: the public address reaches the machine either bridged or through NAT. A machine behind a NAT bridge, or with a placeholder gateway in its roster entry, must not get a default route: that route shadows the route that the bridge gives over DHCP, and all egress fails. On incus methods, the setup takes the uplink type, and for a node that the uplink delivers to, the interface and the gateways, from the deployment.
Why this priority: a wrong default route takes all egress away from the machine. The same machine data serves several topologies.
Independent Test: a unit test of the gateway decision in the rendered module, and a unit test of the uplink values that the setup states.
Acceptance Scenarios:
- Given a NAT uplink, When the module evaluates, Then no default gateway is set.
- Given a missing or empty gateway, When the module evaluates, Then no default gateway is set for that family.
- Given a bridged uplink and a real gateway, When the module evaluates, Then the default route uses that gateway on the stated interface.
- Given an incus method and a node that the uplink delivers to, When the policy evaluates, Then the interface and the gateways come from the uplink, and override the roster.
- Given a method that is not an incus method, When the policy evaluates, Then the uplink does not change the policy.
User Story 3 - Use the address that NetBox allocates (Priority: P1)
On tf-incus methods, NetBox allocates the public address of a node. The address is not in the plan or in the closure of the node. The deployment program puts the address of each family on the instance through the incus guest API, together with the addresses of all nodes of the deployment as peers. The node reads these values at boot and again on each change of the guest API. It applies the address and the gateway to its interface, and gives the peer addresses to the firewall gate, which admits them as host addresses (firewall spec). Thus a changed address gets to the running node without a deploy, and does not change the closure of the node.
Why this priority: without its allocated address, a node on a tf-incus method has no public address.
Independent Test: unit tests that a node that reads the guest API renders no static address, and does not need the network resource; a decision test of the guest API values of a public node and of an internal node; a VM test that changes the address of a running node and waits until its interface carries the new address.
Acceptance Scenarios:
- Given a node that reads its addresses from the guest API, When the module evaluates, Then the configuration holds no static address and no default gateway, and the node applies them at run time.
- Given a running incus node, When its allocated address changes, Then the interface gets the new address and loses the old one without a deploy.
Edge Cases
- The domain has no default. A node evaluated without the setup fails on the missing value.
- A missing address adds no interface address and no gateway.
- An allocated address in one family only leaves the other family at the address of the settings.
- On a node that reads the guest API, a family without a guest API value uses the address of the settings. A family with neither gets no interface configuration.
- A guest API address without a prefix length gets the usual prefix length of its family.
- A deployment in which no node has an address puts no peer list on the instances.
Requirements (mandatory)
Functional Requirements
- FR-001: The policy MUST accept the domain, a list of resolvers, a host name, the uplink type (bridged or NAT), and per address family the interface, the address and the gateway. Each fact except the domain MUST have a default.
- FR-002: The module MUST set the domain of the machine, and MUST put the resolvers of the policy before any other resolvers of the machine.
- FR-003: The module MUST set the host name only when the name is a valid host label.
- FR-004: The module MUST accept an address in CIDR form and split it into the address and the prefix length.
- FR-005: The module MUST set a default gateway only when the uplink is not NAT, the address is set, and the gateway is not a placeholder (missing or empty).
- FR-006: The setup MUST give every node that it deploys the group domain.
- FR-007: When no external service holds the apex, the setup MUST give each node that is not a DNS node the IPv4 and IPv6 addresses of all DNS nodes of the deployment as resolvers.
- FR-008: On a node that reads its addresses from the guest API, the module MUST NOT render the address and the gateways of the settings.
- FR-009: On an incus method, every node MUST read its addresses from the guest API. The deployment program MUST NOT put the allocated addresses into the plan.
- FR-010: The deployment program MUST give each instance, per family, the address in CIDR form that NetBox allocates to it, and no value for a family without an address. It MUST give each instance the list of the addresses of all nodes of the deployment, sorted and without duplicates, and no list when no node has an address.
- FR-011: A node that reads the guest API MUST apply the address of each family (from the guest API, else from the settings) with the gateway that FR-005 allows, before its network starts and again on each change of the guest API.
Key Entities
- Machine network entry: the network facts of a machine in the roster: name, IPv4 and IPv6.
- Allocated address: an address in CIDR form that NetBox allocates to a node, and that the node reads from the guest API of its instance.
- Uplink type: how the public address reaches the machine: bridged or through NAT.
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: the unit tests of the resource and of the uplink wiring pass.
Assumptions
- The roster gives each machine a network entry.
- A NetBox-allocated address arrives in CIDR form.
Known Deviations
- The policy accepts a flag that says whether a node needs a public address, but nothing reads it (#2131). Its description says that the setup skips the NetBox allocation for a node that sets it to false. The setup derives this fact from the list of public nodes instead.