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