On March 18, 2020 10:02 am, Stefan Reiter wrote:
> On 17/03/2020 20:56, Mira Limbeck wrote:
>> The reuse of the tunnel, which we're opening to communicate with the target
>> node and to forward the unix socket for the state migration, for the NBD unix
>> socket requires adding support for an array of sockets to forward, not just a
>> single one. We also have to change the $sock_addr variable to an array
>> for the cleanup of the socket file as SSH does not remove the file.
>> 
>> To communicate to the target node the support of unix sockets for NBD
>> storage migration, we're specifying an nbd_protocol_version which is set
>> to 1. This version is then passed to the target node via STDIN. Because
>> we don't want to be dependent on the order of arguments being passed
>> via STDIN, we also prefix the spice ticket with 'spice_ticket: '. The
>> target side handles both the spice ticket and the nbd protocol version
>> with a fallback for old source nodes passing the spice ticket without a
>> prefix.
>> All arguments are line based and require a newline in between.
>> 
>> When the NBD server on the target node is started with a unix socket, we
>> get a different line containing all the information required to start
>> the drive-mirror. This contains the unix socket path used on the target node
>> which we require for forwarding and cleanup.
>> 
>> Signed-off-by: Mira Limbeck <m.limb...@proxmox.com>
>> ---
>> v2:
>>   - added 'spice_ticket: (...)' to input if $spice_ticket is defined
>>   - added waiting for all sockets that are used in the tunnel
>> 
>>   PVE/QemuMigrate.pm | 52 +++++++++++++++++++++++++++++++++++++---------
>>   1 file changed, 42 insertions(+), 10 deletions(-)
>> 
>> diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm
>> index 10c0ff2..50ebd77 100644
>> --- a/PVE/QemuMigrate.pm
>> +++ b/PVE/QemuMigrate.pm
>> @@ -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
>> @@ -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;
> 
> I know it's already been applied, but this breaks new->old migration 
> (with SPICE) for no reason, doesn't it? I know we don't always support 
> it, but I don't see why we need the break here..
> 
> I.e. if we just send the spice-ticket w/o a prefix an old node will be 
> perfectly happy and just send us back the TCP migration URI (and with 
> the fallback in place a new node will also be happy), but if we do 
> prefix it the remote will pick up the entire "spice_ticket: xxx" as the 
> ticket.

yes, we could revert that back to the old behaviour and add a FIXME: add 
prefix 'spice_ticket: ' with 7.0?

> 
>>   
>>       # 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();
>>   
>> 
> 

_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to