public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Stefan Hanreich <s.hanreich@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v2 qemu-server 1/2] add migrate-hook and query-migrate-hook commands to CLI
Date: Thu,  6 Oct 2022 14:44:46 +0200	[thread overview]
Message-ID: <20221006124447.120701-8-s.hanreich@proxmox.com> (raw)
In-Reply-To: <20221006124447.120701-1-s.hanreich@proxmox.com>

migrate-hook runs the migrate hook by forking a new process and
attaching to its STDOUT. This helps us deal with long running
hookscripts, that could otherwise block. Additionally it safeguards us
from hookscripts doing weird stuff with output.

query-migrate-hook can be used to query the current state of the running
hookscript. After the migrate-hook has finished it also transfers the
output back to the source node. When an error occurs, the
query-migrate-hook command informs the caller and returns the respective
output as well.

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
 PVE/CLI/qm.pm | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)

diff --git a/PVE/CLI/qm.pm b/PVE/CLI/qm.pm
index ca5d25f..5ac091b 100755
--- a/PVE/CLI/qm.pm
+++ b/PVE/CLI/qm.pm
@@ -306,6 +306,8 @@ __PACKAGE__->register_method ({
 	$tunnel_write->("tunnel online");
 	$tunnel_write->("ver 1");
 
+	my $state = {};
+
 	while (my $line = <STDIN>) {
 	    chomp $line;
 	    if ($line =~ /^quit$/) {
@@ -323,6 +325,113 @@ __PACKAGE__->register_method ({
 		} else {
 		    $tunnel_write->("ERR: resume failed - VM $vmid not running");
 		}
+	    } elsif ($line =~ /^migrate-hook (\d+) (pre|post) ([\S]+) ([\S]+)$/) {
+		if ($state->{migrate_hook}) {
+		    $tunnel_write->("ERR: migrate-hook is already running!");
+		    next;
+		}
+
+		my $vmid = $1;
+		my $phase = $2;
+		my $source = $3;
+		my $target = $4;
+
+		if (!PVE::JSONSchema::pve_verify_node_name($source, 1)) {
+		    $tunnel_write->("ERR: Invalid name for source node");
+		    next;
+		}
+
+		if (!PVE::JSONSchema::pve_verify_node_name($target, 1)) {
+		    $tunnel_write->("ERR: Invalid name for target node");
+		    next;
+		}
+
+		my $config_node = ($phase eq 'pre')
+		    ? $source
+		    : $target;
+
+		eval {
+		    my $conf = PVE::QemuConfig->load_config($vmid, $config_node);
+
+		    pipe(my $reader, my $writer);
+
+		    my $pid = fork();
+		    die "Could not fork new process!" if !defined $pid;
+
+		    if ($pid == 0) {
+			# child
+			close $reader;
+
+			$ENV{PVE_MIGRATED_FROM} = $source;
+
+			eval {
+			    PVE::GuestHelpers::exec_hookscript(
+				$conf,
+				$vmid,
+				"$phase-migrate",
+				1,
+				{
+				    output  => ">&" . fileno($writer),
+				    errfunc => sub {
+					my $error_line = shift;
+					print $writer "STDERR: " . $error_line;
+				    },
+				}
+			    );
+			};
+			my $err = $@;
+
+			close $writer;
+
+			if ($err) {
+			    POSIX::_exit(1);
+			}
+
+			POSIX::_exit(0);
+		    }
+
+		    close $writer;
+
+		    $state->{migrate_hook} = {
+			output => $reader,
+			pid    => $pid,
+		    };
+		};
+		if ($@) {
+		    chomp $@;
+		    $tunnel_write->("ERR: $phase-migrate hook failed - $@");
+		} else {
+		    $tunnel_write->("OK");
+		}
+	    } elsif ($line =~ /^query-migrate-hook$/) {
+		if (!$state->{migrate_hook}) {
+		    $tunnel_write->("ERR: No migration hook running!");
+		    next;
+		}
+
+		if (!waitpid($state->{migrate_hook}->{pid}, POSIX::WNOHANG)) {
+		    $tunnel_write->("OK");
+		    $tunnel_write->("running");
+		    next;
+		}
+
+		my $reader = $state->{migrate_hook}->{output};
+		my $output = "";
+
+		while (my $line = <$reader>) {
+		    $output .= $line;
+		}
+
+		close $state->{migrate_hook}->{output};
+		delete $state->{migrate_hook};
+
+		my $status = ($? == 0)
+		    ? 'finished'
+		    : 'error';
+
+		$tunnel_write->("OK");
+		$tunnel_write->("$status");
+		$tunnel_write->(MIME::Base64::encode($output, ''));
 	    }
 	}
 
-- 
2.30.2




  parent reply	other threads:[~2022-10-06 12:45 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-06 12:44 [pve-devel] [PATCH v2 pve-container/qemu-server/pve-docs/pve-guest-common 0/8] Add pre/post-migrate hooks Stefan Hanreich
2022-10-06 12:44 ` [pve-devel] [PATCH v2 pve-guest-common 1/1] Add run_params to exec_hookscript function Stefan Hanreich
2022-10-06 12:44 ` [pve-devel] [PATCH v2 pve-container 1/2] add pct mtunnel command to the CLI Stefan Hanreich
2022-10-06 12:44 ` [pve-devel] [PATCH v2 pve-container 2/2] add migration hooks to container migration process Stefan Hanreich
2022-10-06 12:44 ` [pve-devel] [PATCH v2 pve-docs 1/3] Add pre/post-migrate events to hookscript example Stefan Hanreich
2022-10-06 12:44 ` [pve-devel] [PATCH v2 pve-docs 2/3] Add hookscript section to container documentation Stefan Hanreich
2022-10-06 12:44 ` [pve-devel] [PATCH v2 pve-docs 3/3] Add pre/post-migrate section to VM hookscript documentation Stefan Hanreich
2022-10-06 12:44 ` Stefan Hanreich [this message]
2022-10-06 12:44 ` [pve-devel] [PATCH v2 qemu-server 2/2] add migration hooks to VM migration process Stefan Hanreich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221006124447.120701-8-s.hanreich@proxmox.com \
    --to=s.hanreich@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal