Skip to content
15 changes: 15 additions & 0 deletions nixos/doc/manual/release-notes/rl-1809.xml
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,21 @@ $ nix-instantiate -E '(import <nixpkgsunstable> {}).gitFull'
from your config without any issues.
</para>
</listitem>
<listitem>
<para>
The following changes apply if <literal>system.stateVersion</literal> is
changed to 18.09 or higher. For <literal>system.stateVersion = "18.03"</literal> or lower
the old behavior is preserved.
</para>
<itemizedlist>
<listitem>
<para>
If predictable interface names are enabled (<literal>networking.usePredictableInterfaceNames = true </literal>), interfaces are already renamed in Stage 1 (initrd).
<emphasis role="strong">This may break existing configurations that require networking in Stage 1 (initrd) to boot. In the worst case, your system may become unbootable.</emphasis> Before updating <literal>stateVersion</literal> to 18.09 or higher, make sure your configuration is not affected.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last bit

Before updating stateVersion to 18.09 or higher, make sure your configuration is not affected.

is redundant because of the previous paragraph; the opening paragraph of that section. I'm not specifically against keeping it, but I think removing redundant phrases in the release notes is important; they may be long! (They are probably still incomplete, we'll see in the coming days.)

</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</section>

Expand Down
3 changes: 3 additions & 0 deletions nixos/modules/services/hardware/udev.nix
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,9 @@ in
change randomly across reboots; for instance, you may find
<literal>eth0</literal> and <literal>eth1</literal> flipping
unpredictably.
For newer configurations with <literal>system.stateVersion >= 18.09</literal>,
interfaces are renamed to predictable names in Stage 1 (initrd), and
changing this option's value requires a reboot to take effect.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and changing this option's value requires a reboot to take effect.

Reading this, I initially thought that this was related to the previous sentence. It would be better to separate the sentences, as they share no relation.

For newer configurations with system.stateVersion >= 18.09,
interfaces are renamed to predictable names in Stage 1 (initrd).
Changing this option's value requires a reboot to take effect.

Additionally, dropping the newer will keep the description evergreen and not feel weird in two years when 20.09 is being used, seeing 18.09 described as newer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading this, I initially thought that this was related to the previous sentence.

It actually is related - in the current implementation, the option can be changed with nixos-rebuild switch without rebooting. But with this PR it will require a reboot.

'';
};

Expand Down
3 changes: 3 additions & 0 deletions nixos/modules/system/boot/networkd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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" ];
};
Expand Down
10 changes: 9 additions & 1 deletion nixos/modules/system/boot/stage-1.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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}

Expand Down
2 changes: 1 addition & 1 deletion nixos/release.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 {};
Expand Down
123 changes: 70 additions & 53 deletions nixos/tests/initrd-network-ssh/default.nix
Original file line number Diff line number Diff line change
@@ -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]
)
5 changes: 5 additions & 0 deletions nixos/tests/predictable-interface-names.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ in pkgs.lib.listToAttrs (pkgs.lib.crossLists (predictable: withNetworkd: {
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 = true;
# test new behavior for 18.09
system.stateVersion = "18.09";
};

testScript = ''
Expand Down