PVE::LXC::Config->check_lock($conf);
}
- my $cmd = ['lxc-stop', '-n', $vmid, '--kill'];
-
- run_command($cmd);
+ PVE::LXC::vm_stop($vmid, 1);
return;
};
syslog('info', "shutdown CT $vmid: $upid\n");
- my $cmd = ['lxc-stop', '-n', $vmid];
-
$timeout = 60 if !defined($timeout);
my $conf = PVE::LXC::Config->load_config($vmid);
PVE::LXC::Config->check_lock($conf);
- my $storage_cfg = PVE::Storage::config();
-
- push @$cmd, '--timeout', $timeout;
-
- eval { run_command($cmd, timeout => $timeout+5); };
- my $err = $@;
- if ($err && $param->{forceStop}) {
- $err = undef;
- warn "shutdown failed - forcing stop now\n";
-
- my $cmd = ['lxc-stop', '-n', $vmid, '--kill'];
- run_command($cmd);
- }
-
- # make sure container is stopped
- $cmd = ['lxc-wait', '-n', $vmid, '-t', 5, '-s', 'STOPPED'];
- run_command($cmd);
- $err = $@;
-
- die $err if $err;
+ PVE::LXC::vm_stop($vmid, $param->{forceStop}, $timeout);
return;
};
use File::Spec;
use Cwd qw();
use Fcntl qw(O_RDONLY O_NOFOLLOW O_DIRECTORY);
-use Errno qw(ELOOP ENOTDIR EROFS);
+use Errno qw(ELOOP ENOTDIR EROFS ECONNREFUSED);
+use IO::Socket::UNIX;
use PVE::Exception qw(raise_perm_exc);
use PVE::Storage;
return [];
}
+# Helper to stop a container completely and make sure it has stopped completely.
+# This is necessary because we want the post-stop hook to have completed its
+# unmount-all step, but post-stop happens after lxc puts the container into the
+# STOPPED state.
+sub vm_stop {
+ my ($vmid, $kill, $shutdown_timeout, $exit_timeout) = @_;
+
+ # Open the container's command socket.
+ my $path = "\0/var/lib/lxc/$vmid/command";
+ my $sock = IO::Socket::UNIX->new(
+ Type => SOCK_STREAM(),
+ Peer => $path,
+ );
+ if (!$sock) {
+ return if $! == ECONNREFUSED; # The container is not running
+ die "failed to open container ${vmid}'s command socket: $!\n";
+ }
+
+ # Stop the container:
+
+ my $cmd = ['lxc-stop', '-n', $vmid];
+
+ if ($kill) {
+ push @$cmd, '--kill'; # doesn't allow timeouts
+ } elsif (defined($shutdown_timeout)) {
+ push @$cmd, '--timeout', $shutdown_timeout;
+ # Give run_command 5 extra seconds
+ $shutdown_timeout += 5;
+ }
+
+ eval { PVE::Tools::run_command($cmd, timeout => $shutdown_timeout) };
+ if (my $err = $@) {
+ warn $@ if $@;
+ }
+
+ my $result = 1;
+ my $wait = sub { $result = <$sock>; };
+ if (defined($exit_timeout)) {
+ PVE::Tools::run_with_timeout($exit_timeout, $wait);
+ } else {
+ $wait->();
+ }
+
+ return if !defined $result; # monitor is gone and the ct has stopped.
+ die "container did not stop\n";
+}
1;
sub __snapshot_rollback_vm_stop {
my ($class, $vmid) = @_;
- PVE::Tools::run_command(['/usr/bin/lxc-stop', '-n', $vmid, '--kill'])
+ PVE::LXC::vm_stop($vmid, 1)
if $class->__snapshot_check_running($vmid);
}
$self->log('info', "shutdown CT $vmid\n");
- my $cmd = ['lxc-stop', '-n', $vmid, '--timeout', $timeout];
- $self->cmd($cmd, timeout => $timeout + 5);
-
- # make sure container is stopped
- $cmd = ['lxc-wait', '-n', $vmid, '-t', 5, '-s', 'STOPPED'];
- $self->cmd($cmd);
+ PVE::LXC::vm_stop($vmid, 0, $timeout);
$running = 0;
}
my $opts = $self->{vzdump}->{opts};
my $timeout = $opts->{stopwait} * 60;
- $self->cmd("lxc-stop -n $vmid -t $timeout");
-
- # make sure container is stopped
- $self->cmd("lxc-wait -n $vmid -s STOPPED");
+ PVE::LXC::vm_stop($vmid, 0, $timeout);
}
sub start_vm {
die "volume_rollback_is_possible failed\n";
}
+sub mocked_vm_stop {
+ if ($kill_possible) {
+ $running = 0;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
sub mocked_run_command {
my ($cmd, %param) = @_;
my $cmdstring;
die "lxc-[un]freeze disabled\n";
}
if ($cmdstring =~ m/.*\/lxc-stop.*--kill.*/) {
- if ($kill_possible) {
- $running = 0;
- return 1;
- } else {
- return 0;
- }
+ mocked_vm_stop();
}
}
die "unexpected run_command call: '$cmdstring', aborting\n";
my $lxc_module = new Test::MockModule('PVE::LXC');
$lxc_module->mock('sync_container_namespace', sub { return; });
$lxc_module->mock('check_running', \&mocked_check_running);
+$lxc_module->mock('vm_stop', \&mocked_vm_stop);
my $lxc_config_module = new Test::MockModule('PVE::LXC::Config');
$lxc_config_module->mock('config_file_lock', sub { return "snapshot-working/pve-test.lock"; });