sub fork_tunnel {
my ($self, $nodeip, $lport, $rport) = @_;
- my $cmd = [@{$self->{rem_ssh}}, '-L', "$lport:localhost:$rport",
+ my @localtunnelinfo = (defined $lport) ? qw(-L $lport:localhost:$rport) : ();
+
+ my $cmd = [@{$self->{rem_ssh}}, @localtunnelinfo,
'qm', 'mtunnel' ];
my $tunnel = $self->fork_command_pipe($cmd);
$self->log('info', "starting VM $vmid on remote node '$self->{node}'");
+ my $raddr;
my $rport;
-
my $nodename = PVE::INotify::nodename();
## start on remote node
PVE::Tools::run_command($cmd, input => $spice_ticket, outfunc => sub {
my $line = shift;
- if ($line =~ m/^migration listens on port (\d+)$/) {
+ if ($line =~ m/^migration listens on tcp:([\d\.]+|localhost):(\d+)$/) {
+ $raddr = $1;
+ $rport = int($2);
+ }
+ elsif ($line =~ m/^migration listens on port (\d+)$/) {
+ $raddr = "localhost";
$rport = int($1);
- }elsif ($line =~ m/^spice listens on port (\d+)$/) {
+ }
+ elsif ($line =~ m/^spice listens on port (\d+)$/) {
$spice_port = int($1);
}
}, errfunc => sub {
$self->log('info', $line);
});
- die "unable to detect remote migration port\n" if !$rport;
-
- $self->log('info', "starting migration tunnel");
+ die "unable to detect remote migration address\n" if !$raddr;
## create tunnel to remote port
- my $lport = PVE::Tools::next_migrate_port();
+ $self->log('info', "starting ssh migration tunnel");
+ my $lport = ($raddr eq "localhost") ? PVE::Tools::next_migrate_port() : undef;
$self->{tunnel} = $self->fork_tunnel($self->{nodeip}, $lport, $rport);
- $self->log('info', "starting online/live migration on port $lport");
- # start migration
-
my $start = time();
+ $self->log('info', "starting online/live migration on $raddr:$rport");
+ $self->{livemigration} = 1;
# load_defaults
my $defaults = PVE::QemuServer::load_defaults();
}
eval {
- PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "migrate", uri => "tcp:localhost:$lport");
+ PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "migrate", uri => "tcp:$raddr:$rport");
};
my $merr = $@;
+ $self->log('info', "migrate uri => tcp:$raddr:$rport failed: $merr") if $merr;
my $lstat = 0;
my $usleep = 2000000;
die "Failed to move config to node '$self->{node}' - rename failed: $!\n"
if !rename($conffile, $newconffile);
- # now that config file is move, we can resume vm on target if livemigrate
- if ($self->{tunnel}) {
+ if ($self->{livemigration}) {
+ # now that config file is move, we can resume vm on target if livemigrate
my $cmd = [@{$self->{rem_ssh}}, 'qm', 'resume', $vmid, '--skiplock'];
eval{ PVE::Tools::run_command($cmd, outfunc => sub {},
errfunc => sub {
my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
my $migrate_port = 0;
-
+ my $migrate_uri;
if ($statefile) {
if ($statefile eq 'tcp') {
+ my $localip = "localhost";
+ my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
+ if ($datacenterconf->{migration_unsecure}) {
+ my $nodename = PVE::INotify::nodename();
+ $localip = PVE::Cluster::remote_node_ip($nodename, 1);
+ }
$migrate_port = PVE::Tools::next_migrate_port();
- my $migrate_uri = "tcp:localhost:${migrate_port}";
+ $migrate_uri = "tcp:${localip}:${migrate_port}";
push @$cmd, '-incoming', $migrate_uri;
push @$cmd, '-S';
} else {
my $err = $@;
die "start failed: $err" if $err;
- print "migration listens on port $migrate_port\n" if $migrate_port;
+ print "migration listens on $migrate_uri\n" if $migrate_uri;
if ($statefile && $statefile ne 'tcp') {
eval { vm_mon_cmd_nocheck($vmid, "cont"); };