Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cloudinit/net/network_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,13 @@ def render_interface(self, iface, network_state, renderer):

# Parse type-specific properties
for nm_prop, key in _prop_map[if_type].items():
# Either dashes or underscores may separate the words in a
# bond option name: v1 config uses underscores
# (bond-fail_over_mac) while v2-derived config uses dashes
# (bond-fail-over-mac). Accept both spellings, as the
# sysconfig and eni renderers already do.
if key not in iface:
key = key.replace("_", "-")
if key not in iface:
continue
if iface[key] is None:
Expand Down
111 changes: 111 additions & 0 deletions tests/unittests/net/test_network_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,117 @@ def test_bond_dns_baseline(self, tmpdir):
rendered_content = dir2dict(target)
assert_equal_dict(expected_config, rendered_content)

def test_bond_multiword_options_from_v2(self, tmpdir):
"""Multi-word bond options from a v2 config reach the NM keyfile.

v2 config produces dash-separated internal keys
(bond-fail-over-mac), while the NM property map is keyed with
underscores. Options like fail-over-mac-policy,
primary-reselect-policy and transmit-hash-policy used to be
silently dropped from the rendered bond. See GH-6932.
"""
config = textwrap.dedent(
"""\
version: 2
ethernets:
eth0:
match:
macaddress: 'xx:xx:xx:xx:xx:00'
eth1:
match:
macaddress: 'xx:xx:xx:xx:xx:01'
bonds:
bond0:
interfaces:
- eth0
- eth1
parameters:
mode: active-backup
fail-over-mac-policy: active
primary-reselect-policy: always
transmit-hash-policy: layer3+4
"""
)

expected_config = {
"/etc/NetworkManager/system-connections/cloud-init-bond0.nmconnection": textwrap.dedent( # noqa: E501
"""\
# Generated by cloud-init. Changes will be lost.

[connection]
id=cloud-init bond0
uuid=54317911-f840-516b-a10d-82cb4c1f075c
autoconnect-priority=120
type=bond
interface-name=bond0

[user]
org.freedesktop.NetworkManager.origin=cloud-init

[bond]
mode=active-backup
xmit_hash_policy=layer3+4
fail_over_mac=active
primary_reselect=always

[ipv4]
method=disabled
may-fail=false

[ipv6]
method=disabled
may-fail=false

"""
),
"/etc/NetworkManager/system-connections/cloud-init-eth0.nmconnection": textwrap.dedent( # noqa: E501
"""\
# Generated by cloud-init. Changes will be lost.

[connection]
id=cloud-init eth0
uuid=1dd9a779-d327-56e1-8454-c65e2556c12c
autoconnect-priority=120
type=ethernet
slave-type=bond
master=54317911-f840-516b-a10d-82cb4c1f075c

[user]
org.freedesktop.NetworkManager.origin=cloud-init

[ethernet]
mac-address=XX:XX:XX:XX:XX:00

"""
),
"/etc/NetworkManager/system-connections/cloud-init-eth1.nmconnection": textwrap.dedent( # noqa: E501
"""\
# Generated by cloud-init. Changes will be lost.

[connection]
id=cloud-init eth1
uuid=3c50eb47-7260-5a6d-801d-bd4f587d6b58
autoconnect-priority=120
type=ethernet
slave-type=bond
master=54317911-f840-516b-a10d-82cb4c1f075c

[user]
org.freedesktop.NetworkManager.origin=cloud-init

[ethernet]
mac-address=XX:XX:XX:XX:XX:01

"""
),
}
with mock.patch("cloudinit.net.get_interfaces_by_mac"):
ns = self._parse_network_state_from_config(config)
target = str(tmpdir)
network_manager.Renderer().render_network_state(ns, target=target)
rendered_content = dir2dict(target)
assert_equal_dict(expected_config, rendered_content)

def test_bond_dns_redacted_with_method_disabled(self, tmpdir):

config = textwrap.dedent(
Expand Down