Commit f7b706cb authored by Dietmar Maurer's avatar Dietmar Maurer

use new AbstractMigrate.pm

parent 25ac9b68
...@@ -320,6 +320,16 @@ __PACKAGE__->register_method({ ...@@ -320,6 +320,16 @@ __PACKAGE__->register_method({
my $cmd = ['vzctl', '--skiplock', '--quiet', 'set', $vmid, my $cmd = ['vzctl', '--skiplock', '--quiet', 'set', $vmid,
'--applyconfig_map', 'name', '--save']; '--applyconfig_map', 'name', '--save'];
run_command($cmd); run_command($cmd);
# reload config
my $conf = PVE::OpenVZ::load_config($vmid);
# and initialize quota
my $disk_quota = $conf->{disk_quota}->{value};
if (!defined($disk_quota) || ($disk_quota != 0)) {
my $cmd = ['vzctl', '--skiplock', 'quotainit', $vmid];
run_command($cmd);
}
}; };
return $rpcenv->fork_worker($param->{restore} ? 'vzrestore' : 'vzcreate', return $rpcenv->fork_worker($param->{restore} ? 'vzrestore' : 'vzcreate',
...@@ -1037,7 +1047,9 @@ __PACKAGE__->register_method({ ...@@ -1037,7 +1047,9 @@ __PACKAGE__->register_method({
my $realcmd = sub { my $realcmd = sub {
my $upid = shift; my $upid = shift;
PVE::OpenVZMigrate::migrate($target, $targetip, $vmid, $param->{online});
PVE::OpenVZMigrate->migrate($target, $targetip, $vmid, $param);
return; return;
}; };
......
...@@ -2,334 +2,125 @@ package PVE::OpenVZMigrate; ...@@ -2,334 +2,125 @@ package PVE::OpenVZMigrate;
use strict; use strict;
use warnings; use warnings;
use POSIX qw(strftime); use PVE::AbstractMigrate;
use File::Basename; use File::Basename;
use File::Copy; use File::Copy;
use IO::File;
use IPC::Open2;
use PVE::Tools; use PVE::Tools;
use PVE::INotify; use PVE::INotify;
use PVE::Cluster; use PVE::Cluster;
use PVE::Storage; use PVE::Storage;
use PVE::OpenVZ; use PVE::OpenVZ;
my $delayed_interrupt = 0; use base qw(PVE::AbstractMigrate);
# blowfish is a fast block cipher, much faster then 3des # fixme: lock VM on target node
my @ssh_opts = ('-c', 'blowfish', '-o', 'BatchMode=yes');
my @ssh_cmd = ('/usr/bin/ssh', @ssh_opts);
my @scp_cmd = ('/usr/bin/scp', @ssh_opts);
my @rsync_opts = ('-aH', '--delete', '--numeric-ids');
my @rsync_cmd = ('/usr/bin/rsync', @rsync_opts);
sub msg2text { sub lock_vm {
my ($level, $msg) = @_; my ($self, $vmid, $code, @param) = @_;
chomp $msg;
return '' if !$msg;
my $res = '';
my $tstr = strftime("%b %d %H:%M:%S", localtime);
foreach my $line (split (/\n/, $msg)) {
if ($level eq 'err') {
$res .= "$tstr ERROR: $line\n";
} else {
$res .= "$tstr $line\n";
}
}
return $res;
}
sub logmsg {
my ($level, $msg) = @_;
chomp $msg;
return if !$msg;
print msg2text($level, $msg);
}
sub run_command {
my ($cmd, %param) = @_;
my $logfunc = sub {
my $line = shift;
logmsg('info', $line);
};
logmsg('info', "# " . PVE::Tools::cmd2string($cmd));
PVE::Tools::run_command($cmd, %param, outfunc => $logfunc, errfunc => $logfunc);
}
sub run_command_quiet_full {
my ($cmd, $logerr, %param) = @_;
my $log = '';
my $logfunc = sub {
my $line = shift;
$log .= msg2text('info', $line);;
};
eval { PVE::Tools::run_command($cmd, %param, outfunc => $logfunc, errfunc => $logfunc); };
if (my $err = $@) {
logmsg('info', "# " . PVE::Tools::cmd2string($cmd));
print $log;
if ($logerr) {
logmsg('err', $err);
} else {
die $err;
}
}
}
sub run_command_quiet {
my ($cmd, %param) = @_;
return run_command_quiet_full($cmd, 0, %param);
}
sub run_command_logerr {
my ($cmd, %param) = @_;
return run_command_quiet_full($cmd, 1, %param);
}
sub eval_int {
my ($func) = @_;
eval {
local $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = sub {
$delayed_interrupt = 0;
die "interrupted by signal\n";
};
local $SIG{PIPE} = sub {
$delayed_interrupt = 0;
die "interrupted by signal\n";
};
my $di = $delayed_interrupt;
$delayed_interrupt = 0;
die "interrupted by signal\n" if $di;
&$func();
};
}
sub migrate {
my ($node, $nodeip, $vmid, $online) = @_;
my $starttime = time();
my $rem_ssh =
local $ENV{RSYNC_RSH} = join(' ', @ssh_cmd);
local $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = $SIG{HUP} = $SIG{PIPE} = sub {
logmsg('err', "received interrupt - delayed");
$delayed_interrupt = 1;
};
local $ENV{RSYNC_RSH} = join(' ', @ssh_cmd);
my $session = {
vmid => $vmid,
node => $node,
nodeip => $nodeip,
storecfg => PVE::Storage::config(),
vzconf => PVE::OpenVZ::read_global_vz_config(),
rem_ssh => [@ssh_cmd, "root\@$nodeip"],
};
my $errors; return PVE::OpenVZ::lock_container($vmid, $code, @param);
# lock container during migration
eval { PVE::OpenVZ::lock_container($vmid, sub {
eval_int(sub { prepare($session, $vmid, $online); });
die $@ if $@;
my $rhash = {};
eval_int (sub { phase1($session, $vmid, $session->{vmconf}, $rhash, $session->{running}); });
my $err = $@;
if ($err) {
logmsg('err', $err);
eval { phase1_cleanup($session, $vmid, $session->{vmconf}, $rhash, $session->{running}); };
if (my $tmperr = $@) {
logmsg('err', $tmperr);
}
eval { final_cleanup($session, $vmid, $session->{vmconf}); };
if (my $tmperr = $@) {
logmsg('err', $tmperr);
}
die $err;
}
# vm is now owned by other node
# Note: there is no VM config file on the local node anymore
if ($session->{running}) {
$rhash = {};
eval_int(sub { phase2($session, $vmid, $session->{vmconf}, $rhash); });
my $phase2err = $@;
if ($phase2err) {
$errors = 1;
logmsg('err', "online migrate failure - $phase2err");
}
eval { phase2_cleanup($session, $vmid, $session->{vmconf}, $rhash, $phase2err); };
if (my $err = $@) {
logmsg('err', $err);
$errors = 1;
}
# always stop local VM - no interrupts possible
eval { phase2_stop_vm($session, $vmid, $session->{vmconf}) };
if (my $err = $@) {
logmsg('err', "stopping vm failed - $err");
$errors = 1;
}
}
# phase3 (finalize)
$rhash = {};
eval_int(sub { phase3($session, $vmid, $session->{vmconf}, $rhash); });
my $phase3err = $@;
if ($phase3err) {
logmsg('err', $phase3err);
$errors = 1;
}
eval { phase3_cleanup($session, $vmid, $session->{vmconf}, $rhash, $phase3err); };
if (my $err = $@) {
logmsg('err', $err);
$errors = 1;
}
eval { final_cleanup($session, $vmid, $session->{vmconf}); };
if (my $tmperr = $@) {
logmsg('err', $tmperr);
}
})};
my $err = $@;
my $delay = time() - $starttime;
my $mins = int($delay/60);
my $secs = $delay - $mins*60;
my $hours = int($mins/60);
$mins = $mins - $hours*60;
my $duration = sprintf "%02d:%02d:%02d", $hours, $mins, $secs;
if ($err) {
logmsg('err', "migration aborted (duration $duration): $err");
die "migration aborted\n";
}
if ($errors) {
logmsg('err', "migration finished with problems (duration $duration)");
die "migration problems\n"
}
logmsg('info', "migration finished successfuly (duration $duration)");
} }
sub prepare { sub prepare {
my ($session, $vmid, $online) = @_; my ($self, $vmid) = @_;
my $online = $self->{opts}->{online};
$self->{storecfg} = PVE::Storage::config();
$self->{vzconf} = PVE::OpenVZ::read_global_vz_config(),
# test is VM exist # test is VM exist
my $conf = $session->{vmconf} = PVE::OpenVZ::load_config($vmid); my $conf = $self->{vmconf} = PVE::OpenVZ::load_config($vmid);
my $path = PVE::OpenVZ::get_privatedir($conf, $vmid); my $path = PVE::OpenVZ::get_privatedir($conf, $vmid);
my ($vtype, $volid) = PVE::Storage::path_to_volume_id($session->{storecfg}, $path); my ($vtype, $volid) = PVE::Storage::path_to_volume_id($self->{storecfg}, $path);
my ($storage, $volname) = PVE::Storage::parse_volume_id($volid, 1) if $volid; my ($storage, $volname) = PVE::Storage::parse_volume_id($volid, 1) if $volid;
die "can't determine assigned storage\n" if !$storage; die "can't determine assigned storage\n" if !$storage;
# check if storage is available on both nodes # check if storage is available on both nodes
my $scfg = PVE::Storage::storage_check_node($session->{storecfg}, $storage); my $scfg = PVE::Storage::storage_check_node($self->{storecfg}, $storage);
PVE::Storage::storage_check_node($session->{storecfg}, $storage, $session->{node}); PVE::Storage::storage_check_node($self->{storecfg}, $storage, $self->{node});
# we simply use the backup dir to store temporary dump files # we simply use the backup dir to store temporary dump files
# Note: this is on shared storage if the storage is 'shared' # Note: this is on shared storage if the storage is 'shared'
$session->{dumpdir} = PVE::Storage::get_backup_dir($session->{storecfg}, $storage); $self->{dumpdir} = PVE::Storage::get_backup_dir($self->{storecfg}, $storage);
PVE::Storage::activate_volumes($session->{storecfg}, [ $volid ]); PVE::Storage::activate_volumes($self->{storecfg}, [ $volid ]);
$session->{storage} = $storage; $self->{storage} = $storage;
$session->{privatedir} = $path; $self->{privatedir} = $path;
$session->{rootdir} = PVE::OpenVZ::get_rootdir($conf, $vmid); $self->{rootdir} = PVE::OpenVZ::get_rootdir($conf, $vmid);
$session->{shared} = $scfg->{shared}; $self->{shared} = $scfg->{shared};
$session->{running} = 0; my $running = 0;
if (PVE::OpenVZ::check_running($vmid)) { if (PVE::OpenVZ::check_running($vmid)) {
die "cant migrate running container without --online\n" if !$online; die "cant migrate running container without --online\n" if !$online;
$session->{running} = 1; $running = 1;
} }
# fixme: test if VM uses local resources # fixme: test if VM uses local resources
# test ssh connection # test ssh connection
my $cmd = [ @{$session->{rem_ssh}}, '/bin/true' ]; my $cmd = [ @{$self->{rem_ssh}}, '/bin/true' ];
eval { run_command_quiet($cmd); }; eval { $self->cmd_quiet($cmd); };
die "Can't connect to destination address using public key\n" if $@; die "Can't connect to destination address using public key\n" if $@;
if ($session->{running}) { if ($running) {
# test if OpenVZ is running # test if OpenVZ is running
$cmd = [ @{$session->{rem_ssh}}, '/etc/init.d/vz status' ]; $cmd = [ @{$self->{rem_ssh}}, '/etc/init.d/vz status' ];
eval { run_command_quiet($cmd); }; eval { $self->cmd_quiet($cmd); };
die "OpenVZ is not running on the target machine\n" if $@; die "OpenVZ is not running on the target machine\n" if $@;
# test if CPT modules are loaded for online migration # test if CPT modules are loaded for online migration
die "vzcpt module is not loaded\n" if ! -f '/proc/cpt'; die "vzcpt module is not loaded\n" if ! -f '/proc/cpt';
$cmd = [ @{$session->{rem_ssh}}, 'test -f /proc/rst' ]; $cmd = [ @{$self->{rem_ssh}}, 'test -f /proc/rst' ];
eval { run_command_quiet($cmd); }; eval { $self->cmd_quiet($cmd); };
die "vzrst module is not loaded on the target machine\n" if $@; die "vzrst module is not loaded on the target machine\n" if $@;
} }
# fixme: do we want to test if IPs exists on target node? # fixme: do we want to test if IPs exists on target node?
return $running;
} }
sub phase1 { sub phase1 {
my ($session, $vmid, $conf, $rhash, $running) = @_; my ($self, $vmid) = @_;
logmsg('info', "starting migration of CT $session->{vmid} to node '$session->{node}' ($session->{nodeip})"); $self->log('info', "starting migration of CT $self->{vmid} to node '$self->{node}' ($self->{nodeip})");
if ($running) { my $conf = $self->{vmconf};
logmsg('info', "container is running - using online migration");
if ($self->{running}) {
$self->log('info', "container is running - using online migration");
} }
my $cmd = [ @{$session->{rem_ssh}}, 'mkdir', '-p', $session->{rootdir} ]; my $cmd = [ @{$self->{rem_ssh}}, 'mkdir', '-p', $self->{rootdir} ];
run_command_quiet($cmd, errmsg => "Failed to make container root directory"); $self->cmd_quiet($cmd, errmsg => "Failed to make container root directory");
my $privatedir = $session->{privatedir}; my $privatedir = $self->{privatedir};
if (!$session->{shared}) { if (!$self->{shared}) {
$cmd = [ @{$session->{rem_ssh}}, 'mkdir', '-p', $privatedir ]; $cmd = [ @{$self->{rem_ssh}}, 'mkdir', '-p', $privatedir ];
run_command_quiet($cmd, errmsg => "Failed to make container private directory"); $self->cmd_quiet($cmd, errmsg => "Failed to make container private directory");
$rhash->{undo_private} = $privatedir; $self->{undo_private} = $privatedir;
logmsg('info', "starting rsync phase 1"); $self->log('info', "starting rsync phase 1");
my $basedir = dirname($privatedir); my $basedir = dirname($privatedir);
$cmd = [ @rsync_cmd, '--sparse', $privatedir, "root\@$session->{nodeip}:$basedir" ]; $cmd = [ @{$self->{rsync_cmd}}, '--sparse', $privatedir, "root\@$self->{nodeip}:$basedir" ];
run_command($cmd, errmsg => "Failed to sync container private area"); $self->cmd($cmd, errmsg => "Failed to sync container private area");
} else { } else {
logmsg('info', "container data is on shared storage '$session->{storage}'"); $self->log('info', "container data is on shared storage '$self->{storage}'");
} }
my $conffile = PVE::OpenVZ::config_file($vmid); my $conffile = PVE::OpenVZ::config_file($vmid);
my $newconffile = PVE::OpenVZ::config_file($vmid, $session->{node}); my $newconffile = PVE::OpenVZ::config_file($vmid, $self->{node});
my $srccfgdir = dirname($conffile); my $srccfgdir = dirname($conffile);
my $newcfgdir = dirname($newconffile); my $newcfgdir = dirname($newconffile);
...@@ -341,208 +132,203 @@ sub phase1 { ...@@ -341,208 +132,203 @@ sub phase1 {
copy($srcfn, $dstfn) || die "copy '$srcfn' to '$dstfn' failed - $!\n"; copy($srcfn, $dstfn) || die "copy '$srcfn' to '$dstfn' failed - $!\n";
} }
if ($running) { if ($self->{running}) {
# fixme: save state and quota # fixme: save state and quota
logmsg('info', "start live migration - suspending container"); $self->log('info', "start live migration - suspending container");
$cmd = [ 'vzctl', '--skiplock', 'chkpnt', $vmid, '--suspend' ]; $cmd = [ 'vzctl', '--skiplock', 'chkpnt', $vmid, '--suspend' ];
run_command_quiet($cmd, errmsg => "Failed to suspend container"); $self->cmd_quiet($cmd, errmsg => "Failed to suspend container");
$rhash->{undo_suspend} = 1; $self->{undo_suspend} = 1;
logmsg('info', "dump container state"); $self->log('info', "dump container state");
$session->{dumpfile} = "$session->{dumpdir}/dump.$vmid"; $self->{dumpfile} = "$self->{dumpdir}/dump.$vmid";
$cmd = [ 'vzctl', '--skiplock', 'chkpnt', $vmid, '--dump', '--dumpfile', $session->{dumpfile} ]; $cmd = [ 'vzctl', '--skiplock', 'chkpnt', $vmid, '--dump', '--dumpfile', $self->{dumpfile} ];
run_command_quiet($cmd, errmsg => "Failed to dump container state"); $self->cmd_quiet($cmd, errmsg => "Failed to dump container state");
if (!$session->{shared}) { if (!$self->{shared}) {
logmsg('info', "copy dump file to target node"); $self->log('info', "copy dump file to target node");
$session->{undo_copy_dump} = 1; $self->{undo_copy_dump} = 1;
$cmd = [@scp_cmd, $session->{dumpfile}, "root\@$session->{nodeip}:$session->{dumpfile}"]; $cmd = [ @{$self->{scp_cmd}}, $self->{dumpfile}, "root\@$self->{nodeip}:$self->{dumpfile}"];
run_command_quiet($cmd, errmsg => "Failed to copy dump file"); $self->cmd_quiet($cmd, errmsg => "Failed to copy dump file");
logmsg('info', "starting rsync (2nd pass)"); $self->log('info', "starting rsync (2nd pass)");
my $basedir = dirname($privatedir); my $basedir = dirname($privatedir);
$cmd = [ @rsync_cmd, $privatedir, "root\@$session->{nodeip}:$basedir" ]; $cmd = [ @{$self->{rsync_cmd}}, $privatedir, "root\@$self->{nodeip}:$basedir" ];
run_command($cmd, errmsg => "Failed to sync container private area"); $self->cmd($cmd, errmsg => "Failed to sync container private area");
} }
} else { } else {
if (PVE::OpenVZ::check_mounted($conf, $vmid)) { if (PVE::OpenVZ::check_mounted($conf, $vmid)) {
logmsg('info', "unmounting container"); $self->log('info', "unmounting container");
$cmd = [ 'vzctl', '--skiplock', 'umount', $vmid ]; $cmd = [ 'vzctl', '--skiplock', 'umount', $vmid ];
run_command_quiet($cmd, errmsg => "Failed to umount container"); $self->cmd_quiet($cmd, errmsg => "Failed to umount container");
} }
} }
my $disk_quota = $conf->{disk_quota}->{value}; my $disk_quota = $conf->{disk_quota}->{value};
if (!defined($disk_quota) || ($disk_quota != 0)) { if (!defined($disk_quota) || ($disk_quota != 0)) {
$disk_quota = $session->{disk_quota} = 1; $disk_quota = $self->{disk_quota} = 1;
logmsg('info', "dump 2nd level quota"); $self->log('info', "dump 2nd level quota");
$session->{quotadumpfile} = "$session->{dumpdir}/quotadump.$vmid"; $self->{quotadumpfile} = "$self->{dumpdir}/quotadump.$vmid";
$cmd = "vzdqdump $vmid -U -G -T > " . PVE::Tools::shellquote($session->{quotadumpfile}); $cmd = "vzdqdump $vmid -U -G -T > " . PVE::Tools::shellquote($self->{quotadumpfile});
run_command_quiet($cmd, errmsg => "Failed to dump 2nd level quota"); $self->cmd_quiet($cmd, errmsg => "Failed to dump 2nd level quota");
if (!$session->{shared}) { if (!$self->{shared}) {
logmsg('info', "copy 2nd level quota to target node"); $self->log('info', "copy 2nd level quota to target node");
$session->{undo_copy_quota_dump} = 1; $self->{undo_copy_quota_dump} = 1;
$cmd = [@scp_cmd, $session->{quotadumpfile}, "root\@$session->{nodeip}:$session->{quotadumpfile}"]; $cmd = [@{$self->{scp_cmd}}, $self->{quotadumpfile},
run_command_quiet($cmd, errmsg => "Failed to copy 2nd level quota dump"); "root\@$self->{nodeip}:$self->{quotadumpfile}"];
$self->cmd_quiet($cmd, errmsg => "Failed to copy 2nd level quota dump");
} }
} }
# everythin copied - make sure container is stoped # everythin copied - make sure container is stoped
# fixme_ do we need to start on the other node first? # fixme_ do we need to start on the other node first?
if ($running) { if ($self->{running}) {
delete $rhash->{undo_suspend}; delete $self->{undo_suspend};
$cmd = [ 'vzctl', '--skiplock', 'chkpnt', $vmid, '--kill' ]; $cmd = [ 'vzctl', '--skiplock', 'chkpnt', $vmid, '--kill' ];
run_command_quiet($cmd, errmsg => "Failed to kill container"); $self->cmd_quiet($cmd, errmsg => "Failed to kill container");
$cmd = [ 'vzctl', '--skiplock', 'umount', $vmid ]; $cmd = [ 'vzctl', '--skiplock', 'umount', $vmid ];
run_command_quiet($cmd, errmsg => "Failed to umount container"); $self->cmd_quiet($cmd, errmsg => "Failed to umount container");
} }
# move config # move config
die "Failed to move config to node '$session->{node}' - rename failed: $!\n" die "Failed to move config to node '$self->{node}' - rename failed: $!\n"
if !rename($conffile, $newconffile); if !rename($conffile, $newconffile);
} }
# only called if there are errors in phase1
sub phase1_cleanup { sub phase1_cleanup {
my ($session, $vmid, $conf, $rhash, $running) = @_; my ($self, $vmid, $err) = @_;
logmsg('info', "aborting phase 1 - cleanup resources"); $self->log('info', "aborting phase 1 - cleanup resources");
if ($rhash->{undo_suspend}) { my $conf = $self->{vmconf};
if ($self->{undo_suspend}) {
my $cmd = [ 'vzctl', '--skiplock', 'chkpnt', $vmid, '--resume' ]; my $cmd = [ 'vzctl', '--skiplock', 'chkpnt', $vmid, '--resume' ];
run_command_logerr($cmd, errmsg => "Failed to resume container"); $self->cmd_logerr($cmd, errmsg => "Failed to resume container");
} }
if ($rhash->{undo_private}) { if ($self->{undo_private}) {
logmsg('info', "removing copied files on target node"); $self->log('info', "removing copied files on target node");
my $cmd = [ @{$session->{rem_ssh}}, 'rm', '-rf', $rhash->{undo_private} ]; my $cmd = [ @{$self->{rem_ssh}}, 'rm', '-rf', $self->{undo_private} ];
run_command_logerr($cmd, errmsg => "Failed to remove copied files"); $self->cmd_logerr($cmd, errmsg => "Failed to remove copied files");
} }
# fixme: that seem to be very dangerous and not needed # fixme: that seem to be very dangerous and not needed
#my $cmd = [ @{$session->{rem_ssh}}, 'rm', '-rf', $session->{rootdir} ]; #my $cmd = [ @{$self->{rem_ssh}}, 'rm', '-rf', $self->{rootdir} ];
#eval { run_command_quiet($cmd); }; #eval { $self->cmd_quiet($cmd); };
my $newconffile = PVE::OpenVZ::config_file($vmid, $session->{node}); my $newconffile = PVE::OpenVZ::config_file($vmid, $self->{node});
my $newcfgdir = dirname($newconffile); my $newcfgdir = dirname($newconffile);
foreach my $s (PVE::OpenVZ::SCRIPT_EXT) { foreach my $s (PVE::OpenVZ::SCRIPT_EXT) {
my $scriptfn = "${vmid}.$s"; my $scriptfn = "${vmid}.$s";
my $dstfn = "$newcfgdir/$scriptfn"; my $dstfn = "$newcfgdir/$scriptfn";
if (-f $dstfn) { if (-f $dstfn) {
logmsg('err', "unlink '$dstfn' failed - $!") if !unlink $dstfn; $self->log('err', "unlink '$dstfn' failed - $!") if !unlink $dstfn;
} }
} }
} }
sub init_target_vm { sub init_target_vm {
my ($session, $vmid, $conf) = @_; my ($self, $vmid) = @_;
my $conf = $self->{vmconf};
logmsg('info', "initialize container on remote node '$session->{node}'"); $self->log('info', "initialize container on remote node '$self->{node}'");
my $cmd = [ @{$session->{rem_ssh}}, 'vzctl', '--quiet', 'set', $vmid, my $cmd = [ @{$self->{rem_ssh}}, 'vzctl', '--quiet', 'set', $vmid,
'--applyconfig_map', 'name', '--save' ]; '--applyconfig_map', 'name', '--save' ];
run_command_quiet($cmd, errmsg => "Failed to apply config on target node"); $self->cmd_quiet($cmd, errmsg => "Failed to apply config on target node");
if ($session->{disk_quota}) { if ($self->{disk_quota}) {
logmsg('info', "initializing remote quota"); $self->log('info', "initializing remote quota");
$cmd = [ @{$session->{rem_ssh}}, 'vzctl', 'quotainit', $vmid]; $cmd = [ @{$self->{rem_ssh}}, 'vzctl', 'quotainit', $vmid];
run_command_quiet($cmd, errmsg => "Failed to initialize quota"); $self->cmd_quiet($cmd, errmsg => "Failed to initialize quota");
logmsg('info', "turn on remote quota"); $self->log('info', "turn on remote quota");
$cmd = [ @{$session->{rem_ssh}}, 'vzctl', 'quotaon', $vmid]; $cmd = [ @{$self->{rem_ssh}}, 'vzctl', 'quotaon', $vmid];
run_command_quiet($cmd, errmsg => "Failed to turn on quota"); $self->cmd_quiet($cmd, errmsg => "Failed to turn on quota");
logmsg('info', "load 2nd level quota"); $self->log('info', "load 2nd level quota");
$cmd = [ @{$session->{rem_ssh}}, "(vzdqload $vmid -U -G -T < " . $cmd = [ @{$self->{rem_ssh}}, "(vzdqload $vmid -U -G -T < " .
PVE::Tools::shellquote($session->{quotadumpfile}) . PVE::Tools::shellquote($self->{quotadumpfile}) .
" && vzquota reload2 $vmid)"]; " && vzquota reload2 $vmid)"];
run_command_quiet($cmd, errmsg => "Failed to load 2nd level quota"); $self->cmd_quiet($cmd, errmsg => "Failed to load 2nd level quota");
if (!$session->{running}) { if (!$self->{running}) {
logmsg('info', "turn off remote quota"); $self->log('info', "turn off remote quota");
$cmd = [ @{$session->{rem_ssh}}, 'vzquota', 'off', $vmid]; $cmd = [ @{$self->{rem_ssh}}, 'vzquota', 'off', $vmid];
run_command_quiet($cmd, errmsg => "Failed to turn off quota"); $self->cmd_quiet($cmd, errmsg => "Failed to turn off quota");
} }
} }
} }
# only called when VM is running
sub phase2 { sub phase2 {
my ($session, $vmid, $conf, $rhash) = @_; my ($self, $vmid) = @_;
$session->{target_initialized} = 1;
init_target_vm($session, $vmid, $conf);
logmsg('info', "starting container on remote node '$session->{node}'"); my $conf = $self->{vmconf};
logmsg('info', "restore container state"); $self->{target_initialized} = 1;
$session->{dumpfile} = "$session->{dumpdir}/dump.$vmid"; init_target_vm($self, $vmid);
my $cmd = [ @{$session->{rem_ssh}}, 'vzctl', 'restore', $vmid, '--undump',
'--dumpfile', $session->{dumpfile}, '--skip_arpdetect' ];
run_command_quiet($cmd, errmsg => "Failed to restore container");
$cmd = [ @{$session->{rem_ssh}}, 'vzctl', 'restore', $vmid, '--resume' ];
run_command_quiet($cmd, errmsg => "Failed to resume container");
}
sub phase2_cleanup { $self->log('info', "starting container on remote node '$self->{node}'");
my ($session, $vmid, $conf, $rhash, $err) = @_;
}; $self->log('info', "restore container state");
$self->{dumpfile} = "$self->{dumpdir}/dump.$vmid";
sub phase2_stop_vm { my $cmd = [ @{$self->{rem_ssh}}, 'vzctl', 'restore', $vmid, '--undump',
my ($session, $vmid, $conf, $rhash); '--dumpfile', $self->{dumpfile}, '--skip_arpdetect' ];
$self->cmd_quiet($cmd, errmsg => "Failed to restore container");
$cmd = [ @{$self->{rem_ssh}}, 'vzctl', 'restore', $vmid, '--resume' ];
$self->cmd_quiet($cmd, errmsg => "Failed to resume container");
} }
# finalize
sub phase3 { sub phase3 {
my ($session, $vmid, $conf, $rhash) = @_; my ($self, $vmid) = @_;
if (!$session->{target_initialized}) { if (!$self->{target_initialized}) {
init_target_vm($session, $vmid, $conf); init_target_vm($self, $vmid);
} }
} }
# phase3 cleanup
sub phase3_cleanup { sub phase3_cleanup {
my ($session, $vmid, $conf, $rhash, $err) = @_; my ($self, $vmid, $err) = @_;
my $conf = $self->{vmconf};
if (!$session->{shared}) { if (!$self->{shared}) {
# destroy local container data # destroy local container data
logmsg('info', "removing container files on local node"); $self->log('info', "removing container files on local node");
my $cmd = [ 'rm', '-rf', $session->{privatedir} ]; my $cmd = [ 'rm', '-rf', $self->{privatedir} ];
run_command_logerr($cmd); $self->cmd_logerr($cmd);
} }
if ($session->{disk_quota}) { if ($self->{disk_quota}) {
my $cmd = [ 'vzquota', 'drop', $vmid]; my $cmd = [ 'vzquota', 'drop', $vmid];
run_command_logerr($cmd, errmsg => "Failed to drop local quota"); $self->cmd_logerr($cmd, errmsg => "Failed to drop local quota");
} }
} }
# final cleanup - always called
sub final_cleanup { sub final_cleanup {
my ($session, $vmid, $conf) = @_; my ($self, $vmid) = @_;
logmsg('info', "start final cleanup"); $self->log('info', "start final cleanup");
unlink($session->{quotadumpfile}) if $session->{quotadumpfile}; my $conf = $self->{vmconf};
unlink($session->{dumpfile}) if $session->{dumpfile}; unlink($self->{quotadumpfile}) if $self->{quotadumpfile};
if ($session->{undo_copy_dump} && $session->{dumpfile}) { unlink($self->{dumpfile}) if $self->{dumpfile};
my $cmd = [ @{$session->{rem_ssh}}, 'rm', '-f', $session->{dumpfile} ];
run_command_logerr($cmd, errmsg => "Failed to remove dump file");
}
if ($session->{undo_copy_quota_dump} && $session->{quotadumpfile}) { if ($self->{undo_copy_dump} && $self->{dumpfile}) {
my $cmd = [ @{$session->{rem_ssh}}, 'rm', '-f', $session->{quotadumpfile} ]; my $cmd = [ @{$self->{rem_ssh}}, 'rm', '-f', $self->{dumpfile} ];
run_command_logerr($cmd, errmsg => "Failed to remove 2nd level quota dump file"); $self->cmd_logerr($cmd, errmsg => "Failed to remove dump file");
} }
if ($self->{undo_copy_quota_dump} && $self->{quotadumpfile}) {
my $cmd = [ @{$self->{rem_ssh}}, 'rm', '-f', $self->{quotadumpfile} ];
$self->cmd_logerr($cmd, errmsg => "Failed to remove 2nd level quota dump file");
}
} }
1; 1;
...@@ -292,17 +292,7 @@ Ext.define('PVE.KVMConsole', { ...@@ -292,17 +292,7 @@ Ext.define('PVE.KVMConsole', {
vm_command("resume"); vm_command("resume");
} }
}, },
{ // Note: no migrate here, because we can't display migrate log
text: gettext('Migrate'),
handler: function() {
var win = Ext.create('PVE.window.Migrate', {
vmtype: 'qemu',
nodename: me.nodename,
vmid: me.vmid
});
win.show();
}
},
{ {
text: gettext('Console'), text: gettext('Console'),
handler: function() { handler: function() {
...@@ -397,17 +387,8 @@ Ext.define('PVE.OpenVZConsole', { ...@@ -397,17 +387,8 @@ Ext.define('PVE.OpenVZConsole', {
}); });
} }
}, },
{ // Note: no migrate here, because we can't display migrate log
text: gettext('Migrate'), // and openvz migrate does not work if console is open
handler: function() {
var win = Ext.create('PVE.window.Migrate', {
vmtype: 'openvz',
nodename: me.nodename,
vmid: me.vmid
});
win.show();
}
},
{ {
text: gettext('Console'), text: gettext('Console'),
handler: function() { handler: function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment