]> git.proxmox.com Git - pve-container.git/blobdiff - src/PVE/LXC/Migrate.pm
adapt to new storage_migrate activation behavior
[pve-container.git] / src / PVE / LXC / Migrate.pm
index e78ea897c8e19731edc37670ae25d223404f9bd7..94a78c57952c18a85ed32393dc8af783aab6d555 100644 (file)
@@ -9,7 +9,11 @@ use PVE::Tools;
 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);
 
@@ -41,9 +45,8 @@ sub prepare {
     $self->{was_running} = $running;
 
     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};
@@ -76,9 +79,6 @@ sub prepare {
            warn "Used shared storage '$storage' is not online on source node!\n"
                if !$plugin->check_connection($storage, $scfg);
        } else {
-           # only activate if not shared
-           push @$need_activate, $volid;
-
            # unless in restart mode because we shut the container down
            die "unable to migrate local mount point '$volid' while CT is running"
                if $running && !$restart;
@@ -86,8 +86,6 @@ sub prepare {
 
     });
 
-    PVE::Storage::activate_volumes($self->{storecfg}, $need_activate);
-
     # todo: test if VM uses local resources
 
     # test ssh connection
@@ -101,12 +99,7 @@ sub prepare {
 
        $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;
     }
@@ -156,7 +149,8 @@ sub phase1 {
            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);
 
@@ -209,7 +203,7 @@ sub phase1 {
        PVE::Storage::foreach_volid($dl, sub {
            my ($volid, $sid, $volname) = @_;
 
-           $volhash->{$volid} = 'storage';
+           $volhash->{$volid}->{ref} = 'storage';
        });
     }
 
@@ -217,11 +211,11 @@ sub phase1 {
     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
@@ -245,11 +239,12 @@ sub phase1 {
     }
 
     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");
@@ -264,11 +259,41 @@ sub phase1 {
        die "can't migrate CT - check log\n";
     }
 
-    my $insecure = $self->{opts}->{migration_type} eq 'insecure';
+    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, undef, undef, undef, undef, $insecure);
+       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 = {
+           'ratelimit_bps' => $bwlimit,
+           'insecure' => $opts->{migration_type} eq 'insecure',
+           'with_snapshots' => $volhash->{$volid}->{snapshots},
+       };
+
+       my $logfunc = sub { $self->log('info', $_[0]); };
+       eval {
+           PVE::Storage::storage_migrate($self->{storecfg}, $volid, $self->{ssh_info},
+                                         $sid, $storage_migrate_opts, $logfunc);
+       };
+       if (my $err = $@) {
+           die "storage migration for '$volid' to storage '$sid' failed - $err\n";
+       }
     }
 
     my $conffile = PVE::LXC::Config->config_file($vmid);
@@ -288,11 +313,16 @@ sub phase1 {
     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 {
@@ -330,25 +360,30 @@ sub final_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;