Skip to content

feat(opennebula): support ETHx_METRIC for default route priority#6811

Open
mcanevet wants to merge 1 commit intocanonical:mainfrom
mcanevet:feat/opennebula-eth-metric
Open

feat(opennebula): support ETHx_METRIC for default route priority#6811
mcanevet wants to merge 1 commit intocanonical:mainfrom
mcanevet:feat/opennebula-eth-metric

Conversation

@mcanevet
Copy link
Copy Markdown
Contributor

Proposed Commit Message

feat(opennebula): support ETHx_METRIC for default route priority

Add `get_metric()` to `OpenNebulaNetwork` and use it in `gen_conf()`.
When `ETHx_METRIC` is set, the default gateway is emitted as an explicit
Netplan v2 `routes:` entry with the metric attached, rather than the
simpler `gateway4:` key. When the variable is absent the existing
`gateway4:` behaviour is preserved.

This allows correct route priority on multi-homed VMs: setting
`ETH0_METRIC=0` and `ETH1_METRIC=1` ensures interface 0 is the
preferred default route.

Additional Context

The OpenNebula context-linux package (one-apps) supports ETHx_METRIC
to set the route metric for the default gateway on each interface.
Without this, multi-homed VMs (common in OpenNebula deployments using
tools like netbox-network-config) have no way to express route priority
and the kernel picks an arbitrary default route.

The fix is minimal: when ETHx_METRIC is present the gateway4: key is
replaced by an explicit routes: entry carrying the metric. When the
variable is absent behaviour is identical to before.

Test Steps

On a multi-homed OpenNebula VM, add to the VM template context:

ETH0_GATEWAY="10.0.0.1"
ETH0_METRIC="0"
ETH1_GATEWAY="185.70.43.1"
ETH1_METRIC="1"

After boot, verify route priorities:

ip route show
# expected: default via 10.0.0.1 dev eth0 metric 0
#           default via 185.70.43.1 dev eth1 metric 1

Also verify that a VM with no ETHx_METRIC set continues to produce
gateway4: in its Netplan config without any change in behaviour.

Merge type

  • Squash merge using "Proposed Commit Message"
  • Rebase and merge unique commits. Requires commit messages per-commit each referencing the pull request number (#<PR_NUM>)

@github-actions github-actions Bot added the documentation This Pull Request changes documentation label Mar 30, 2026
@mcanevet mcanevet force-pushed the feat/opennebula-eth-metric branch 4 times, most recently from 93e1974 to f834651 Compare April 1, 2026 08:29
@github-actions
Copy link
Copy Markdown

Hello! Thank you for this proposed change to cloud-init. This pull request is now marked as stale as it has not seen any activity in 14 days. If no activity occurs within the next 7 days, this pull request will automatically close.

If you are waiting for code review and you are seeing this message, apologies! Please reply, tagging blackboxsw, and he will ensure that someone takes a look soon.

(If the pull request is closed and you would like to continue working on it, please do tag blackboxsw to reopen it.)

@github-actions github-actions Bot added the stale-pr Pull request is stale; will be auto-closed soon label Apr 16, 2026
@blackboxsw blackboxsw removed the stale-pr Pull request is stale; will be auto-closed soon label Apr 21, 2026
@mcanevet mcanevet force-pushed the feat/opennebula-eth-metric branch from f834651 to 6de0417 Compare April 22, 2026 06:27
@mcanevet
Copy link
Copy Markdown
Contributor Author

@blackboxsw rebased

Add `get_metric()` to `OpenNebulaNetwork` and use it in `gen_conf()`.
When `ETHx_METRIC` is set, the default gateway is emitted as an explicit
Netplan v2 `routes:` entry with the metric attached, rather than the
simpler `gateway4:` key. When the variable is absent the existing
`gateway4:` behaviour is preserved.

This allows correct route priority on multi-homed VMs: setting
`ETH0_METRIC=0` and `ETH1_METRIC=1` ensures interface 0 is the
preferred default route.
Copilot AI review requested due to automatic review settings May 5, 2026 14:28
@mcanevet mcanevet force-pushed the feat/opennebula-eth-metric branch from 6de0417 to 995ab92 Compare May 5, 2026 14:28
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the OpenNebula datasource’s Netplan v2 generation to support per-interface default-route priority via ETH<x>_METRIC, aligning cloud-init behavior with OpenNebula’s context-linux contextualization variables for multi-homed VMs.

Changes:

  • Add OpenNebulaNetwork.get_metric() and use it in gen_conf() to emit the IPv4 default gateway as an explicit routes: entry with metric when ETH<x>_METRIC is set (otherwise preserve gateway4: behavior).
  • Add unit tests covering get_metric() and the gen_conf() metric-based route emission behavior.
  • Document ETH<x>_METRIC in the OpenNebula datasource reference.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
cloudinit/sources/DataSourceOpenNebula.py Adds metric lookup and conditionally emits default route with a metric using Netplan routes:.
tests/unittests/sources/test_opennebula.py Adds unit tests for ETH<x>_METRIC parsing and Netplan config output.
doc/rtd/reference/datasources/opennebula.rst Documents the new ETH<x>_METRIC contextualization variable and its effect on default routing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +320 to +327
if metric is not None:
devconf.setdefault("routes", []).append(
{
"to": "default",
"via": gateway,
"metric": int(metric),
}
)
Comment on lines +321 to +327
devconf.setdefault("routes", []).append(
{
"to": "default",
"via": gateway,
"metric": int(metric),
}
)
Comment on lines +1067 to +1083
@mock.patch(DS_PATH + ".get_physical_nics_by_mac")
def test_gen_conf_metric_replaces_gateway4(self, m_get_phys_by_mac):
"""When metric is set, gateway is emitted as an explicit route."""
context = {
"ETH0_MAC": MACADDR,
"ETH0_IP": PUBLIC_IP,
"ETH0_GATEWAY": "10.0.0.1",
"ETH0_METRIC": "100",
}
m_get_phys_by_mac.return_value = {MACADDR: "eth0"}
net = ds.OpenNebulaNetwork(context, mock.Mock())
conf = net.gen_conf()
eth0 = conf["ethernets"]["eth0"]
assert "gateway4" not in eth0
expected_route = {"to": "default", "via": "10.0.0.1", "metric": 100}
assert expected_route in eth0["routes"]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation This Pull Request changes documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants