diff --git a/nixos/doc/manual/release-notes/rl-1809.xml b/nixos/doc/manual/release-notes/rl-1809.xml index d831f85144662..c977aa389695b 100644 --- a/nixos/doc/manual/release-notes/rl-1809.xml +++ b/nixos/doc/manual/release-notes/rl-1809.xml @@ -200,6 +200,22 @@ $ nix-instantiate -E '(import <nixpkgsunstable> {}).gitFull' from your config without any issues. + + + The following changes apply if system.stateVersion is + changed to 18.09 or higher. For system.stateVersion = "18.03" or lower + the old behavior is preserved. + + + + + If predictable interface names are enabled (networking.usePredictableInterfaceNames = true ), + interfaces are already renamed in Stage 1 (initrd). This may break existing configurations + that require networking in Stage 1 (initrd) to boot. In the worst case, your system may become unbootable. + + + + diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix index 0266286aaacf9..5094be3997fa4 100644 --- a/nixos/modules/services/hardware/udev.nix +++ b/nixos/modules/services/hardware/udev.nix @@ -266,6 +266,9 @@ in change randomly across reboots; for instance, you may find eth0 and eth1 flipping unpredictably. + For configurations with system.stateVersion >= 18.09, + interfaces are renamed to predictable names in Stage 1 (initrd). + Changing this option's value may require a reboot to take effect. ''; }; diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index c11aaeaeb6dcd..79eb69ff1c99e 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -844,7 +844,10 @@ in systemd.services.systemd-networkd = { wantedBy = [ "multi-user.target" ]; restartTriggers = map (f: f.source) (unitFiles); + } // optionalAttrs (versionOlder config.system.stateVersion "18.09") { # prevent race condition with interface renaming (#39069) + # This is not necessary for newer configs (stateVersion>=18.09) + # since they do interface renaming in stage 1 requires = [ "systemd-udev-settle.service" ]; after = [ "systemd-udev-settle.service" ]; }; diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index f58b68cb3353d..f5f8649211796 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -195,9 +195,11 @@ let fi ''; # */ + # use same rules as stage 2 for renaming network interfaces to predictable names + netSetupLinkRules = ../../services/hardware/80-net-setup-link.rules; udevRules = pkgs.runCommand "udev-rules" - { allowedReferences = [ extraUtils ]; } + { allowedReferences = [ netSetupLinkRules extraUtils ]; } '' mkdir -p $out @@ -206,6 +208,12 @@ let cp -v ${udev}/lib/udev/rules.d/60-cdrom_id.rules $out/ cp -v ${udev}/lib/udev/rules.d/60-persistent-storage.rules $out/ cp -v ${udev}/lib/udev/rules.d/80-drivers.rules $out/ + # rename interfaces to predictable names in stage 1 for newer configs + ${optionalString (config.networking.usePredictableInterfaceNames && + lib.versionAtLeast config.system.stateVersion "18.09") '' + cp -v ${udev}/lib/udev/rules.d/75-net-description.rules $out/ + cp -v ${netSetupLinkRules} $out/80-net-setup-link.rules + ''} cp -v ${pkgs.lvm2}/lib/udev/rules.d/*.rules $out/ ${config.boot.initrd.extraUdevRulesCommands} diff --git a/nixos/release.nix b/nixos/release.nix index b25c684ff47a8..5397cb31f6442 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -314,7 +314,7 @@ in rec { tests.hydra = callTest tests/hydra {}; tests.i3wm = callTest tests/i3wm.nix {}; tests.iftop = callTest tests/iftop.nix {}; - tests.initrd-network-ssh = callTest tests/initrd-network-ssh {}; + tests.initrd-network-ssh = callSubTests tests/initrd-network-ssh {}; tests.installer = callSubTests tests/installer.nix {}; tests.influxdb = callTest tests/influxdb.nix {}; tests.ipv6 = callTest tests/ipv6.nix {}; diff --git a/nixos/tests/initrd-network-ssh/default.nix b/nixos/tests/initrd-network-ssh/default.nix index b2209f297a4f8..6222a4c9c856c 100644 --- a/nixos/tests/initrd-network-ssh/default.nix +++ b/nixos/tests/initrd-network-ssh/default.nix @@ -1,59 +1,76 @@ -import ../make-test.nix ({ lib, ... }: +{ system ? builtins.currentSystem }: -{ - name = "initrd-network-ssh"; - meta = with lib.maintainers; { - maintainers = [ willibutz ]; - }; +let + inherit (import ../../lib/testing.nix { inherit system; }) makeTest pkgs; +in + with pkgs; lib.listToAttrs ( map (predictable: { - nodes = with lib; rec { - server = - { config, ... }: - { - boot.kernelParams = [ - "ip=${config.networking.primaryIPAddress}:::255.255.255.0::eth1:none" - ]; - boot.initrd.network = { - enable = true; - ssh = { - enable = true; - authorizedKeys = [ "${readFile ./openssh.pub}" ]; - port = 22; - hostRSAKey = ./dropbear.priv; - }; - }; - boot.initrd.preLVMCommands = '' - while true; do - if [ -f fnord ]; then - poweroff - fi - sleep 1 - done - ''; + name = if predictable then "predictable" else "unpredictable"; + + value = makeTest { + name = "initrd-network-ssh"+ lib.optionalString predictable "predictable"; + meta = with lib.maintainers; { + maintainers = [ willibutz xeji ]; }; - client = - { config, ... }: - { - environment.etc.knownHosts = { - text = concatStrings [ - "server," - "${toString (head (splitString " " ( - toString (elemAt (splitString "\n" config.networking.extraHosts) 2) - )))} " - "${readFile ./dropbear.pub}" - ]; - }; + nodes = with lib; + let interface2 = if predictable then "ens4" else "eth1"; + in rec { + server = + { config, ... }: + { + # for stateVersion < 18.09 this doesn't make a difference in initrd + system.stateVersion = "18.09"; + networking.usePredictableInterfaceNames = mkForce predictable; + boot.kernelParams = [ + "ip=${config.networking.primaryIPAddress}:::255.255.255.0::${interface2}:none" + ]; + boot.initrd.network = { + enable = true; + # for initrd networking with predictable interface names, + # udhcpc must be given the name as an argument + udhcpc.extraArgs = [ (lib.optionalString predictable "-i ${interface2}")]; + ssh = { + enable = true; + authorizedKeys = [ "${readFile ./openssh.pub}" ]; + port = 22; + hostRSAKey = ./dropbear.priv; + }; + }; + boot.initrd.preLVMCommands = '' + while true; do + if [ -f fnord ]; then + poweroff + fi + sleep 1 + done + ''; + }; + + client = + { config, ... }: + { + environment.etc.knownHosts = { + text = concatStrings [ + "server," + "${toString (head (splitString " " ( + toString (elemAt (splitString "\n" config.networking.extraHosts) 2) + )))} " + "${readFile ./dropbear.pub}" + ]; + }; + }; }; - }; - testScript = '' - startAll; - $client->waitForUnit("network.target"); - $client->copyFileFromHost("${./openssh.priv}","/etc/sshKey"); - $client->succeed("chmod 0600 /etc/sshKey"); - $client->waitUntilSucceeds("ping -c 1 server"); - $client->succeed("ssh -i /etc/sshKey -o UserKnownHostsFile=/etc/knownHosts server 'touch /fnord'"); - $client->shutdown; - ''; -}) + testScript = '' + $client->waitForUnit("network.target"); + $client->copyFileFromHost("${./openssh.priv}","/etc/sshKey"); + $client->succeed("chmod 0600 /etc/sshKey"); + $server->start; + $client->waitUntilSucceeds("ping -c 1 server"); + $client->succeed("ssh -i /etc/sshKey -o UserKnownHostsFile=/etc/knownHosts server 'touch /fnord'"); + $client->shutdown; + ''; + }; + }) [false true] +) diff --git a/nixos/tests/predictable-interface-names.nix b/nixos/tests/predictable-interface-names.nix index 0d73436c1c3f5..4497e42d71462 100644 --- a/nixos/tests/predictable-interface-names.nix +++ b/nixos/tests/predictable-interface-names.nix @@ -2,17 +2,22 @@ let inherit (import ../lib/testing.nix { inherit system; }) makeTest pkgs; -in pkgs.lib.listToAttrs (pkgs.lib.crossLists (predictable: withNetworkd: { +in pkgs.lib.listToAttrs (pkgs.lib.crossLists (predictable: withNetworkd: stateV: { name = pkgs.lib.optionalString (!predictable) "un" + "predictable" - + pkgs.lib.optionalString withNetworkd "Networkd"; + + pkgs.lib.optionalString withNetworkd "Networkd" + + builtins.replaceStrings ["."] [""] stateV; value = makeTest { - name = "${if predictable then "" else "un"}predictableInterfaceNames${if withNetworkd then "-with-networkd" else ""}"; + name = "${if predictable then "" else "un"}predictableInterfaceNames${if withNetworkd then "-with-networkd" else ""}-${stateV}"; meta = {}; machine = { lib, ... }: { networking.usePredictableInterfaceNames = lib.mkForce predictable; networking.useNetworkd = withNetworkd; networking.dhcpcd.enable = !withNetworkd; + # So we can see the initrd device names in the log + # although we don't add an automated test here + boot.initrd.network.enable = (stateV == "18.09"); + system.stateVersion = stateV; }; testScript = '' @@ -21,4 +26,4 @@ in pkgs.lib.listToAttrs (pkgs.lib.crossLists (predictable: withNetworkd: { $machine->fail("ip link show ${if predictable then "eth0" else "ens3"}"); ''; }; -}) [[true false] [true false]]) +}) [[true false] [true false] ["18.03" "18.09"]])