Using the pct commands implemented in the previous commit, this commit
adds running the migration-hooks during the container migration process.

I am redirecting STDERR from the pct mtunnel to /dev/null since it is
not captured by the current fork_ssh_tunnel function and can then
pollute the output of the migration task. The STDERR of the
migrate-hookscript is not affected, since it is captured by the remote
mtunnel command and gets transferred via the query-migrate-hook command.

Signed-off-by: Stefan Hanreich <s.hanre...@proxmox.com>
---
 src/PVE/LXC/Migrate.pm | 119 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/src/PVE/LXC/Migrate.pm b/src/PVE/LXC/Migrate.pm
index 2ef1cce..fdde180 100644
--- a/src/PVE/LXC/Migrate.pm
+++ b/src/PVE/LXC/Migrate.pm
@@ -89,6 +89,8 @@ sub prepare {
            if !$target_scfg->{content}->{rootdir};
     });
 
+    $self->migration_hook($vmid, 'pre');
+
     # todo: test if VM uses local resources
 
     # test ssh connection
@@ -384,6 +386,15 @@ sub phase3 {
     }
 }
 
+#  only called when phase1 was successful
+sub phase3_cleanup {
+    my ($self, $vmid, $err) = @_;
+
+    if (!$self->{errors}) {
+       $self->migration_hook($vmid, 'post');
+    }
+}
+
 sub final_cleanup {
     my ($self, $vmid) = @_;
 
@@ -413,7 +424,115 @@ sub final_cleanup {
            $self->cmd($cmd);
        }
     }
+}
+
+sub fork_tunnel {
+    my ($self, $ssh_forward_info) = @_;
+
+    my $cmd = ['/usr/sbin/pct', 'mtunnel', '2>', '/dev/null'];
+    my $log = sub {
+       my ($level, $msg) = @_;
+       $self->log($level, $msg);
+    };
+
+    return PVE::Tunnel::fork_ssh_tunnel($self->{rem_ssh}, $cmd, 
$ssh_forward_info, $log);
+}
+
+sub migration_hook {
+    my ($self, $vmid, $phase) = @_;
+
+    if (!$self->{vmconf}->{hookscript}) {
+       return;
+    }
+
+    my $stop_on_error = $phase eq 'pre';
+
+    PVE::GuestHelpers::exec_hookscript(
+       $self->{vmconf},
+       $vmid,
+       "$phase-migrate",
+       $stop_on_error,
+    );
+
+    my $tunnel;
+
+    eval {
+       $tunnel = $self->{tunnel} // $self->fork_tunnel();
+    };
+    if ($@ =~ /can't open tunnel/) {
+       $self->log('warn', 'Target node does not support mtunnel. Not running 
hookscript on target, but still continuing with migration.');
+       return;
+    } elsif ($@) {
+       die $@;
+    }
+
+    my $close_tunnel = sub {
+       if (!$self->{tunnel}) {
+           eval {
+               $self->log('info', "closing tunnel for migration hook");
+               PVE::Tunnel::finish_tunnel($tunnel);
+           };
+           if ($@) {
+               $self->log('warn', 'could not close tunnel to remote host');
+           }
+       }
+    };
+
+    my $result;
+
+    eval {
+       $self->log('info', "starting hook $phase-migrate on target");
+
+       $result = PVE::Tunnel::write_tunnel($tunnel, 30, "migrate-hook", {
+           vmid => $vmid,
+           phase => $phase,
+           source => PVE::INotify::nodename(),
+           target => $self->{node},
+       });
+    };
+    my $err = $@;
+
+    if ($err) {
+       $close_tunnel->();
+       die $err;
+    }
+
+    $self->log('info', "successfully started hook $phase-migrate on target");
+
+    my $running = 1;
+
+    while ($running) {
+       eval {
+           $result = PVE::Tunnel::write_tunnel($tunnel, 30, 
"query-migrate-hook");
+
+           if (!exists $result->{status}) {
+               die "Invalid response!";
+           } elsif ($result->{status} eq 'running') {
+               sleep(5);
+           } elsif ($result->{status} eq 'finished') {
+               $self->log('info', "$phase-migrate hook ran successfully on 
target:\n$result->{output}");
+           } elsif ($result->{status} eq 'error') {
+               my $msg = "An error occured during running the hookscript:\n" . 
$result->{output};
+
+               if ($stop_on_error) {
+                   die $msg;
+               } else {
+                   $self->log('warn', $msg)
+               }
+           } else {
+               die "Invalid response!";
+           }
+
+           $running = $result->{status} eq 'running';
+       };
+       if ($@) {
+           $err = $@;
+           last;
+       }
+    }
 
+    $close_tunnel->();
+    die $err if $err;
 }
 
 1;
-- 
2.30.2


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

Reply via email to