]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuMigrate.pm
drive_mirror: rename variables and values
[qemu-server.git] / PVE / QemuMigrate.pm
index aa8ee6e406fe1b3bf75a5c0c33392eda00b61beb..3e5f093631f91d0081a79e5260bbb2c82c98fceb 100644 (file)
@@ -142,7 +142,10 @@ sub write_tunnel {
 sub fork_tunnel {
     my ($self, $tunnel_addr) = @_;
 
-    my @localtunnelinfo = defined($tunnel_addr) ? ('-L' , $tunnel_addr ) : ();
+    my @localtunnelinfo = ();
+    foreach my $addr (@$tunnel_addr) {
+       push @localtunnelinfo, '-L', $addr;
+    }
 
     my $cmd = [@{$self->{rem_ssh}}, '-o ExitOnForwardFailure=yes', @localtunnelinfo, '/usr/sbin/qm', 'mtunnel' ];
 
@@ -184,7 +187,7 @@ sub finish_tunnel {
 
     if ($tunnel->{sock_addr}) {
        # ssh does not clean up on local host
-       my $cmd = ['rm', '-f', $tunnel->{sock_addr}]; #
+       my $cmd = ['rm', '-f', @{$tunnel->{sock_addr}}]; #
        PVE::Tools::run_command($cmd);
 
        # .. and just to be sure check on remote side
@@ -319,6 +322,7 @@ sub sync_disks {
                # a raw+size stream, but on-the-fly conversion from qcow2 to raw+size
                # back to qcow2 is currently not possible.
                $local_volumes->{$volid}->{snapshots} = ($volinfo->{format} =~ /^(?:qcow2|vmdk)$/);
+               $local_volumes->{$volid}->{format} = $volinfo->{format};
            });
        }
 
@@ -370,7 +374,6 @@ sub sync_disks {
            die "owned by other VM (owner = VM $owner)\n"
                if !$owner || ($owner != $self->{vmid});
 
-           my $format = PVE::QemuServer::qemu_img_format($scfg, $volname);
            if (defined($snaprefs)) {
                $local_volumes->{$volid}->{snapshots} = 1;
 
@@ -378,7 +381,7 @@ sub sync_disks {
                # exceptions: 'zfspool' or 'qcow2' files (on directory storage)
 
                die "online storage migration not possible if snapshot exists\n" if $self->{running};
-               if (!($scfg->{type} eq 'zfspool' || $format eq 'qcow2')) {
+               if (!($scfg->{type} eq 'zfspool' || $local_volumes->{$volid}->{format} eq 'qcow2')) {
                    die "non-migratable snapshot exists\n";
                }
            }
@@ -594,10 +597,16 @@ sub phase2 {
     }
 
     my $spice_port;
+    my $tunnel_addr = [];
+    my $sock_addr = [];
+    # version > 0 for unix socket support
+    my $nbd_protocol_version = 1;
+    my $input = "nbd_protocol_version: $nbd_protocol_version\n";
+    $input .= "spice_ticket: $spice_ticket\n" if $spice_ticket;
 
     # Note: We try to keep $spice_ticket secret (do not pass via command line parameter)
     # instead we pipe it through STDIN
-    my $exitcode = PVE::Tools::run_command($cmd, input => $spice_ticket, outfunc => sub {
+    my $exitcode = PVE::Tools::run_command($cmd, input => $input, outfunc => sub {
        my $line = shift;
 
        if ($line =~ m/^migration listens on tcp:(localhost|[\d\.]+|\[[\d\.:a-fA-F]+\]):(\d+)$/) {
@@ -626,7 +635,18 @@ sub phase2 {
 
            $self->{target_drive}->{$targetdrive}->{drivestr} = $drivestr;
            $self->{target_drive}->{$targetdrive}->{nbd_uri} = $nbd_uri;
+       } elsif ($line =~ m!^storage migration listens on nbd:unix:(/run/qemu-server/(\d+)_nbd\.migrate):exportname=(\S+) volume:(\S+)$!) {
+           my $drivestr = $4;
+           die "Destination UNIX socket's VMID does not match source VMID" if $vmid ne $2;
+           my $nbd_unix_addr = $1;
+           my $nbd_uri = "nbd:unix:$nbd_unix_addr:exportname=$3";
+           my $targetdrive = $3;
+           $targetdrive =~ s/drive-//g;
 
+           $self->{target_drive}->{$targetdrive}->{drivestr} = $drivestr;
+           $self->{target_drive}->{$targetdrive}->{nbd_uri} = $nbd_uri;
+           push @$tunnel_addr, "$nbd_unix_addr:$nbd_unix_addr";
+           push @$sock_addr, $nbd_unix_addr;
        } elsif ($line =~ m/^QEMU: (.*)$/) {
            $self->log('info', "[$self->{node}] $1\n");
        }
@@ -645,20 +665,31 @@ sub phase2 {
 
        if ($ruri =~ /^unix:/) {
            unlink $raddr;
-           $self->{tunnel} = $self->fork_tunnel("$raddr:$raddr");
-           $self->{tunnel}->{sock_addr} = $raddr;
+           push @$tunnel_addr, "$raddr:$raddr";
+           $self->{tunnel} = $self->fork_tunnel($tunnel_addr);
+           push @$sock_addr, $raddr;
 
            my $unix_socket_try = 0; # wait for the socket to become ready
-           while (! -S $raddr) {
+           while ($unix_socket_try <= 100) {
                $unix_socket_try++;
-               if ($unix_socket_try > 100) {
-                   $self->{errors} = 1;
-                   $self->finish_tunnel($self->{tunnel});
-                   die "Timeout, migration socket $ruri did not get ready";
+               my $available = 0;
+               foreach my $sock (@$sock_addr) {
+                   if (-S $sock) {
+                       $available++;
+                   }
+               }
+
+               if ($available == @$sock_addr) {
+                   last;
                }
 
                usleep(50000);
            }
+           if ($unix_socket_try > 100) {
+               $self->{errors} = 1;
+               $self->finish_tunnel($self->{tunnel});
+               die "Timeout, migration socket $ruri did not get ready";
+           }
 
        } elsif ($ruri =~ /^tcp:/) {
            my $tunnel_addr;
@@ -678,6 +709,7 @@ sub phase2 {
        #fork tunnel for insecure migration, to send faster commands like resume
        $self->{tunnel} = $self->fork_tunnel();
     }
+    $self->{tunnel}->{sock_addr} = $sock_addr if (@$sock_addr);
 
     my $start = time();
 
@@ -703,7 +735,7 @@ sub phase2 {
            my $bwlimit = PVE::Storage::get_bandwidth_limit('migration', [$source_sid, $target_sid], $opt_bwlimit);
 
            $self->log('info', "$drive: start migration to $nbd_uri");
-           PVE::QemuServer::qemu_drive_mirror($vmid, $drive, $nbd_uri, $vmid, undef, $self->{storage_migration_jobs}, 1, undef, $bwlimit);
+           PVE::QemuServer::qemu_drive_mirror($vmid, $drive, $nbd_uri, $vmid, undef, $self->{storage_migration_jobs}, 'skip', undef, $bwlimit);
        }
     }
 
@@ -967,8 +999,8 @@ sub phase3_cleanup {
     my $tunnel = $self->{tunnel};
 
     if ($self->{storage_migration}) {
-       # finish block-job
-       eval { PVE::QemuServer::qemu_drive_mirror_monitor($vmid, undef, $self->{storage_migration_jobs}); };
+       # finish block-job with block-job-cancel, to disconnect source VM from NBD
+       eval { PVE::QemuServer::qemu_drive_mirror_monitor($vmid, undef, $self->{storage_migration_jobs}, 'cancel'); };
 
        if (my $err = $@) {
            eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $self->{storage_migration_jobs}) };