my $storecfg = PVE::Storage::config();
my $realcmd = sub {
+ my $upid = shift;
+
+ syslog('info', "destroy VM $vmid: $upid\n");
+
PVE::QemuServer::vm_destroy($storecfg, $vmid, $skiplock);
};
# test if VM exists
my $conf = PVE::QemuServer::load_config($param->{vmid});
- my $vmstatus = PVE::QemuServer::vmstatus($param->{vmid});
+ my $vmstatus = PVE::QemuServer::vmstatus($param->{vmid});
return $vmstatus->{$param->{vmid}};
}});
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ die "VM $vmid already running\n" if PVE::QemuServer::check_running($vmid);
+
my $storecfg = PVE::Storage::config();
my $realcmd = sub {
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ die "VM $vmid not running\n" if !PVE::QemuServer::check_running($vmid);
+
+ my $storecfg = PVE::Storage::config();
+
my $realcmd = sub {
my $upid = shift;
syslog('info', "stop VM $vmid: $upid\n");
- PVE::QemuServer::vm_stop($vmid, $skiplock);
-
- my $pid = PVE::QemuServer::check_running ($vmid);
-
- if ($pid && $param->{timeout}) {
- print "waiting until VM $vmid stopps (PID $pid)\n";
-
- my $count = 0;
- while (($count < $param->{timeout}) &&
- PVE::QemuServer::check_running($vmid)) {
- $count++;
- sleep 1;
- }
-
- die "wait failed - got timeout\n" if PVE::QemuServer::check_running($vmid);
- }
+ PVE::QemuServer::vm_stop($storecfg, $vmid, $skiplock, 0, $param->{timeout});
return;
};
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ die "VM $vmid not running\n" if !PVE::QemuServer::check_running($vmid);
+
my $realcmd = sub {
my $upid = shift;
- syslog('info', "reset VM $vmid: $upid\n");
-
PVE::QemuServer::vm_reset($vmid, $skiplock);
return;
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ die "VM $vmid not running\n" if !PVE::QemuServer::check_running($vmid);
+
my $realcmd = sub {
my $upid = shift;
syslog('info', "shutdown VM $vmid: $upid\n");
- PVE::QemuServer::vm_shutdown($vmid, $skiplock);
-
- my $pid = PVE::QemuServer::check_running ($vmid);
-
- if ($pid && $param->{timeout}) {
- print "waiting until VM $vmid stopps (PID $pid)\n";
-
- my $count = 0;
- while (($count < $param->{timeout}) &&
- PVE::QemuServer::check_running($vmid)) {
- $count++;
- sleep 1;
- }
-
- die "wait failed - got timeout\n" if PVE::QemuServer::check_running($vmid);
- }
+ PVE::QemuServer::vm_shutdown($vmid, $skiplock, $param->{timeout});
return;
};
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ die "VM $vmid not running\n" if !PVE::QemuServer::check_running($vmid);
+
my $realcmd = sub {
my $upid = shift;
raise_param_exc({ skiplock => "Only root may use this option." })
if $skiplock && $user ne 'root@pam';
+ die "VM $vmid already running\n" if PVE::QemuServer::check_running($vmid);
+
my $realcmd = sub {
my $upid = shift;
use IO::File;
use IPC::Open2;
use PVE::Tools qw(run_command);
-use PVE::SafeSyslog;
use PVE::INotify;
use PVE::Cluster;
use PVE::Storage;
my $tstr = strftime("%b %d %H:%M:%S", localtime);
- syslog($level, $msg);
-
foreach my $line (split (/\n/, $msg)) {
- print STDOUT "$tstr $line\n";
+ if ($level eq 'err') {
+ print STDOUT "$tstr ERROR: $line\n";
+ } else {
+ print STDOUT "$tstr $line\n";
+ }
}
\*STDOUT->flush();
}
eval {
local $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = sub {
$delayed_interrupt = 0;
- logmsg('err', "received interrupt");
die "interrupted by signal\n";
};
local $SIG{PIPE} = sub {
$delayed_interrupt = 0;
- logmsg('err', "received broken pipe interrupt");
die "interrupted by signal\n";
};
# lock config during migration
eval { PVE::QemuServer::lock_config($vmid, sub {
- eval_int(sub { prepare($session); });
+ my $conf;
+ eval_int(sub { $conf = prepare($session); });
die $@ if $@;
- my $conf = PVE::QemuServer::load_config($vmid);
-
- PVE::QemuServer::check_lock($conf);
-
my $running = 0;
if (my $pid = PVE::QemuServer::check_running($vmid)) {
die "cant migrate running VM without --online\n" if !$online;
if ($rhash->{clearlock}) {
my $unset = { lock => 1 };
eval { PVE::QemuServer::change_config_nolock($session->{vmid}, {}, $unset, 1) };
- logmsg('err', $@) if $@;
+ if (my $tmperr = $@) {
+ logmsg('err', $tmperr);
+ }
}
if ($rhash->{volumes}) {
foreach my $volid (@{$rhash->{volumes}}) {
# always kill tunnel
if ($rhash->{tunnel}) {
eval_int(sub { finish_tunnel($rhash->{tunnel}) });
- if ($@) {
- logmsg('err', "stopping tunnel failed - $@");
+ if (my $tmperr = $@) {
+ logmsg('err', "stopping tunnel failed - $tmperr");
$errors = 1;
}
}
# always stop local VM - no interrupts possible
- eval { PVE::QemuServer::vm_stop($session->{vmid}, 1, 1); };
- if ($@) {
- logmsg('err', "stopping vm failed - $@");
+ eval { PVE::QemuServer::vm_stop($session->{storecfg}, $session->{vmid}, 1, 1); };
+ if (my $tmperr = $@) {
+ logmsg('err', "stopping vm failed - $tmperr");
$errors = 1;
}
my $cmd = [ @{$session->{rem_ssh}}, $qm_cmd, 'unlock', $session->{vmid} ];
run_command($cmd);
});
- if ($@) {
- logmsg('err', "failed to clear migrate lock - $@");
+ if (my $tmperr = $@) {
+ logmsg('err', "failed to clear migrate lock - $tmperr");
$errors = 1;
}
last if $err =~ /^interrupted by signal$/;
}
}
+
+ # always deactivate volumes - avoid lvm LVs to be active on
+ # several nodes
+ eval {
+ my $vollist = PVE::QemuServer::get_vm_volumes($conf);
+ PVE::Storage::deactivate_volumes($session->{storecfg}, $vollist);
+ };
+ if (my $tmperr = $@) {
+ logmsg('err', $tmperr);
+ $errors = 1;
+ }
+
})};
my $err = $@;
my $duration = sprintf "%02d:%02d:%02d", $hours, $mins, $secs;
if ($err) {
- my $msg = "migration aborted (duration $duration): $err\n";
- logmsg('err', $msg);
- die $msg;
+ logmsg('err', "migration aborted (duration $duration): $err");
+ die "migration aborted";
}
if ($errors) {
- my $msg = "migration finished with problems (duration $duration)\n";
- logmsg('err', $msg);
- die $msg;
+ logmsg('err', "migration finished with problems (duration $duration)");
+ die "migration problems"
}
logmsg('info', "migration finished successfuly (duration $duration)");
sub prepare {
my ($session) = @_;
- my $conffile = PVE::QemuServer::config_file($session->{vmid});
- die "VM $session->{vmid} does not exist on this node\n" if ! -f $conffile;
+ # test is VM exist
+ my $conf = PVE::QemuServer::load_config($session->{vmid});
+
+ PVE::QemuServer::check_lock($conf);
+
+ # activate volumes
+ my $vollist = PVE::QemuServer::get_vm_volumes($conf);
+ PVE::Storage::activate_volumes($session->{storecfg}, $vollist);
# test ssh connection
my $cmd = [ @{$session->{rem_ssh}}, '/bin/true' ];
eval { run_command($cmd); };
die "Can't connect to destination address using public key\n" if $@;
+
+ return $conf;
}
sub sync_disks {
my $start = time();
- PVE::QemuServer::vm_monitor_command($session->{vmid}, "migrate -d \"tcp:localhost:$lport\"", 0, 1);
+ PVE::QemuServer::vm_monitor_command($session->{vmid}, "migrate -d \"tcp:localhost:$lport\"", 1);
my $lstat = '';
while (1) {
sleep (2);
- my $stat = PVE::QemuServer::vm_monitor_command($session->{vmid}, "info migrate", 1, 1);
+ my $stat = PVE::QemuServer::vm_monitor_command($session->{vmid}, "info migrate", 1);
if ($stat =~ m/^Migration status: (active|completed|failed|cancelled)$/im) {
my $ms = $1;
return $vollist;
}
-sub unlink_image {
- my ($storecfg, $vmid, $volid) = @_;
-
- die "reject to unlink absolute path '$volid'"
- if $volid =~ m|^/|;
-
- my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
-
- die "reject to unlink '$volid' - not owned by this VM"
- if !$owner || ($owner != $vmid);
-
- syslog('info', "VM $vmid deleting volume '$volid'");
-
- PVE::Storage::vdisk_free($storecfg, $volid);
-
- touch_config($vmid);
-}
-
sub destroy_vm {
my ($storecfg, $vmid, $keep_empty_config) = @_;
return if drive_is_cdrom($drive);
my $volid = $drive->{file};
- next if !$volid || $volid =~ m|^/|;
+ return if !$volid || $volid =~ m|^/|;
my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
- next if !$path || !$owner || ($owner != $vmid);
+ return if !$path || !$owner || ($owner != $vmid);
PVE::Storage::vdisk_free($storecfg, $volid);
});
foreach_drive($conf, sub {
my ($ds, $drive) = @_;
- eval {
- PVE::Storage::parse_volume_id($drive->{file});
+ if (PVE::Storage::parse_volume_id($drive->{file}, 1)) {
push @$vollist, $drive->{file};
- }; # ignore errors
-
+ }
+
$use_virtio = 1 if $ds =~ m/^virtio/;
if ($drive->{interface} eq 'scsi') {
my $maxdev = 7;
sub vm_devices_list {
my ($vmid) = @_;
- my $res = vm_monitor_command ($vmid, "info pci", 1);
+ my $res = vm_monitor_command ($vmid, "info pci");
my @lines = split ("\n", $res);
my $devices;
if($deviceid =~ m/^(virtio)(\d+)$/) {
my $drive = print_drive_full($storecfg, $vmid, $device);
- my $ret = vm_monitor_command($vmid, "drive_add auto $drive", 1);
+ my $ret = vm_monitor_command($vmid, "drive_add auto $drive");
# If the command succeeds qemu prints: "OK"
if ($ret !~ m/OK/s) {
die "adding drive failed: $ret";
}
my $devicefull = print_drivedevice_full($storecfg, $vmid, $device);
- $ret = vm_monitor_command($vmid, "device_add $devicefull", 1);
+ $ret = vm_monitor_command($vmid, "device_add $devicefull");
$ret =~ s/^\s+//;
# Otherwise, if the command succeeds, no output is sent. So any non-empty string shows an error
die 'error on hotplug device : $ret' if $ret ne "";
if($deviceid =~ m/^(virtio)(\d+)$/){
- my $ret = vm_monitor_command($vmid, "drive_del drive-$deviceid", 1);
+ my $ret = vm_monitor_command($vmid, "drive_del drive-$deviceid");
$ret =~ s/^\s+//;
if ($ret =~ m/Device \'.*?\' not found/s) {
# NB: device not found errors mean the drive was auto-deleted and we ignore the error
die "deleting drive $deviceid failed : $ret";
}
- $ret = vm_monitor_command($vmid, "device_del $deviceid", 1);
+ $ret = vm_monitor_command($vmid, "device_del $deviceid");
$ret =~ s/^\s+//;
die 'detaching device $deviceid failed : $ret' if $ret ne "";
check_lock($conf) if !$skiplock;
- if (check_running($vmid)) {
- my $msg = "VM $vmid already running - start failed\n" ;
- syslog('err', $msg);
- die $msg;
- } else {
- syslog('info', "VM $vmid start");
- }
+ die "VM $vmid already running\n" if check_running($vmid);
my $migrate_uri;
my $migrate_port = 0;
PVE::Storage::activate_volumes($storecfg, $vollist);
eval { run_command($cmd, timeout => $migrate_uri ? undef : 30); };
-
my $err = $@;
-
- if ($err) {
- my $msg = "start failed: $err";
- syslog('err', "VM $vmid $msg");
- die $msg;
- }
+ die "start failed: $err" if $err;
if ($statefile) {
} else {
unlink $statefile;
# fixme: send resume - is that necessary ?
- eval { vm_monitor_command($vmid, "cont", 1) };
+ eval { vm_monitor_command($vmid, "cont"); };
}
}
$migrate_speed = $conf->{migrate_speed} || $migrate_speed;
eval {
my $cmd = "migrate_set_speed ${migrate_speed}m";
- vm_monitor_command($vmid, $cmd, 1);
+ vm_monitor_command($vmid, $cmd);
};
if (my $migrate_downtime =
$conf->{migrate_downtime} || $defaults->{migrate_downtime}) {
my $cmd = "migrate_set_downtime ${migrate_downtime}";
- eval { vm_monitor_command($vmid, $cmd, 1); };
+ eval { vm_monitor_command($vmid, $cmd); };
}
vm_balloonset($vmid, $conf->{balloon}) if $conf->{balloon};
}
sub vm_monitor_command {
- my ($vmid, $cmdstr, $nolog, $nocheck) = @_;
+ my ($vmid, $cmdstr, $nocheck) = @_;
my $res;
- syslog("info", "VM $vmid monitor command '$cmdstr'") if !$nolog;
-
eval {
- die "VM not running\n" if !check_running($vmid, $nocheck);
+ die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
my $sname = monitor_socket($vmid);
check_lock($conf) if !$skiplock;
- syslog("info", "VM $vmid sending 'reset'");
+ vm_monitor_command($vmid, "system_reset");
+ });
+}
+
+sub get_vm_volumes {
+ my ($conf) = @_;
- vm_monitor_command($vmid, "system_reset", 1);
+ my $vollist = [];
+ foreach_drive($conf, sub {
+ my ($ds, $drive) = @_;
+
+ my ($sid, $volname) = PVE::Storage::parse_volume_id($drive->{file}, 1);
+ return if !$sid;
+
+ my $volid = $drive->{file};
+ return if !$volid || $volid =~ m|^/|;
+
+ push @$vollist, $volid;
});
+
+ return $vollist;
+}
+
+sub vm_stop_cleanup {
+ my ($storecfg, $vmid, $conf) = @_;
+
+ fairsched_rmnod($vmid); # try to destroy group
+
+ my $vollist = get_vm_volumes($conf);
+ PVE::Storage::deactivate_volumes($storecfg, $vollist);
}
sub vm_shutdown {
- my ($vmid, $skiplock) = @_;
+ my ($storecfg, $vmid, $skiplock, $timeout) = @_;
+
+ $timeout = 60 if !$timeout;
lock_config($vmid, sub {
check_lock($conf) if !$skiplock;
- syslog("info", "VM $vmid sending 'shutdown'");
+ vm_monitor_command($vmid, "system_powerdown");
+
+ my $pid = check_running($vmid);
+
+ if ($pid && $timeout) {
+ print "waiting until VM $vmid stopps (PID $pid)\n";
+
+ my $count = 0;
+ while (($count < $timeout) && check_running($vmid)) {
+ $count++;
+ sleep 1;
+ }
+
+ die "shutdown failed - got timeout\n" if check_running($vmid);
+ }
- vm_monitor_command($vmid, "system_powerdown", 1);
+ vm_stop_cleanup($storecfg, $vmid, $conf);
});
}
# Note: use $nockeck to skip tests if VM configuration file exists.
# We need that when migration VMs to other nodes (files already moved)
sub vm_stop {
- my ($vmid, $skiplock, $nocheck) = @_;
+ my ($storecfg, $vmid, $skiplock, $nocheck, $timeout) = @_;
+
+ $timeout = 60 if !$timeout;
lock_config($vmid, sub {
my $pid = check_running($vmid, $nocheck);
+ return if !$pid;
- if (!$pid) {
- syslog('info', "VM $vmid already stopped");
- return;
- }
-
+ my $conf;
if (!$nocheck) {
- my $conf = load_config($vmid);
+ $conf = load_config($vmid);
check_lock($conf) if !$skiplock;
}
- syslog("info", "VM $vmid stopping");
-
- eval { vm_monitor_command($vmid, "quit", 1, $nocheck); };
-
+ eval { vm_monitor_command($vmid, "quit", $nocheck); };
my $err = $@;
if (!$err) {
- # wait some time
- my $timeout = 50; # fixme: how long?
-
my $count = 0;
while (($count < $timeout) && check_running($vmid, $nocheck)) {
$count++;
}
if ($count >= $timeout) {
- syslog('info', "VM $vmid still running - terminating now with SIGTERM");
+ warn "VM still running - terminating now with SIGTERM\n";
kill 15, $pid;
}
} else {
- syslog('info', "VM $vmid quit failed - terminating now with SIGTERM");
+ warn "VM quit failed - terminating now with SIGTERM\n";
kill 15, $pid;
}
# wait again
- my $timeout = 10;
+ $timeout = 10;
my $count = 0;
while (($count < $timeout) && check_running($vmid, $nocheck)) {
}
if ($count >= $timeout) {
- syslog('info', "VM $vmid still running - terminating now with SIGKILL\n");
+ warn "VM still running - terminating now with SIGKILL\n";
kill 9, $pid;
+ sleep 1;
}
- fairsched_rmnod($vmid); # try to destroy group
- });
+ vm_stop_cleanup($storecfg, $vmid, $conf) if $conf;
+ });
}
sub vm_suspend {
check_lock($conf) if !$skiplock;
- syslog("info", "VM $vmid suspend");
-
- vm_monitor_command($vmid, "stop", 1);
+ vm_monitor_command($vmid, "stop");
});
}
check_lock($conf) if !$skiplock;
- syslog("info", "VM $vmid resume");
-
- vm_monitor_command($vmid, "cont", 1);
+ vm_monitor_command($vmid, "cont");
});
}
check_lock($conf) if !$skiplock;
- syslog("info", "VM $vmid sending key $key");
-
- vm_monitor_command($vmid, "sendkey $key", 1);
+ vm_monitor_command($vmid, "sendkey $key");
});
}
check_lock($conf) if !$skiplock;
- syslog("info", "VM $vmid destroy called (removing all data)");
-
- eval {
- if (!check_running($vmid)) {
- fairsched_rmnod($vmid); # try to destroy group
- destroy_vm($storecfg, $vmid);
- } else {
- die "VM is running\n";
- }
- };
-
- my $err = $@;
-
- if ($err) {
- syslog("err", "VM $vmid destroy failed - $err");
- die $err;
+ if (!check_running($vmid)) {
+ fairsched_rmnod($vmid); # try to destroy group
+ destroy_vm($storecfg, $vmid);
+ } else {
+ die "VM $vmid is running - destroy failed\n";
}
});
}
sub vm_stopall {
- my ($timeout) = @_;
+ my ($storecfg, $timeout) = @_;
$timeout = 3*60 if !$timeout;
+ my $cleanuphash = {};
+
my $vzlist = vzlist();
my $count = 0;
foreach my $vmid (keys %$vzlist) {
next if !$vzlist->{$vmid}->{pid};
$count++;
+ $cleanuphash->{$vmid} = 1;
}
- if ($count) {
+ return if !$count;
- my $msg = "Stopping Qemu Server - sending shutdown requests to all VMs\n";
- syslog('info', $msg);
- print STDERR $msg;
+ my $msg = "Stopping Qemu Server - sending shutdown requests to all VMs\n";
+ syslog('info', $msg);
+ warn $msg;
- foreach my $vmid (keys %$vzlist) {
- next if !$vzlist->{$vmid}->{pid};
- eval { vm_shutdown($vmid, 1); };
- print STDERR $@ if $@;
+ foreach my $vmid (keys %$vzlist) {
+ next if !$vzlist->{$vmid}->{pid};
+ eval { vm_shutdown($storecfg, $vmid, 1); };
+ my $err = $@;
+ if ($err) {
+ warn $err;
+ } else {
+ delete $cleanuphash->{$vmid};
}
+ }
- my $wt = 5;
- my $maxtries = int(($timeout + $wt -1)/$wt);
- my $try = 0;
- while (($try < $maxtries) && $count) {
- $try++;
- sleep $wt;
-
- $vzlist = vzlist();
- $count = 0;
- foreach my $vmid (keys %$vzlist) {
- next if !$vzlist->{$vmid}->{pid};
- $count++;
- }
- last if !$count;
+ my $wt = 5;
+ my $maxtries = int(($timeout + $wt -1)/$wt);
+ my $try = 0;
+ while (($try < $maxtries) && $count) {
+ $try++;
+ sleep $wt;
+
+ $vzlist = vzlist();
+ $count = 0;
+ foreach my $vmid (keys %$vzlist) {
+ next if !$vzlist->{$vmid}->{pid};
+ $count++;
}
+ last if !$count;
+ }
- return if !$count;
+ if ($count) {
foreach my $vmid (keys %$vzlist) {
next if !$vzlist->{$vmid}->{pid};
- $msg = "VM $vmid still running - sending stop now\n";
- syslog('info', $msg);
- print $msg;
-
- eval { vm_monitor_command($vmid, "quit", 1); };
- print STDERR $@ if $@;
-
+ warn "VM $vmid still running - sending stop now\n";
+ eval { vm_monitor_command($vmid, "quit"); };
+ warn $@ if $@;
}
$timeout = 30;
while (($try < $maxtries) && $count) {
$try++;
sleep $wt;
-
+
$vzlist = vzlist();
$count = 0;
foreach my $vmid (keys %$vzlist) {
last if !$count;
}
- return if !$count;
+ if ($count) {
- foreach my $vmid (keys %$vzlist) {
- next if !$vzlist->{$vmid}->{pid};
+ foreach my $vmid (keys %$vzlist) {
+ next if !$vzlist->{$vmid}->{pid};
- $msg = "VM $vmid still running - terminating now with SIGTERM\n";
- syslog('info', $msg);
- print $msg;
- kill 15, $vzlist->{$vmid}->{pid};
+ warn "VM $vmid still running - terminating now with SIGTERM\n";
+ kill 15, $vzlist->{$vmid}->{pid};
+ }
+ sleep 1;
}
# this is called by system shotdown scripts, so remaining
# processes gets killed anyways (no need to send kill -9 here)
+ }
- $msg = "Qemu Server stopped\n";
- syslog('info', $msg);
- print STDERR $msg;
+ $vzlist = vzlist();
+ foreach my $vmid (keys %$cleanuphash) {
+ next if $vzlist->{$vmid}->{pid};
+ eval {
+ my $conf = load_config($vmid);
+ vm_stop_cleanup($storecfg, $vmid, $conf);
+ };
+ warn $@ if $@;
}
+
+ $msg = "Qemu Server stopped\n";
+ syslog('info', $msg);
+ print $msg;
}
# pci helpers
sub vm_balloonset {
my ($vmid, $value) = @_;
- vm_monitor_command($vmid, "balloon $value", 1);
+ vm_monitor_command($vmid, "balloon $value");
}
# vzdump restore implementaion