netplan: 0.106.1 -> 1.2.2 (#521006)

This commit is contained in:
nikstur
2026-07-28 09:45:45 +00:00
committed by GitHub
5 changed files with 258 additions and 32 deletions
+1
View File
@@ -1329,6 +1329,7 @@
./services/networking/netbird/server.nix
./services/networking/netclient.nix
./services/networking/netfoil.nix
./services/networking/netplan.nix
./services/networking/networkd-dispatcher.nix
./services/networking/networkmanager.nix
./services/networking/newt.nix
@@ -0,0 +1,61 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.networking.netplan;
networkdEnabled = (config.networking.useNetworkd || config.systemd.network.enable);
networkmanagerEnabled = config.networking.networkmanager.enable;
in
{
options = {
networking.netplan = {
enable = lib.mkEnableOption "Whether to enable the netplan-configure service at boot";
package = lib.mkPackageOption pkgs "netplan" { };
configFiles = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = { };
example = ''
{
"10-example.yaml" = \'\'
---
network:
version: 2
dummy-devices:
example:
addresses: ["fd00::feed:cafe/32"]
\'\'
}
'';
description = "Netplan YAML configuration files to write under /etc/netplan/";
};
};
};
config = lib.mkIf cfg.enable {
warnings = lib.optionals (!(networkdEnabled || networkmanagerEnabled)) [
"You enabled the netplan-configure service, but you haven't enabled a backend for it. It's likely you want to enable either networkd or NetworkManager."
];
environment = {
systemPackages = [ cfg.package ];
etc = builtins.listToAttrs (
builtins.map (key: {
name = "netplan/" + key;
value = {
text = cfg.configFiles."${key}";
user = "root";
group = "root";
mode = "0600";
};
}) (pkgs.lib.attrNames cfg.configFiles)
);
};
systemd = {
packages = [ cfg.package ];
services.netplan-configure.wantedBy = [ "sysinit.target" ];
};
};
}
+1
View File
@@ -1137,6 +1137,7 @@ in
netbox_4_5 = handleTest ./web-apps/netbox/default.nix { netbox = pkgs.netbox_4_5; };
netdata = runTest ./netdata.nix;
netfoil = runTest ./netfoil.nix;
netplan = runTest ./netplan.nix;
networking.networkd = handleTest ./networking/networkd-and-scripted.nix { networkd = true; };
networking.networkmanager = handleTest ./networking/networkmanager.nix { };
networking.scripted = handleTest ./networking/networkd-and-scripted.nix { networkd = false; };
+144
View File
@@ -0,0 +1,144 @@
{ pkgs, lib, ... }:
let
# Test by creating a "group" of interfaces: a VRF, plus a dummy interface under it, to which we'll assign an IPv6 ULA address
# This must be done for both configs under /etc ("static") and configs under /run ("dynamic"). So each test group gets an address
test-groups = {
"static" = "fd00::feed:cafe/32";
"dynamic" = "fd00::dead:beef/32";
};
# Generate link information, interface getter commands, and configuration files, to be used on all test VMs
# The variable respects the globs:
# - fixtures.{static,dynamic}.links.{vrf,dummy}.{name,getter-cmd,address} (NB: address is unavailable in 'vrf')
# - fixtures.{static,dynamic}.cfgs.{networkd,NetworkManager}.{filename,src}
fixtures = lib.mapAttrs (
group: address:
let
vrf-name = "np${group}";
in
{
links.vrf.name = "${vrf-name}";
links.vrf.getter-cmd = "ip -o link show dev ${vrf-name} type vrf";
links.dummy.name = "${vrf-name}-lo";
links.dummy.getter-cmd = "ip -o link show dev ${vrf-name}-lo type dummy master ${vrf-name}";
links.dummy.address = address;
cfgs = lib.genAttrs [ "networkd" "NetworkManager" ] (renderer: get-config-file group renderer);
}
) test-groups;
# Utility to generate netplan configuration objects
get-config-file = (
group: renderer:
let
links = fixtures.${group}.links;
content = ''
---
network:
version: 2
renderer: ${renderer}
dummy-devices:
${links.dummy.name}:
addresses: ["${links.dummy.address}"]
vrfs:
${links.vrf.name}:
table: 130
interfaces: [${links.dummy.name}]
'';
in
{
filename = "10-test-${group}-${renderer}.yaml";
src = pkgs.writeText "netplan-test-${group}-${renderer}" content;
}
);
in
{
name = "netplan";
meta.maintainers = with lib.maintainers; [
mkg20001
];
nodes = {
networkd = {
networking.useNetworkd = true;
systemd.network.enable = true;
networking.useDHCP = false;
networking.netplan.enable = true;
networking.netplan.configFiles = {
${fixtures.static.cfgs.networkd.filename} = builtins.readFile fixtures.static.cfgs.networkd.src;
};
systemd.tmpfiles.settings."netplan"."/run/netplan".d = {
user = "root";
group = "root";
mode = "0700";
};
};
networkmanager = {
networking.networkmanager.enable = true;
networking.netplan.enable = true;
networking.netplan.configFiles = {
${fixtures.static.cfgs.NetworkManager.filename} =
builtins.readFile fixtures.static.cfgs.NetworkManager.src;
};
systemd.tmpfiles.settings."netplan"."/run/netplan".d = {
user = "root";
group = "root";
mode = "0700";
};
};
};
testScript = ''
import json
fixtures = json.loads('${builtins.toJSON fixtures}')
start_all()
# Test both networkd and networkmanager backends
for machine in [networkd, networkmanager]:
# Prepare variables for testing
renderer = "networkd" if machine is networkd else "NetworkManager"
configfiles = dict()
links = dict()
for group in ['static', 'dynamic']:
links[group] = list(fixtures[group]['links'].items())
configfiles[group] = fixtures[group]['cfgs'][renderer]
# Wait for tests to be runnable
machine.wait_for_unit("network.target")
# Basic tests
with subtest("Check that netplan package has been installed and is able to run"):
machine.succeed("which netplan")
machine.succeed("netplan --help")
# Module tests
with subtest("Check that the nixos module wrote the configuration file"):
machine.succeed(f"ls /etc/netplan/{configfiles['static']['filename']}")
# Run the interface checks twice: once before applying the dynamic config, and once after
for dynamic_config in [False, True]:
# If testing the synamic, write out the fixture YAML file, and apply it
if dynamic_config:
with subtest("Run netplan apply to configure dynamic interfaces"):
destination_filename = f"/run/netplan/{configfiles['dynamic']['filename']}"
machine.copy_from_host_via_shell(configfiles['dynamic']['src'], destination_filename)
machine.succeed(f"chown root:root {destination_filename}")
machine.succeed(f"chmod 0700 {destination_filename}")
machine.succeed("netplan apply")
# Check that the interfaces exist and are of the right type
# Commands below rely on '-o pipefail' being set in the shell
links_to_test = links['static'] + (links['dynamic'] if dynamic_config else [])
with subtest(f"Check that netplan correctly configured the network interfaces ({'/run populated' if dynamic_config else 'right after boot'})"):
for link_type, link in links_to_test:
link_name = link['name']
machine.wait_until_succeeds(f"{link['getter-cmd']} | grep {link_name}")
# For the dummy interface, check the IP address as well
if link_type == 'dummy':
machine.wait_until_succeeds(f"ip -o addr show {link_name} to {link['address']} | grep {link_name}")
'';
}
+51 -32
View File
@@ -9,68 +9,87 @@
python3,
libuuid,
bash-completion,
meson,
ninja,
cmake,
iproute2,
makeWrapper,
lib,
nixosTests,
}:
let
pythonenv = python3.withPackages (
p: with p; [
pyyaml
cffi
setuptools
]
);
in
stdenv.mkDerivation (finalAttrs: {
pname = "netplan";
version = "0.106.1";
version = "1.2.2";
src = fetchFromGitHub {
owner = "canonical";
repo = "netplan";
rev = finalAttrs.version;
hash = "sha256-wQ4gd9+9YU92WGRMjSiF/zLCGxhaSl8s22pH1jr+Mm0=";
hash = "sha256-3gvTQGQxQoQWfrcsVEF0ekdCjldRL6gh3k23NIXXZCQ=";
};
strictDeps = true;
nativeBuildInputs = [
pythonenv
pkg-config
glib
pandoc
meson
ninja
cmake
makeWrapper
];
buildInputs = [
pythonenv
systemd
glib
libyaml
(python3.withPackages (
p: with p; [
pyyaml
netifaces
dbus-python
rich
]
))
libuuid
bash-completion
iproute2
];
env.PKG_CONFIG_BASH_COMPLETION_COMPLETIONSDIR = "${placeholder "out"}/share/bash-completion/completions";
env.PKG_CONFIG_SYSTEMD_SYSTEMDSYSTEMGENERATORDIR = "${placeholder "out"}/lib/systemd/system-generators";
env.PKG_CONFIG_SYSTEMD_SYSTEMDSYSTEMUNITDIR = "${placeholder "out"}/lib/systemd/system";
postPatch = ''
substituteInPlace netplan/libnetplan.py \
--replace "/lib/netplan/generate" "$out/lib/netplan/generate" \
--replace "ctypes.util.find_library('netplan')" "\"$out/lib/libnetplan.so\""
substituteInPlace Makefile \
--replace 'SYSTEMD_GENERATOR_DIR=' 'SYSTEMD_GENERATOR_DIR ?= ' \
--replace 'SYSTEMD_UNIT_DIR=' 'SYSTEMD_UNIT_DIR ?= ' \
--replace 'BASH_COMPLETIONS_DIR=' 'BASH_COMPLETIONS_DIR ?= ' \
--replace 'pkg-config' '$(PKG_CONFIG)'
# from upstream https://github.com/canonical/netplan/blob/ee0d5df7b1dfbc3197865f02c724204b955e0e58/rpm/netplan.spec#L81
sed -e "s/-Werror//g" -i Makefile
substituteInPlace netplan/cli/utils.py \
--replace-fail "/usr/libexec/netplan/generate" "${placeholder "out"}/lib/netplan/generate"
substituteInPlace netplan-configure.service \
--replace-fail "/usr/libexec/netplan/" "${placeholder "out"}/libexec/netplan/"
substituteInPlace netplan_cli/cli/utils.py \
--replace-fail "/usr/libexec/netplan/" "${placeholder "out"}/libexec/netplan/"
'';
makeFlags = [
"PREFIX="
"DESTDIR=$(out)"
"SYSTEMD_GENERATOR_DIR=lib/systemd/system-generators/"
"SYSTEMD_UNIT_DIR=lib/systemd/units/"
"BASH_COMPLETIONS_DIR=share/bash-completion/completions"
# Wrap the systemd generator to force its argv0 value, ensuring it detects itself being invoked as such
# As netplan installs a systemd generator to function, it requires `systemd.packages = [ pkgs.netplan ];` to make systemd use it
postFixup = ''
wrapProgram $out/bin/netplan \
--prefix PYTHONPATH : "$out/${pythonenv.sitePackages}:${pythonenv}/${pythonenv.sitePackages}" \
--prefix LD_LIBRARY_PATH : "$out/lib" \
--prefix PATH : "${lib.makeBinPath [ iproute2 ]}" \
--inherit-argv0
wrapProgram $out/lib/systemd/system-generators/netplan \
--argv0 /etc/systemd/system-generators/netplan
'';
mesonFlags = [
(lib.mesonBool "testing" false)
];
passthru.tests = {
inherit (nixosTests) netplan;
};
meta = {
description = "Backend-agnostic network configuration in YAML";
homepage = "https://netplan.io";