use PVE::INotify;
use PVE::Cluster;
use PVE::Storage;
+use PVE::LXC::Config;
use PVE::LXC;
+use PVE::ReplicationConfig;
+use PVE::ReplicationState;
+use PVE::Replication;
use base qw(PVE::AbstractMigrate);
my $force = $self->{opts}->{force} // 0;
my $need_activate = [];
- PVE::LXC::Config->foreach_mountpoint($conf, sub {
+ PVE::LXC::Config->foreach_volume($conf, sub {
my ($ms, $mountpoint) = @_;
my $volid = $mountpoint->{volume};
$self->log('info', "shutdown CT $vmid\n");
- my $cmd = ['lxc-stop', '-n', $vmid, '--timeout', $timeout];
- $self->cmd($cmd, timeout => $timeout + 5);
-
- # make sure container is stopped
- $cmd = ['lxc-wait', '-n', $vmid, '-t', 5, '-s', 'STOPPED'];
- $self->cmd($cmd);
+ PVE::LXC::vm_stop($vmid, 0, $timeout);
$running = 0;
}
return;
}
- $volhash->{$volid} = defined($snapname) ? 'snapshot' : 'config';
+ $volhash->{$volid}->{ref} = defined($snapname) ? 'snapshot' : 'config';
+ $volhash->{$volid}->{snapshots} = defined($snapname);
my ($path, $owner) = PVE::Storage::path($self->{storecfg}, $volid);
PVE::Storage::foreach_volid($dl, sub {
my ($volid, $sid, $volname) = @_;
- $volhash->{$volid} = 'storage';
+ $volhash->{$volid}->{ref} = 'storage';
});
}
foreach my $snapname (keys %{$conf->{snapshots}}) {
&$test_volid($conf->{snapshots}->{$snapname}->{'vmstate'}, 0, undef)
if defined($conf->{snapshots}->{$snapname}->{'vmstate'});
- PVE::LXC::Config->foreach_mountpoint($conf->{snapshots}->{$snapname}, $test_mp, $snapname);
+ PVE::LXC::Config->foreach_volume($conf->{snapshots}->{$snapname}, $test_mp, $snapname);
}
# finally all currently used volumes
- PVE::LXC::Config->foreach_mountpoint($conf, $test_mp);
+ PVE::LXC::Config->foreach_volume($conf, $test_mp);
# additional checks for local storage
}
foreach my $volid (sort keys %$volhash) {
- if ($volhash->{$volid} eq 'storage') {
+ my $ref = $volhash->{$volid}->{ref};
+ if ($ref eq 'storage') {
$self->log('info', "found local volume '$volid' (via storage)\n");
- } elsif ($volhash->{$volid} eq 'config') {
+ } elsif ($ref eq 'config') {
$self->log('info', "found local volume '$volid' (in current VM config)\n");
- } elsif ($volhash->{$volid} eq 'snapshot') {
+ } elsif ($ref eq 'snapshot') {
$self->log('info', "found local volume '$volid' (referenced by snapshot(s))\n");
} else {
$self->log('info', "found local volume '$volid'\n");
die "can't migrate CT - check log\n";
}
+ my $rep_volumes;
+
+ my $rep_cfg = PVE::ReplicationConfig->new();
+
+ if (my $jobcfg = $rep_cfg->find_local_replication_job($vmid, $self->{node})) {
+ die "can't live migrate VM with replicated volumes\n" if $self->{running};
+ my $start_time = time();
+ my $logfunc = sub { my ($msg) = @_; $self->log('info', $msg); };
+ $rep_volumes = PVE::Replication::run_replication(
+ 'PVE::LXC::Config', $jobcfg, $start_time, $start_time, $logfunc);
+ }
+
+ my $opts = $self->{opts};
foreach my $volid (keys %$volhash) {
+ next if $rep_volumes->{$volid};
my ($sid, $volname) = PVE::Storage::parse_volume_id($volid);
push @{$self->{volumes}}, $volid;
- PVE::Storage::storage_migrate($self->{storecfg}, $volid, $self->{ssh_info}, $sid);
+ my $bwlimit = PVE::Storage::get_bandwidth_limit('migration', [$sid], $opts->{bwlimit});
+ # JSONSchema and get_bandwidth_limit use kbps - storage_migrate bps
+ $bwlimit = $bwlimit * 1024 if defined($bwlimit);
+
+ my $storage_migrate_opts = {
+ 'bwlimit' => $bwlimit,
+ 'insecure' => $opts->{migration_type} eq 'insecure',
+ 'with_snapshots' => $volhash->{$volid}->{snapshots},
+ };
+
+ PVE::Storage::storage_migrate($self->{storecfg}, $volid, $self->{ssh_info}, $sid, $storage_migrate_opts);
}
my $conffile = PVE::LXC::Config->config_file($vmid);
my $vollist = PVE::LXC::Config->get_vm_volumes($conf);
PVE::Storage::deactivate_volumes($self->{storecfg}, $vollist);
+ # transfer replication state before move config
+ $self->transfer_replication_state() if $rep_volumes;
+
# move config
die "Failed to move config to node '$self->{node}' - rename failed: $!\n"
if !rename($conffile, $newconffile);
$self->{conf_migrated} = 1;
+
+ $self->switch_replication_job_target() if $rep_volumes;
}
sub phase1_cleanup {
$self->log('info', "start final cleanup");
if (!$self->{conf_migrated}) {
- my $conf = $self->{vmconf};
- delete $conf->{lock};
-
- eval { PVE::LXC::Config->write_config($vmid, $conf); };
+ eval { PVE::LXC::Config->remove_lock($vmid, 'migrate'); };
if (my $err = $@) {
$self->log('err', $err);
}
+ # in restart mode, we start the container on the source node
+ # on migration error
+ if ($self->{opts}->{restart} && $self->{was_running}) {
+ $self->log('info', "start container on source node");
+ my $skiplock = 1;
+ PVE::LXC::vm_start($vmid, $self->{vmconf}, $skiplock);
+ }
} else {
my $cmd = [ @{$self->{rem_ssh}}, 'pct', 'unlock', $vmid ];
- $self->cmd_logerr($cmd, errmsg => "failed to clear migrate lock");
+ $self->cmd_logerr($cmd, errmsg => "failed to clear migrate lock");
+
+ # in restart mode, we start the container on the target node
+ # after migration
+ if ($self->{opts}->{restart} && $self->{was_running}) {
+ $self->log('info', "start container on target node");
+ my $cmd = [ @{$self->{rem_ssh}}, 'pct', 'start', $vmid];
+ $self->cmd($cmd);
+ }
}
- # in restart mode, we start the container on the target node
- # after migration
- if ($self->{opts}->{restart} && $self->{was_running}) {
- $self->log('info', "start container on target node");
- my $cmd = [ @{$self->{rem_ssh}}, 'pct', 'start', $vmid];
- $self->cmd($cmd);
- }
}
1;