my $other_errors = [];
my $abort = 0;
- my $sharedvm = 1;
-
my $log_error = sub {
my ($msg, $volid) = @_;
# check if storage is available on target node
PVE::Storage::storage_check_node($self->{storecfg}, $targetsid, $self->{node});
- $sharedvm = 0; # there is a non-shared disk
PVE::Storage::foreach_volid($dl, sub {
my ($volid, $sid, $volname) = @_;
return if $scfg->{shared};
- $sharedvm = 0;
-
$local_volumes->{$volid}->{ref} = $attr->{referenced_in_config} ? 'config' : 'snapshot';
if ($attr->{cdrom}) {
'PVE::QemuConfig', $jobcfg, $start_time, $start_time, $logfunc);
}
+ # sizes in config have to be accurate for remote node to correctly
+ # allocate disks, rescan to be sure
+ my $volid_hash = PVE::QemuServer::scan_volids($self->{storecfg}, $vmid);
+ PVE::QemuServer::foreach_drive($conf, sub {
+ my ($key, $drive) = @_;
+ my ($updated, $old_size, $new_size) = PVE::QemuServer::update_disksize($drive, $volid_hash);
+ if (defined($updated)) {
+ $conf->{$key} = PVE::QemuServer::print_drive($updated);
+ $self->log('info', "size of disk '$updated->{file}' ($key) updated from $old_size to $new_size\n");
+ }
+ });
+
$self->log('info', "copying local disk images") if scalar(%$local_volumes);
foreach my $volid (keys %$local_volumes) {
foreach my $target_drive (keys %{$self->{target_drive}}) {
- my $drive = PVE::QemuServer::parse_drive($target_drive, $self->{target_drive}->{$target_drive}->{volid});
+ my $drive = PVE::QemuServer::parse_drive($target_drive, $self->{target_drive}->{$target_drive}->{drivestr});
my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
my $cmd = [@{$self->{rem_ssh}}, 'pvesm', 'free', "$storeid:$volname"];
sync_disks($self, $vmid);
+ # sync_disks fixes disk sizes to match their actual size, write changes so
+ # target allocates correct volumes
+ PVE::QemuConfig->write_config($vmid, $conf);
};
sub phase1_cleanup {
# Note: We try to keep $spice_ticket secret (do not pass via command line parameter)
# instead we pipe it through STDIN
- PVE::Tools::run_command($cmd, input => $spice_ticket, outfunc => sub {
+ my $exitcode = PVE::Tools::run_command($cmd, input => $spice_ticket, outfunc => sub {
my $line = shift;
if ($line =~ m/^migration listens on tcp:(localhost|[\d\.]+|\[[\d\.:a-fA-F]+\]):(\d+)$/) {
$spice_port = int($1);
}
elsif ($line =~ m/^storage migration listens on nbd:(localhost|[\d\.]+|\[[\d\.:a-fA-F]+\]):(\d+):exportname=(\S+) volume:(\S+)$/) {
- my $volid = $4;
+ my $drivestr = $4;
my $nbd_uri = "nbd:$1:$2:exportname=$3";
my $targetdrive = $3;
$targetdrive =~ s/drive-//g;
- $self->{target_drive}->{$targetdrive}->{volid} = $volid;
+ $self->{target_drive}->{$targetdrive}->{drivestr} = $drivestr;
$self->{target_drive}->{$targetdrive}->{nbd_uri} = $nbd_uri;
+ } elsif ($line =~ m/^QEMU: (.*)$/) {
+ $self->log('info', "[$self->{node}] $1\n");
}
}, errfunc => sub {
my $line = shift;
- $self->log('info', $line);
- });
+ $self->log('info', "[$self->{node}] $line");
+ }, noerr => 1);
+
+ die "remote command failed with exit code $exitcode\n" if $exitcode;
die "unable to detect remote migration address\n" if !$raddr;
foreach my $drive (keys %{$self->{target_drive}}){
my $target = $self->{target_drive}->{$drive};
my $nbd_uri = $target->{nbd_uri};
- my $source_sid = PVE::Storage::Plugin::parse_volume_id($conf->{$drive});
- my $target_sid = PVE::Storage::Plugin::parse_volume_id($target->{volid});
+
+ my $source_drive = PVE::QemuServer::parse_drive($drive, $conf->{$drive});
+ my $target_drive = PVE::QemuServer::parse_drive($drive, $target->{drivestr});
+
+ my $source_sid = PVE::Storage::Plugin::parse_volume_id($source_drive->{file});
+ my $target_sid = PVE::Storage::Plugin::parse_volume_id($target_drive->{file});
+
my $bwlimit = PVE::Storage::get_bandwidth_limit('migrate', [$source_sid, $target_sid], $opt_bwlimit);
$self->log('info', "$drive: start migration to $nbd_uri");
die "Failed to complete storage migration: $err\n";
} else {
foreach my $target_drive (keys %{$self->{target_drive}}) {
- my $drive = PVE::QemuServer::parse_drive($target_drive, $self->{target_drive}->{$target_drive}->{volid});
+ my $drive = PVE::QemuServer::parse_drive($target_drive, $self->{target_drive}->{$target_drive}->{drivestr});
$conf->{$target_drive} = PVE::QemuServer::print_drive($drive);
PVE::QemuConfig->write_config($vmid, $conf);
}