[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