diff --git a/nixos/tests/containers-imperative.nix b/nixos/tests/containers-imperative.nix index 61df74042cb..c4f2002918f 100644 --- a/nixos/tests/containers-imperative.nix +++ b/nixos/tests/containers-imperative.nix @@ -46,6 +46,15 @@ import ./make-test-python.nix ({ pkgs, ...} : { }; } ''; + brokenCfg = pkgs.writeText "broken.nix" '' + { + assertions = [ + { assertion = false; + message = "I never evaluate"; + } + ]; + } + ''; in '' with subtest("Make sure we have a NixOS tree (required by ‘nixos-container create’)"): machine.succeed("PAGER=cat nix-env -qa -A nixos.hello >&2") @@ -130,5 +139,11 @@ import ./make-test-python.nix ({ pkgs, ...} : { with subtest("Ensure that the container path is gone"): print(machine.succeed("ls -lsa /var/lib/containers")) machine.succeed(f"test ! -e /var/lib/containers/{id1}") + + with subtest("Ensure that a failed container creation doesn'leave any state"): + machine.fail( + "nixos-container create b0rk --config-file ${brokenCfg}" + ) + machine.succeed(f"test ! -e /var/lib/containers/b0rk") ''; }) diff --git a/pkgs/tools/virtualization/nixos-container/nixos-container.pl b/pkgs/tools/virtualization/nixos-container/nixos-container.pl index 0ba0d5546a0..6e38942cb25 100755 --- a/pkgs/tools/virtualization/nixos-container/nixos-container.pl +++ b/pkgs/tools/virtualization/nixos-container/nixos-container.pl @@ -43,6 +43,7 @@ Usage: nixos-container list [--config ] [--config-file ] [--flake ] + [--nixos-path ] nixos-container login nixos-container root-login nixos-container run -- args... @@ -149,6 +150,16 @@ sub buildFlake { unlink("$systemPath.tmp"); } +sub clearContainerState { + my ($profileDir, $gcRootsDir, $root, $configFile) = @_; + + safeRemoveTree($profileDir) if -e $profileDir; + safeRemoveTree($gcRootsDir) if -e $gcRootsDir; + system("chattr", "-i", "$root/var/empty") if -e "$root/var/empty"; + safeRemoveTree($root) if -e $root; + unlink($configFile) or die; +} + if ($action eq "create") { # Acquire an exclusive lock to prevent races with other # invocations of ‘nixos-container create’. @@ -226,7 +237,10 @@ if ($action eq "create") { if (defined $systemPath) { system("nix-env", "-p", "$profileDir/system", "--set", $systemPath) == 0 - or die "$0: failed to set initial container configuration\n"; + or do { + clearContainerState($profileDir, "$profileDir/$containerName", $root, $confFile); + die "$0: failed to set initial container configuration\n"; + }; } else { mkpath("$root/etc/nixos", 0, 0755); @@ -237,7 +251,10 @@ if ($action eq "create") { system("nix-env", "-p", "$profileDir/system", "-I", "nixos-config=$nixosConfigFile", "-f", "$nixenvF", "--set", "-A", "system") == 0 - or die "$0: failed to build initial container configuration\n"; + or do { + clearContainerState($profileDir, "$profileDir/$containerName", $root, $confFile); + die "$0: failed to build initial container configuration\n" + }; } print "$containerName\n" if $ensureUniqueName; @@ -331,11 +348,7 @@ if ($action eq "destroy") { terminateContainer if (isContainerRunning); - safeRemoveTree($profileDir) if -e $profileDir; - safeRemoveTree($gcRootsDir) if -e $gcRootsDir; - system("chattr", "-i", "$root/var/empty") if -e "$root/var/empty"; - safeRemoveTree($root) if -e $root; - unlink($confFile) or die; + clearContainerState($profileDir, $gcRootsDir, $root, $confFile); } elsif ($action eq "restart") { @@ -374,6 +387,7 @@ elsif ($action eq "update") { system("nix-env", "-p", "$profileDir/system", "--set", $systemPath) == 0 or die "$0: failed to set container configuration\n"; } else { + my $nixosConfigFile = "$root/etc/nixos/configuration.nix"; # FIXME: may want to be more careful about clobbering the existing @@ -383,8 +397,9 @@ elsif ($action eq "update") { writeNixOSConfig $nixosConfigFile; } + my $nixenvF = $nixosPath // ""; system("nix-env", "-p", "$profileDir/system", - "-I", "nixos-config=$nixosConfigFile", "-f", "", + "-I", "nixos-config=$nixosConfigFile", "-f", $nixenvF, "--set", "-A", "system") == 0 or die "$0: failed to build container configuration\n"; }