[pve-devel] [PATCH v2 pve-container 2/2] add migration hooks to container migration process
Stefan Hanreich
s.hanreich at proxmox.com
Thu Oct 6 14:44:42 CEST 2022
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.hanreich at 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
More information about the pve-devel
mailing list