diff --git a/nixos/maintainers/scripts/incus/incus-container-image.nix b/nixos/maintainers/scripts/incus/incus-container-image.nix index 9faf6a5d87ad..989f583307fe 100644 --- a/nixos/maintainers/scripts/incus/incus-container-image.nix +++ b/nixos/maintainers/scripts/incus/incus-container-image.nix @@ -13,18 +13,24 @@ ]; }; - # copy the config for nixos-rebuild - system.activationScripts.config = + # Create a default configuration.nix on first boot so nixos-rebuild works + # out of the box. + systemd.services.incus-create-nixos-config = let - config = pkgs.replaceVars ./incus-container-image-inner.nix { + configFile = pkgs.replaceVars ./incus-container-image-inner.nix { stateVersion = lib.trivial.release; }; in - '' - if [ ! -e /etc/nixos/configuration.nix ]; then - install -m 0644 -D ${config} /etc/nixos/configuration.nix - fi - ''; + { + description = "Create default NixOS configuration for Incus"; + wantedBy = [ "multi-user.target" ]; + unitConfig.ConditionPathExists = "!/etc/nixos/configuration.nix"; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.coreutils}/bin/install -m 0644 -D ${configFile} /etc/nixos/configuration.nix"; + }; + }; networking = { dhcpcd.enable = false; diff --git a/nixos/maintainers/scripts/incus/incus-virtual-machine-image.nix b/nixos/maintainers/scripts/incus/incus-virtual-machine-image.nix index db60160c9c77..f06b43dc2675 100644 --- a/nixos/maintainers/scripts/incus/incus-virtual-machine-image.nix +++ b/nixos/maintainers/scripts/incus/incus-virtual-machine-image.nix @@ -13,18 +13,24 @@ ]; }; - # copy the config for nixos-rebuild - system.activationScripts.config = + # Create a default configuration.nix on first boot so nixos-rebuild works + # out of the box. + systemd.services.incus-create-nixos-config = let - config = pkgs.replaceVars ./incus-virtual-machine-image-inner.nix { + configFile = pkgs.replaceVars ./incus-virtual-machine-image-inner.nix { stateVersion = lib.trivial.release; }; in - '' - if [ ! -e /etc/nixos/configuration.nix ]; then - install -m 0644 -D ${config} /etc/nixos/configuration.nix - fi - ''; + { + description = "Create default NixOS configuration for Incus"; + wantedBy = [ "multi-user.target" ]; + unitConfig.ConditionPathExists = "!/etc/nixos/configuration.nix"; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.coreutils}/bin/install -m 0644 -D ${configFile} /etc/nixos/configuration.nix"; + }; + }; # Network networking = { diff --git a/nixos/modules/profiles/docker-container.nix b/nixos/modules/profiles/docker-container.nix index 2029f569b073..5c1681048bed 100644 --- a/nixos/modules/profiles/docker-container.nix +++ b/nixos/modules/profiles/docker-container.nix @@ -79,8 +79,9 @@ in ''; }; - # Install new init script - system.activationScripts.installInitScript = '' - ln -fs $systemConfig/init /init + # Update /init symlink when switching configurations so the container + # boots the new system on restart. + system.build.installBootLoader = pkgs.writeShellScript "install-docker-init" '' + ${pkgs.coreutils}/bin/ln -fs "$1/init" /init ''; } diff --git a/nixos/modules/virtualisation/lxc-container.nix b/nixos/modules/virtualisation/lxc-container.nix index ddd004361161..abdf377c3875 100644 --- a/nixos/modules/virtualisation/lxc-container.nix +++ b/nixos/modules/virtualisation/lxc-container.nix @@ -136,8 +136,5 @@ systemd.packages = [ pkgs.distrobuilder.generator ]; - system.activationScripts.installInitScript = lib.mkForce '' - ln -fs $systemConfig/init /sbin/init - ''; }; } diff --git a/nixos/tests/incus/incus-tests-module.nix b/nixos/tests/incus/incus-tests-module.nix index 085dbfbc8750..8d8752fde81f 100644 --- a/nixos/tests/incus/incus-tests-module.nix +++ b/nixos/tests/incus/incus-tests-module.nix @@ -156,6 +156,16 @@ in server.succeed(f"incus exec {instance_name} -- test -e /dev/tpm0") server.succeed(f"incus exec {instance_name} -- test -e /dev/tpmrm0") + + with subtest("[${image_id}] default configuration.nix is created on first boot"): + server.succeed(f"incus exec {instance_name} -- test -f /etc/nixos/configuration.nix") + + with subtest("[${image_id}] configuration.nix create service does not overwrite existing config"): + server.succeed(f"incus exec {instance_name} -- systemctl restart incus-create-nixos-config.service") + status = server.succeed( + f"incus exec {instance_name} -- systemctl show -p ActiveState incus-create-nixos-config.service" + ).strip() + assert "inactive" in status, f"Expected inactive (ConditionPathExists should prevent start), got {status}" '' # # container specific @@ -164,6 +174,21 @@ in lib.optionalString (config.type == "container") # python '' + with subtest("[${image_id}] switch-to-configuration updates /sbin/init via installBootLoader"): + # Remove /sbin/init so we can verify installBootLoader recreates it + server.succeed(f"incus exec {instance_name} -- rm -f /sbin/init") + server.fail(f"incus exec {instance_name} -- test -e /sbin/init") + + server.succeed( + f"incus exec {instance_name} -- /run/current-system/bin/switch-to-configuration switch" + ) + + # Verify installBootLoader recreated /sbin/init pointing to the system's init + server.succeed(f"incus exec {instance_name} -- test -x /sbin/init") + target = server.succeed(f"incus exec {instance_name} -- readlink -f /sbin/init").strip() + current = server.succeed(f"incus exec {instance_name} -- readlink -f /run/current-system/init").strip() + assert target == current, f"/sbin/init -> {target}, expected {current}" + # TODO troubleshoot VM hot memory resizing which was introduced in 6.12 with subtest("[${image_id}] memory limits can be hotplug changed"): server.set_instance_config(instance_name, "limits.memory 512MB")