diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm index dd48f78e..62e90733 100644 --- a/PVE/QemuMigrate.pm +++ b/PVE/QemuMigrate.pm @@ -11,6 +11,7 @@ use PVE::Cluster; use PVE::Storage; use PVE::QemuServer; use Time::HiRes qw( usleep ); +use PVE::RPCEnvironment; use base qw(PVE::AbstractMigrate); @@ -308,11 +309,19 @@ sub phase2 { my $rport; + my $spice_port; my $nodename = PVE::INotify::nodename(); ## start on remote node - my $cmd = [@{$self->{rem_ssh}}, 'qm', 'start', - $vmid, '--stateuri', 'tcp', '--skiplock', '--migratedfrom', $nodename]; + my $cmd = [@{$self->{rem_ssh}}]; + + if($conf->{vga} eq 'qxl'){ + my $res = PVE::QemuServer::vm_mon_cmd($vmid, 'query-spice'); + push @$cmd, 'SPICETICKET='.$res->{ticket} if $res->{ticket}; + } + + push @$cmd , 'qm', 'start', $vmid, '--stateuri', 'tcp', '--skiplock', '--migratedfrom', $nodename; + if ($self->{forcemachine}) { push @$cmd, '--machine', $self->{forcemachine}; @@ -323,6 +332,8 @@ sub phase2 { if ($line =~ m/^migration listens on port (\d+)$/) { $rport = $1; + }elsif ($line =~ m/^spice listens on port (\d+)$/) { + $spice_port = $1; } }, errfunc => sub { my $line = shift; @@ -380,6 +391,24 @@ sub phase2 { PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "migrate-set-cache-size", value => $cachesize); }; + if($conf->{vga} eq 'qxl'){ + my $rpcenv = PVE::RPCEnvironment::get(); + my $authuser = $rpcenv->get_user(); + + my ($ticket, $proxyticket) = PVE::AccessControl::assemble_spice_ticket($authuser, $vmid, $self->{node}); + + my $filename = "/etc/pve/nodes/".$self->{node}."/pve-ssl.pem"; + my $subject = PVE::QemuServer::read_x509_subject_spice($filename); + + $self->log('info', "spice client_migrate_info"); + + eval { + PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "client_migrate_info", protocol => 'spice', hostname => $proxyticket, 'tls-port' => int($spice_port), 'cert-subject' => $subject); + }; + $self->log('info', "client_migrate_info error: $@") if $@; + + } + eval { PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "migrate", uri => "tcp:localhost:$lport"); }; @@ -550,6 +579,18 @@ sub phase3_cleanup { } } + my $timer = 0; + if($conf->{vga} eq 'qxl'){ + $self->log('info', "Waiting for spice server migration"); + while (1) { + my $res = PVE::QemuServer::vm_mon_cmd_nocheck($vmid, 'query-spice'); + last if int($res->{'migrated'}) == 1; + last if $timer > 50; + $timer ++; + usleep(200000); + } + } + # always stop local VM eval { PVE::QemuServer::vm_stop($self->{storecfg}, $vmid, 1, 1); }; if (my $err = $@) { diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 0f2d245a..ccd65655 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -2457,10 +2457,10 @@ sub config_to_command { if ($vga eq 'qxl') { my $pciaddr = print_pci_addr("spice", $bridges); - + my $port = PVE::Tools::next_unused_port(61000, 61099); - push @$cmd, '-spice', "tls-port=$port,addr=127.0.0.1,tls-ciphers=DES-CBC3-SHA"; + push @$cmd, '-spice', "tls-port=$port,addr=127.0.0.1,tls-ciphers=DES-CBC3-SHA,seamless-migration=on"; push @$cmd, '-device', "virtio-serial,id=spice$pciaddr"; push @$cmd, '-chardev', "spicevmc,id=vdagent,name=vdagent"; @@ -2593,7 +2593,7 @@ sub vnc_socket { sub spice_port { my ($vmid) = @_; - my $res = vm_mon_cmd($vmid, 'query-spice'); + my $res = vm_mon_cmd_nocheck($vmid, 'query-spice'); return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n"; } @@ -3090,6 +3090,15 @@ sub vm_start { $capabilities->{capability} = "xbzrle"; $capabilities->{state} = JSON::true; eval { vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => [$capabilities]); }; + if($conf->{vga} eq 'qxl'){ + my $spice_port = PVE::QemuServer::spice_port($vmid); + print "spice listens on port $spice_port\n" if $spice_port; + if($spiceticket){ + PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice', password => $spiceticket); + PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice', time => "+5"); + } + } + } else{