Skip to content

Commit

Permalink
Support networkd RequiredForOnline option
Browse files Browse the repository at this point in the history
Implement the "optional" ethernet interface property for the networkd
renderer. Marks an interface as not required for the network-online
target.
  • Loading branch information
dankm committed Nov 1, 2024
1 parent 96a07fb commit f033ac3
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 1 deletion.
7 changes: 6 additions & 1 deletion cloudinit/net/network_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"set-name",
"wakeonlan",
"accept-ra",
"optional",
]

NET_CONFIG_TO_V2: Dict[str, Dict[str, Any]] = {
Expand Down Expand Up @@ -409,6 +410,9 @@ def handle_physical(self, command):
wakeonlan = command.get("wakeonlan", None)
if wakeonlan is not None:
wakeonlan = util.is_true(wakeonlan)
optional = command.get("optional", None)
if optional is not None:
optional = util.is_true(optional)
iface.update(
{
"config_id": command.get("config_id"),
Expand All @@ -423,6 +427,7 @@ def handle_physical(self, command):
"subnets": subnets,
"accept-ra": accept_ra,
"wakeonlan": wakeonlan,
"optional": optional,
}
)
iface_key = command.get("config_id", command.get("name"))
Expand Down Expand Up @@ -747,7 +752,7 @@ def handle_ethernets(self, command):
driver = match.get("driver", None)
if driver:
phy_cmd["params"] = {"driver": driver}
for key in ["mtu", "match", "wakeonlan", "accept-ra"]:
for key in ["mtu", "match", "wakeonlan", "accept-ra", "optional"]:
if key in cfg:
phy_cmd[key] = cfg[key]

Expand Down
3 changes: 3 additions & 0 deletions cloudinit/net/networkd.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ def generate_link_section(self, iface, cfg: CfgParser):
if "mtu" in iface and iface["mtu"]:
cfg.update_section(sec, "MTUBytes", iface["mtu"])

if "optional" in iface and iface["optional"]:
cfg.update_section(sec, "RequiredForOnline", "no")

def parse_routes(self, rid, conf, cfg: CfgParser):
"""
Parse a route and use rid as a key in order to isolate the route from
Expand Down
8 changes: 8 additions & 0 deletions doc/rtd/reference/network-config-format-v2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,14 @@ The MTU key represents a device's Maximum Transmission Unit, the largest size
packet or frame, specified in octets (eight-bit bytes), that can be sent in a
packet- or frame-based network. Specifying ``mtu`` is optional.

``optional: <(bool)>``
------------------------

Mark a device as not required for booting. By default networkd will wait for
all configured interfaces to be configured before continuing to boot. This
option causes networkd to not wait for the interface. This is only supported
by networkd. The default is false.

``nameservers: <(mapping)>``
----------------------------

Expand Down
40 changes: 40 additions & 0 deletions tests/unittests/net/test_networkd.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,35 @@
from cloudinit import safeyaml
from cloudinit.net import network_state, networkd

V2_CONFIG_OPTIONAL = """\
network:
version: 2
ethernets:
eth0:
optional: true
eth1:
optional: false
"""

V2_CONFIG_OPTIONAL_RENDERED_ETH0 = """[Link]
RequiredForOnline=no
[Match]
Name=eth0
[Network]
DHCP=no
"""

V2_CONFIG_OPTIONAL_RENDERED_ETH1 = """[Match]
Name=eth1
[Network]
DHCP=no
"""

V2_CONFIG_SET_NAME = """\
network:
version: 2
Expand Down Expand Up @@ -452,6 +481,17 @@ def _parse_network_state_from_config(self, config):
config = yaml.safe_load(config)
return network_state.parse_net_config_data(config["network"])

def test_networkd_render_with_optional(self):
with mock.patch("cloudinit.net.get_interfaces_by_mac"):
ns = self._parse_network_state_from_config(V2_CONFIG_OPTIONAL)
renderer = networkd.Renderer()
rendered_content = renderer._render_content(ns)

assert "eth0" in rendered_content
assert rendered_content["eth0"] == V2_CONFIG_OPTIONAL_RENDERED_ETH0
assert "eth1" in rendered_content
assert rendered_content["eth1"] == V2_CONFIG_OPTIONAL_RENDERED_ETH1

def test_networkd_render_with_set_name(self):
with mock.patch("cloudinit.net.get_interfaces_by_mac"):
ns = self._parse_network_state_from_config(V2_CONFIG_SET_NAME)
Expand Down

0 comments on commit f033ac3

Please sign in to comment.