Change:
Describe the bug NetworkManager is a particularly important component and we don't have any tests for it that could block a channel advance. In particular, a change can happen on nixos-unstable leaving users without functioning networking, and while rollbacks are possible it isn't an excuse to allow that to reach production systems. NixOS doesn't produce either. Manual testing is also cumbersome if we want to make a new stable release. Upstream NetworkManager does have some integration testing but obviously not useful to us. I think to start, if we at least had a test that verifies the services start without issues would be great.
Agreed. While developing tests for the multipath TCP module I was surprised to see no networkmanager module. I had some difficulties with the nixos test infrastructure at first because the test infra will by default install a slirp interface () and it messed up the interface naming. Like I would clear but interfaces would still be named starting from instead of . Just thought I would mention it in case the brave soul writing the test is interested in multihoming. (but that's more a concern I have with the test infra).
Thank you for your contributions. This has been automatically marked as stale because it has had no activity for 180 days. If this is still important to you, we ask that you leave a comment below. Your comment can be as simple as "still important to me". This lets people see that at least one person still cares about this. Someone will have to do this at most twice a year if there is no other activity. Here are suggestions that might help resolve this more quickly: for maintainers and people that previously touched the related code and @ mention them in a comment. on the . 3. Ask on the on .
Bleh.
I marked this as stale due to inactivity. &rarr;
consequences of our inactions

Discussion:
/nixos/modules/services/networking/babeld.nix @mweinelt /nixos/modules/services/networking/kea.nix @mweinelt /nixos/modules/services/networking/knot.nix @mweinelt <ins> nixos/modules/services/networking/networkmanager.nix @Janik-Haag </ins> /nixos/modules/services/monitoring/prometheus/exporters/kea.nix @mweinelt /nixos/tests/babeld.nix @mweinelt /nixos/tests/kea.nix @mweinelt /nixos/tests/knot.nix @mweinelt <ins> /nixos/tests/networking/* @Janik-Haag </ins> # Web servers /doc/packages/nginx.section.md @raitobezarius

- The `hardware.pulseaudio` module now sets permission of pulse user home directory to 755 when running in "systemWide" mode. It fixes [issue 114399](https://github.com/NixOS/nixpkgs/issues/114399). <ins> - The `services.networkmanager.extraConfig` was renamed to `services.networkmanager.settings` and was changed to use the ini type instead of using a multiline string. </ins> - The module `services.github-runner` has been removed. To configure a single GitHub Actions Runner refer to `services.github-runners.*`. Note that this will trigger a new runner registration. - The `services.slskd` has been refactored to include more configuation options in

enableIwd = cfg.wifi.backend == "iwd"; <del> mkValue = v: if v == true then "yes" else if v == false then "no" else if lib.isInt v then toString v else v; mkSection = name: attrs: '' [${name}] ${ lib.concatStringsSep "n" (lib.mapAttrsToList (k: v: "${k}=${mkValue v}") (lib.filterAttrs (k: v: v != null) attrs)) } ''; configFile = pkgs.writeText "NetworkManager.conf" (lib.concatStringsSep "n" [ (mkSection "main" { </del> <ins> configAttrs = lib.recursiveUpdate { main = { </ins> plugins = "keyfile"; inherit (cfg) dhcp dns; # If resolvconf is disabled that means that resolv.conf is managed by some other module. rc-manager = if config.networking.resolvconf.enable then "resolvconf" else "unmanaged"; <del> }) (mkSection "keyfile" { </del> <ins> }; keyfile = { </ins> unmanaged-devices = <del> if cfg.unmanaged == [ ] then null else lib.concatStringsSep ";" cfg.unmanaged; }) (mkSection "logging" { </del> <ins> if cfg.unmanaged == [ ] then null else lib.concatStringsSep ";" cfg.unmanaged; }; logging = { </ins> audit = config.security.audit.enable; level = cfg.logLevel; <del> }) (mkSection "connection" cfg.connectionConfig) (mkSection "device" { "wifi.scan-rand-mac-address" = cfg.wifi.scanRandMacAddress; "wifi.backend" = cfg.wifi.backend; }) cfg.extraConfig ]); </del> <ins> }; connection = cfg.connectionConfig; device = { "wifi.scan-rand-mac-address" = cfg.wifi.scanRandMacAddress; "wifi.backend" = cfg.wifi.backend; }; } cfg.settings; configFile = ini.generate "NetworkManager.conf" configAttrs; </ins> /* [network-manager]

{ meta = { <del> maintainers = teams.freedesktop.members; </del> <ins> maintainers = teams.freedesktop.members ++ [ lib.maintainers.janik ]; </ins> }; ###### interface

''; }; <del> extraConfig = mkOption { type = types.lines; default = ""; </del> <ins> settings = mkOption { type = ini.type; default = {}; </ins> description = '' <del> Configuration appended to the generated NetworkManager.conf. </del> <ins> Configuration added to the generated NetworkManager.conf, note that you can overwrite settings with this. </ins> Refer to [ https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html

imports = [ (mkRenamedOptionModule [ "networking" "networkmanager" "packages" ] <del> [ "networking" "networkmanager" "plugins" ]) (mkRenamedOptionModule [ "networking" "networkmanager" "useDnsmasq" ] [ "networking" "networkmanager" "dns" ]) </del> <ins> [ "networking" "networkmanager" "plugins" ] ) (mkRenamedOptionModule [ "networking" "networkmanager" "useDnsmasq" ] [ "networking" "networkmanager" "dns" ] ) (mkRemovedOptionModule [ "networking" "networkmanager" "extraConfig" ] '' This option was removed in favour of `networking.networkmanager.settings`, which accepts structured nix-code equivalent to the ini and allows for overriding settings. Example patch: ```patch networking.networkmanager = { -    extraConfig = ''' -      [main] -      no-auto-default=* -    ''' +    extraConfig.main.no-auto-default = "*"; }; ``` '' ) </ins> (mkRemovedOptionModule [ "networking" "networkmanager" "enableFccUnlock" ] '' This option was removed, because using bundled FCC unlock scripts is risky, might conflict with vendor-provided unlock scripts, and should

netdata = handleTest ./netdata.nix {}; networking.scripted = handleTest ./networking/networkd-and-scripted.nix { networkd = false; }; networking.networkd = handleTest ./networking/networkd-and-scripted.nix { networkd = true; }; <ins> networking.networkmanager = handleTest ./networking/networkmanager.nix {}; </ins> netbox_3_6 = handleTest ./web-apps/netbox.nix { netbox = pkgs.netbox_3_6; }; netbox_3_7 = handleTest ./web-apps/netbox.nix { netbox = pkgs.netbox_3_7; }; netbox-upgrade = handleTest ./web-apps/netbox-upgrade.nix {};

<ins> { system ? builtins.currentSystem , config ? {} , pkgs ? import ../.. { inherit system config; } }: with import ../../lib/testing-python.nix { inherit system pkgs; }; let lib = pkgs.lib; # this is intended as a client test since you shouldn't use NetworkManager for a router or server # so using systemd-networkd for the router vm is fine in these tests. router = import ./router.nix { networkd = true; }; qemu-common = import ../../lib/qemu-common.nix { inherit (pkgs) lib pkgs; }; clientConfig = extraConfig: lib.recursiveUpdate { networking.useDHCP = false; # Make sure that only NetworkManager configures the interface networking.interfaces = lib.mkForce { eth1 = {}; }; networking.networkmanager = { enable = true; # this is needed so NM doesn't generate 'Wired Connection' profiles and instead uses the default one settings.main.no-auto-default = "*"; ensureProfiles.profiles.default = { connection = { id = "default"; type = "ethernet"; interface-name = "eth1"; autoconnect = true; }; }; }; } extraConfig; testCases = { static = { name = "static"; nodes = { inherit router; client = clientConfig { networking.networkmanager.ensureProfiles.profiles.default = { ipv4.method = "manual"; ipv4.addresses = "192.168.1.42/24"; ipv4.gateway = "192.168.1.1"; ipv6.method = "manual"; ipv6.addresses = "fd00:1234:5678:1::42/64"; ipv6.gateway = "fd00:1234:5678:1::1"; }; }; }; testScript = '' start_all() router.systemctl("start network-online.target") router.wait_for_unit("network-online.target") client.wait_for_unit("NetworkManager.service") with subtest("Wait until we have an ip address on each interface"): client.wait_until_succeeds("ip addr show dev eth1 | grep -q '192.168.1'") client.wait_until_succeeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'") with subtest("Test if icmp echo works"): client.wait_until_succeeds("ping -c 1 192.168.3.1") client.wait_until_succeeds("ping -c 1 fd00:1234:5678:3::1") router.wait_until_succeeds("ping -c 1 192.168.1.42") router.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::42") ''; }; auto = { name = "auto"; nodes = { inherit router; client = clientConfig { networking.networkmanager.ensureProfiles.profiles.default = { ipv4.method = "auto"; ipv6.method = "auto"; }; }; }; testScript = '' start_all() router.systemctl("start network-online.target") router.wait_for_unit("network-online.target") client.wait_for_unit("NetworkManager.service") with subtest("Wait until we have an ip address on each interface"): client.wait_until_succeeds("ip addr show dev eth1 | grep -q '192.168.1'") client.wait_until_succeeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'") with subtest("Test if icmp echo works"): client.wait_until_succeeds("ping -c 1 192.168.1.1") client.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::1") router.wait_until_succeeds("ping -c 1 192.168.1.2") router.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::2") ''; }; dns = { name = "dns"; nodes = { inherit router; dynamic = clientConfig { networking.networkmanager.ensureProfiles.profiles.default = { ipv4.method = "auto"; }; }; static = clientConfig { networking.networkmanager.ensureProfiles.profiles.default = { ipv4 = { method = "auto"; ignore-auto-dns = "true"; dns = "10.10.10.10"; dns-search = ""; }; }; }; }; testScript = '' start_all() router.systemctl("start network-online.target") router.wait_for_unit("network-online.target") dynamic.wait_for_unit("NetworkManager.service") static.wait_for_unit("NetworkManager.service") dynamic.wait_until_succeeds("cat /etc/resolv.conf | grep -q '192.168.1.1'") static.wait_until_succeeds("cat /etc/resolv.conf | grep -q '10.10.10.10'") static.wait_until_fails("cat /etc/resolv.conf | grep -q '192.168.1.1'") ''; }; dispatcherScripts = { name = "dispatcherScripts"; nodes.client = clientConfig { networking.networkmanager.dispatcherScripts = [{ type = "pre-up"; source = pkgs.writeText "testHook" '' touch /tmp/dispatcher-scripts-are-working ''; }]; }; testScript = '' start_all() client.wait_for_unit("NetworkManager.service") client.wait_until_succeeds("stat /tmp/dispatcher-scripts-are-working") ''; }; envsubst = { name = "envsubst"; nodes.client = let # you should never write secrets in to your nixos configuration, please use tools like sops-nix or agenix secretFile = pkgs.writeText "my-secret.env" '' MY_SECRET_IP=fd00:1234:5678:1::23/64 ''; in clientConfig { networking.networkmanager.ensureProfiles.environmentFiles = [ secretFile ]; networking.networkmanager.ensureProfiles.profiles.default = { ipv6.method = "manual"; ipv6.addresses = "$MY_SECRET_IP"; }; }; testScript = '' start_all() client.wait_for_unit("NetworkManager.service") client.wait_until_succeeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'") client.wait_until_succeeds("ping -c 1 fd00:1234:5678:1::23") ''; }; }; in lib.mapAttrs (lib.const (attrs: makeTest (attrs // { name = "${attrs.name}-Networking-NetworkManager"; meta = { maintainers = with lib.maintainers; [ janik ]; }; }))) testCases </ins>

, mobile-broadband-provider-info , runtimeShell , buildPackages <ins> , nixosTests </ins> }: let

attrPath = "networkmanager"; versionPolicy = "odd-unstable"; }; <ins> tests = { inherit (nixosTests.networking) networkmanager; }; </ins> }; meta = with lib; {