Skip to content

feat(opennebula): support ETHx_ROUTES static routes in network config#6810

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

feat(opennebula): support ETHx_ROUTES static routes in network config#6810
mcanevet wants to merge 1 commit intocanonical:mainfrom
mcanevet:feat/opennebula-eth-routes

Conversation

@mcanevet
Copy link
Copy Markdown

Proposed Commit Message

feat(opennebula): support ETHx_ROUTES static routes in network config

Add `get_routes()` to `OpenNebulaNetwork` to parse the `ETHx_ROUTES`
context variable (format: "NETWORK via GATEWAY, ...") and emit the
resulting routes into the Netplan v2 `routes:` list in `gen_conf()`.

Malformed entries are skipped with a warning. No `routes` key is
emitted when the variable is absent or empty, preserving backward
compatibility.

Additional Context

The OpenNebula context-linux package (one-apps) supports ETHx_ROUTES
to configure static routes per interface. cloud-init's OpenNebula
datasource was silently ignoring this variable, meaning any static
routes defined in the VM template were never applied.

Test Steps

On an OpenNebula VM, add to the VM template context section:

ETH0_ROUTES="10.0.0.0/8 via 192.168.1.1, 172.16.0.0/12 via 192.168.1.254"

After boot, verify the routes were applied:

ip route show
# expected: routes to 10.0.0.0/8 and 172.16.0.0/12 via 192.168.1.x

Also verify that a VM with no ETHx_ROUTES set continues to boot and
configure networking 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-routes branch 2 times, most recently from 8c4e264 to e5efa6e Compare March 30, 2026 16:16
@holmanb
Copy link
Copy Markdown
Member

holmanb commented Mar 30, 2026

Hey @mcanevet. What is your goal and intent with these PRs? It doesn't look like you are trying to a single missing feature. Are you employed by Open Nebula?

@mcanevet
Copy link
Copy Markdown
Author

I'm just trying to add support for context variables that are honored by Open Nebula's official agent. And I'm not working for them, just a simple user that would like to use cloud-init with complex network configuration. Do you prefer a single PR for all of this?

@mcanevet mcanevet force-pushed the feat/opennebula-eth-routes branch from e5efa6e to eff0ece Compare April 1, 2026 08:06
Add `get_routes()` to `OpenNebulaNetwork` to parse the `ETHx_ROUTES`
context variable (format: "NETWORK via GATEWAY, ...") and emit the
resulting routes into the Netplan v2 `routes:` list in `gen_conf()`.

Malformed entries are skipped with a warning. No `routes` key is emitted
when the variable is absent or empty, preserving backward compatibility.
@mcanevet mcanevet force-pushed the feat/opennebula-eth-routes branch from eff0ece to 3d4c3f9 Compare April 1, 2026 08:28
@mcanevet
Copy link
Copy Markdown
Author

mcanevet commented Apr 1, 2026

@holmanb do you prefer a single PR to implement this feature that reduces the gap between the OpenNebula agent (https://github.com/OpenNebula/one-apps/tree/master/context-linux) and Cloud-init? We basically need this to use cloud-init with standard OpenNebula context variables that the official agent support.

@holmanb
Copy link
Copy Markdown
Member

holmanb commented Apr 1, 2026

I have a few concerns:

  1. The proposed PR would change existing behavior, so stable distros would need to patch these changes out.
  2. The OpenNebula Python datasource code type checking is disabled (see pyproject.toml). If the existing code first passed mypy's checks, it would be easier to have confidence in subsequent changes to this code.
  3. Not something that you are responsible for or that I expect you to change, but Opennebula's design choice to provide a bash script as the source of platform information is not ideal for consuming that information from Python.

Additionally, I would like to see the the full cloud-init logs on the system that you tested these changes on as well as from an instance without these changes applied - as well as a context.sh file content.

mcanevet added a commit to mcanevet/cloud-init that referenced this pull request Apr 2, 2026
- Add type annotations to DataSourceOpenNebula.py
- Add type annotations to read_context_disk_dir() function
- Add type annotation for gen_conf() return type
- Use assertions for type narrowing where needed
- Add type: ignore for mock assignment in tests

Addresses concern from PR canonical#6810 about type checking being disabled.
mcanevet added a commit to mcanevet/cloud-init that referenced this pull request Apr 2, 2026
Add type annotations to DataSourceOpenNebula.py to address concerns
raised in PR canonical#6810 about type checking being disabled for the
OpenNebula datasource.

Refs canonicalGH-6810
@mcanevet
Copy link
Copy Markdown
Author

mcanevet commented Apr 2, 2026

Hi @holmanb,

regarding first concern about changing existing behavior:

Looking at the diff, I believe this change is purely additive. The get_routes() method is new, and in gen_conf() the routes key is only added to the device config when ETHx_ROUTES is explicitly present in the context variables:

extra_routes = self.get_routes(c_dev)
if extra_routes:
  devconf["routes"] = extra_routes

If ETHx_ROUTES is absent (as it would be in all existing deployments), get_routes() returns an empty list, the condition is false, and gen_conf() output is identical to today's. No existing context variables are reinterpreted or removed.

Could you clarify what specific behavior you see changing? I want to make sure I'm not missing something.

Regarding the second concern, I enabled type checking in #6827.

@mcanevet
Copy link
Copy Markdown
Author

mcanevet commented Apr 2, 2026

Here is a gist with context.sh, cloud-init.log and cloud-init-output.log:
https://gist.github.com/mcanevet/7561c97acd64c8ebd980843bc8ca90ee

@mcanevet
Copy link
Copy Markdown
Author

mcanevet commented Apr 2, 2026

you can see in the logs that before my patch, the ETH0_ROUTES context variable is not used.
here is the official documentation for the context variables: https://docs.opennebula.io/6.10/management_and_operations/references/template.html#context-section

mcanevet added a commit to mcanevet/cloud-init that referenced this pull request Apr 3, 2026
Add type annotations to DataSourceOpenNebula.py to address concerns
raised in PR canonical#6810 about type checking being disabled for the
OpenNebula datasource.

Refs canonicalGH-6810
mcanevet added a commit to mcanevet/cloud-init that referenced this pull request Apr 10, 2026
Add type annotations to parse_shell_config, get_field (with @overload),
and all OpenNebulaNetwork.get_* methods as requested. Replace assert-based
type narrowing with proper guards. Remove leaked global assignment in test
and revert unrelated cosmetic changes.

Refs canonicalGH-6810
mcanevet added a commit to mcanevet/cloud-init that referenced this pull request Apr 10, 2026
Add type annotations to parse_shell_config, get_field (with @overload),
and all OpenNebulaNetwork.get_* methods as requested. Replace assert-based
type narrowing with proper guards. Remove leaked global assignment in test
and revert unrelated cosmetic changes.

Refs canonicalGH-6810
mcanevet added a commit to mcanevet/cloud-init that referenced this pull request Apr 10, 2026
Add type annotations to parse_shell_config, get_field (with @overload),
and all OpenNebulaNetwork.get_* methods as requested. Replace assert-based
type narrowing with proper guards. Remove leaked global assignment in test
and revert unrelated cosmetic changes.

Refs canonicalGH-6810
mcanevet added a commit to mcanevet/cloud-init that referenced this pull request Apr 13, 2026
Context values come exclusively from parse_shell_config which returns
Dict[str, str]. Shell variables can only be absent or hold string values,
so a None context value is impossible in production. The equivalent
realistic scenario is already covered by test_get_field_emptycontext.

Refs canonicalGH-6810
mcanevet added a commit to mcanevet/cloud-init that referenced this pull request Apr 13, 2026
…idates

When test_find_candidates was refactored from a try/finally pattern to
@mock.patch in d482353, the bare global assignment
`util.find_devs_with = my_devs_with` was left in by mistake. The
try/finally used to save and restore the original; without it, this
assignment leaks state and can cause order-dependent failures in other
tests. The @mock.patch decorator already patches the function correctly
and restores it after the test.

Refs canonicalGH-6810
mcanevet added a commit to mcanevet/cloud-init that referenced this pull request Apr 14, 2026
…idates

When test_find_candidates was refactored from a try/finally pattern to
@mock.patch in d482353, the bare global assignment
`util.find_devs_with = my_devs_with` was left in by mistake. The
try/finally used to save and restore the original; without it, this
assignment leaks state and can cause order-dependent failures in other
tests. The @mock.patch decorator already patches the function correctly
and restores it after the test.

Refs canonicalGH-6810
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.

2 participants