-
Notifications
You must be signed in to change notification settings - Fork 921
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(raspberry-pi-os): Add Raspberry Pi OS support #5827
Open
paulober
wants to merge
7
commits into
canonical:main
Choose a base branch
from
paulober:raspios-support
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
7b13b43
Added Raspberry Pi OS support
paulober ff24964
Remove legacy dhcp
paulober 3cb6d64
Add only available NTP client
paulober 4df4317
Update raspberry-pi-os config
paulober 4ac9a76
Add cc_netplan_nm_patch module
paulober 1da5ee6
Fix some lint errors
paulober fad1bff
Simplify rpios integration
paulober File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# Copyright (C) 2024, Raspberry Pi Ltd. | ||
# | ||
# Author: Paul Oberosler <[email protected]> | ||
# | ||
# This file is part of cloud-init. See LICENSE file for license information. | ||
|
||
from cloudinit import subp | ||
from cloudinit.cloud import Cloud | ||
from cloudinit.config import Config | ||
from cloudinit.config.schema import MetaSchema | ||
from cloudinit.distros import ALL_DISTROS | ||
from cloudinit.net.netplan import CLOUDINIT_NETPLAN_FILE | ||
from cloudinit.settings import PER_INSTANCE | ||
import logging | ||
import os | ||
import re | ||
|
||
LOG = logging.getLogger(__name__) | ||
|
||
meta: MetaSchema = { | ||
"id": "cc_netplan_nm_patch", | ||
"distros": [ALL_DISTROS], | ||
"frequency": PER_INSTANCE, | ||
"activate_by_schema_keys": [], | ||
} | ||
|
||
|
||
def exec_cmd(command: list[str]) -> str | None: | ||
try: | ||
result = subp.subp(command) | ||
if result.stdout is not None: | ||
return result.stdout | ||
except subp.ProcessExecutionError as e: | ||
LOG.error("Failed to execute command: %s", e) | ||
return None | ||
LOG.debug("Command has no stdout: %s", command) | ||
return None | ||
|
||
|
||
def get_netplan_generated_configs() -> list[str]: | ||
"""Get the UUIDs of all connections starting with 'netplan-'.""" | ||
output = exec_cmd(["nmcli", "connection", "show"]) | ||
if output is None: | ||
return [] | ||
|
||
netplan_conns = [] | ||
for line in output.splitlines(): | ||
if line.startswith("netplan-"): | ||
parts = line.split() | ||
if len(parts) > 1: | ||
# name = parts[0] | ||
uuid = parts[1] | ||
netplan_conns.append(uuid) | ||
return netplan_conns | ||
|
||
|
||
def get_connection_object_path(uuid: str) -> str | None: | ||
"""Get the D-Bus object path for a connection by UUID.""" | ||
output = exec_cmd( | ||
[ | ||
"busctl", | ||
"call", | ||
"org.freedesktop.NetworkManager", | ||
"/org/freedesktop/NetworkManager/Settings", | ||
"org.freedesktop.NetworkManager.Settings", | ||
"GetConnectionByUuid", | ||
"s", | ||
uuid, | ||
] | ||
) | ||
|
||
path_match = ( | ||
re.search( | ||
r'o\s+"(/org/freedesktop/NetworkManager/Settings/\d+)"', output | ||
) | ||
if output | ||
else None | ||
) | ||
if path_match: | ||
return path_match.group(1) | ||
else: | ||
LOG.error("Failed to find object path for connection: %s", uuid) | ||
return None | ||
|
||
|
||
def save_connection(obj_path: str) -> None: | ||
"""Call the Save method on the D-Bus obj path for a connection.""" | ||
result = exec_cmd( | ||
[ | ||
"busctl", | ||
"call", | ||
"org.freedesktop.NetworkManager", | ||
obj_path, | ||
"org.freedesktop.NetworkManager.Settings.Connection", | ||
"Save", | ||
] | ||
) | ||
|
||
if result is None: | ||
LOG.error("Failed to save connection: %s", obj_path) | ||
else: | ||
LOG.debug("Saved connection: %s", obj_path) | ||
|
||
|
||
def handle(name: str, cfg: Config, cloud: Cloud, args: list) -> None: | ||
LOG.debug("Applying netplan patch") | ||
|
||
# remove cloud-init file after NetworkManager has generated | ||
# replacement netplan configurations to avoid conflicts in the | ||
# future | ||
|
||
try: | ||
np_conns = get_netplan_generated_configs() | ||
if not np_conns: | ||
LOG.debug("No netplan connections found") | ||
return | ||
|
||
for conn_uuid in np_conns: | ||
obj_path = get_connection_object_path(conn_uuid) | ||
if obj_path is None: | ||
continue | ||
save_connection(obj_path) | ||
|
||
os.remove(CLOUDINIT_NETPLAN_FILE) | ||
LOG.debug("Netplan cfg has been patched: %s", CLOUDINIT_NETPLAN_FILE) | ||
except subp.ProcessExecutionError as e: | ||
LOG.error("Failed to patch netplan cfg: %s", e) | ||
except Exception as e: | ||
LOG.error("Failed to patch netplan cfg: %s", e) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Copyright (C) 2024, Raspberry Pi Ltd. | ||
# | ||
# Author: Paul Oberosler <[email protected]> | ||
# | ||
# This file is part of cloud-init. See LICENSE file for license information. | ||
|
||
from cloudinit import subp | ||
from cloudinit.cloud import Cloud | ||
from cloudinit.config import Config | ||
from cloudinit.config.schema import MetaSchema | ||
from cloudinit.settings import PER_INSTANCE | ||
import logging | ||
|
||
|
||
LOG = logging.getLogger(__name__) | ||
ENABLE_RPI_CONNECT_KEY = "enable_rpi_connect" | ||
|
||
meta: MetaSchema = { | ||
"id": "cc_rpi_connect", | ||
"distros": ["raspberry-pi-os"], | ||
"frequency": PER_INSTANCE, | ||
"activate_by_schema_keys": [ENABLE_RPI_CONNECT_KEY], | ||
} | ||
|
||
|
||
def configure_rpi_connect(enable: bool) -> None: | ||
LOG.debug("Configuring rpi-connect: %s", enable) | ||
|
||
num = 0 if enable else 1 | ||
|
||
try: | ||
subp.subp(["/usr/bin/raspi-config", "do_rpi_connect", str(num)]) | ||
except subp.ProcessExecutionError as e: | ||
LOG.error("Failed to configure rpi-connect: %s", e) | ||
|
||
|
||
def handle(name: str, cfg: Config, cloud: Cloud, args: list) -> None: | ||
if ENABLE_RPI_CONNECT_KEY in cfg: | ||
# expect it to be a dictionary | ||
enable = cfg[ENABLE_RPI_CONNECT_KEY] | ||
|
||
if isinstance(enable, bool): | ||
configure_rpi_connect(enable) | ||
else: | ||
LOG.warning( | ||
"Invalid value for %s: %s", ENABLE_RPI_CONNECT_KEY, enable | ||
) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this file is necessary. Cloud-init writes
50-cloud-init.yaml
, but as far as I know, all network-manager -> netplan files start with '90-'. Doesn't this mean any changes made in network-manager will automatically override the default netplan config? Are you aware of cases where this doesn't work?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I remember correctly, the problem was if you edit the netplan generated NetworkManager (created by cloud-init) config in a desktop GUI the updated config will be written back to netplan with a generated UUID and not touching the original file. This ment changes made by a user are lost after a reboot because the cloud-init netplan config will always be preferred and overrides the NM generated one. By triggering the save operation for every cloud-init generated config after first boot and then removing the original file this issue can be resolved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious if things are different on raspberry-pi-os, but on my desktop at least, I see the network manager files get written with a '90-' first, e.g.,
90-NM-141e654c-21b3-4e52-9505-e3c94be335c0.yaml
so anything in that file would override what is in50-cloud-init.yaml
. If it doesn't work this way, I would think this would be a netplan bug, or the patch was applied incorrectly. Is this something you can check to see if you get different results?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I just checked without the netplan_nm_patch, and yes the updated config is written to 90-NM... and also visible in the UI. But after a reboot the 50-cloud-init will take over => changes are not effective.