From 5d83988c1e4a666086c0ba96cae7ab6cbb41c3b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Hamb=C3=BCchen?= Date: Mon, 11 Dec 2017 04:05:15 +0100 Subject: [PATCH] nixos-container: Fix `destroy` terminating before it's done. Fixes #32545. This also fixes the race condition found in #32551. And it fixes nixops's repeated destroy/deploy being broken (https://github.com/NixOS/nixops/issues/809). --- .../nixos-container/nixos-container.pl | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/pkgs/tools/virtualization/nixos-container/nixos-container.pl b/pkgs/tools/virtualization/nixos-container/nixos-container.pl index fefdcd614a5..2cb723a7b71 100755 --- a/pkgs/tools/virtualization/nixos-container/nixos-container.pl +++ b/pkgs/tools/virtualization/nixos-container/nixos-container.pl @@ -7,6 +7,7 @@ use File::Slurp; use Fcntl ':flock'; use Getopt::Long qw(:config gnu_getopt); use Cwd 'abs_path'; +use Time::HiRes; my $nsenter = "@utillinux@/bin/nsenter"; my $su = "@su@"; @@ -214,21 +215,6 @@ if (!-e $confFile) { die "$0: container ‘$containerName’ does not exist\n" ; } -sub isContainerRunning { - my $status = `systemctl show 'container\@$containerName'`; - return $status =~ /ActiveState=active/; -} - -sub terminateContainer { - system("machinectl", "terminate", $containerName) == 0 - or die "$0: failed to terminate container\n"; -} - -sub stopContainer { - system("systemctl", "stop", "container\@$containerName") == 0 - or die "$0: failed to stop container\n"; -} - # Return the PID of the init process of the container. sub getLeader { my $s = `machinectl show "$containerName" -p Leader`; @@ -237,6 +223,30 @@ sub getLeader { return int($1); } +sub isContainerRunning { + my $status = `systemctl show 'container\@$containerName'`; + return $status =~ /ActiveState=active/; +} + +sub terminateContainer { + my $leader = getLeader; + system("machinectl", "terminate", $containerName) == 0 + or die "$0: failed to terminate container\n"; + # Wait for the leader process to exit + # TODO: As for any use of PIDs for process control where the process is + # not a direct child of ours, this can go wrong when the pid gets + # recycled after a PID overflow. + # Relying entirely on some form of UUID provided by machinectl + # instead of PIDs would remove this risk. + # See https://github.com/NixOS/nixpkgs/pull/32992#discussion_r158586048 + while ( kill 0, $leader ) { Time::HiRes::sleep(0.1) } +} + +sub stopContainer { + system("systemctl", "stop", "container\@$containerName") == 0 + or die "$0: failed to stop container\n"; +} + # Run a command in the container. sub runInContainer { my @args = @_;