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
17 changes: 14 additions & 3 deletions cloudinit/sources/DataSourceOpenNebula.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,22 @@ def mac2ip(self, mac: str) -> str:

def get_nameservers(self, dev: str) -> Dict[str, List[str]]:
nameservers: Dict[str, List[str]] = {}
dns = self.get_field(dev, "dns", "").split()
dns.extend(self.context.get("DNS", "").split())
dns: List[str] = []
for server in (
self.get_field(dev, "dns", "").split()
+ self.context.get("DNS", "").split()
):
if server not in dns:
dns.append(server)
if dns:
nameservers["addresses"] = dns
search_domain = self.get_field(dev, "search_domain", "").split()
search_domain: List[str] = []
for domain in (
self.get_field(dev, "search_domain", "").split()
+ self.context.get("SEARCH_DOMAIN", "").split()
):
if domain not in search_domain:
Comment thread
mcanevet marked this conversation as resolved.
search_domain.append(domain)
if search_domain:
nameservers["search"] = search_domain
return nameservers
Expand Down
8 changes: 7 additions & 1 deletion doc/rtd/reference/datasources/opennebula.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ the OpenNebula documentation.
::

DNS
SEARCH_DOMAIN
ETH<x>_IP
ETH<x>_NETWORK
ETH<x>_MASK
Expand All @@ -74,7 +75,12 @@ the OpenNebula documentation.
ETH<x>_IP6_GATEWAY
ETH<x>_ROUTES

Static `network configuration`_.
Static `network configuration`_. ``DNS`` and ``SEARCH_DOMAIN`` are global
values applied to every interface. Per-interface ``ETH<x>_DNS`` and
``ETH<x>_SEARCH_DOMAIN`` (defined in `context-linux`_) take precedence;
duplicate entries across both levels are suppressed.

.. _context-linux: https://github.com/OpenNebula/one-apps/blob/v7.0.0/context-linux/src/etc/one-context.d/loc-10-network.d/functions#L463-L466

``ETH<x>_ROUTES`` is a comma-separated list of static routes in the form
``NETWORK via GATEWAY``. For example::
Expand Down
78 changes: 78 additions & 0 deletions tests/unittests/sources/test_opennebula.py
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,84 @@ def test_multiple_nics(self):

assert expected == net.gen_conf()

@pytest.mark.parametrize(
"context,expected_search",
[
pytest.param(
{"SEARCH_DOMAIN": "global.example.com global.example.org"},
["global.example.com", "global.example.org"],
id="global_only",
),
pytest.param(
{
"ETH0_SEARCH_DOMAIN": "iface.example.com",
"SEARCH_DOMAIN": "global.example.com",
},
["iface.example.com", "global.example.com"],
id="per_interface_and_global",
),
pytest.param(
{"ETH0_SEARCH_DOMAIN": "iface.example.com"},
["iface.example.com"],
id="per_interface_only",
),
pytest.param(
{
"ETH0_SEARCH_DOMAIN": "shared.example.com",
# extra precedes shared in global; shared must still come
# first because per-interface ordering takes precedence
"SEARCH_DOMAIN": "extra.example.com shared.example.com",
},
["shared.example.com", "extra.example.com"],
id="dedup_iface_order_preferred",
),
],
)
def test_get_nameservers_search_domain(self, context, expected_search):
"""get_nameservers merges and deduplicates SEARCH_DOMAIN correctly."""
net = ds.OpenNebulaNetwork(context, mock.Mock())
val = net.get_nameservers("eth0")
assert val["search"] == expected_search

@mock.patch(DS_PATH + ".get_physical_nics_by_mac")
def test_gen_conf_global_search_domain(self, m_get_phys_by_mac):
"""gen_conf includes global SEARCH_DOMAIN in nameservers.search."""
context = {
"ETH0_MAC": MACADDR,
"SEARCH_DOMAIN": "global.example.com",
}
for nic in self.system_nics:
m_get_phys_by_mac.return_value = {MACADDR: nic}
net = ds.OpenNebulaNetwork(context, mock.Mock())
conf = net.gen_conf()
assert conf["ethernets"][nic]["nameservers"]["search"] == [
"global.example.com"
]

@mock.patch(DS_PATH + ".get_physical_nics_by_mac")
def test_gen_conf_global_search_domain_multiple_nics(
self, m_get_phys_by_mac
):
"""Global SEARCH_DOMAIN appears on every NIC."""
MAC_1 = "02:00:0a:12:01:01"
MAC_2 = "02:00:0a:12:01:02"
context = {
"ETH0_MAC": MAC_1,
"ETH1_MAC": MAC_2,
"SEARCH_DOMAIN": "global.example.com",
}
net = ds.OpenNebulaNetwork(
context,
mock.Mock(),
system_nics_by_mac={MAC_1: "eth0", MAC_2: "eth1"},
)
conf = net.gen_conf()
for nic in ("eth0", "eth1"):
assert (
"global.example.com"
in conf["ethernets"][nic]["nameservers"]["search"]
)

# ------------------------------------------------------------------ #
# ETHx_ROUTES #
# ------------------------------------------------------------------ #
Expand Down
Loading