This calls the newly added commands in the previous commit to run the
migrate-hooks during the migration process. When a tunnel already
exists, the tunnel gets reused otherwise it creates a new ad-hoc tunnel
that is used for running the migration-hook.

Additionally I added some mock methods to the QemuMigrateMock class, so
the test class supports the newly added commands as well.

Signed-off-by: Stefan Hanreich <s.hanre...@proxmox.com>
---
 PVE/QemuMigrate.pm                    | 108 ++++++++++++++++++++++++++
 test/MigrationTest/QemuMigrateMock.pm |  11 ++-
 2 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm
index d52dc8d..42cf7d0 100644
--- a/PVE/QemuMigrate.pm
+++ b/PVE/QemuMigrate.pm
@@ -203,6 +203,8 @@ sub prepare {
     eval { $self->cmd_quiet($cmd); };
     die "Can't connect to destination address using public key\n" if $@;
 
+    $self->migration_hook($vmid, 'pre');
+
     return $running;
 }
 
@@ -1216,6 +1218,10 @@ sub phase3_cleanup {
        }
     }
 
+    if (!$self->{errors}) {
+       $self->migration_hook($vmid, 'post');
+    }
+
     # close tunnel on successful migration, on error phase2_cleanup closed it
     if ($tunnel) {
        eval { PVE::Tunnel::finish_tunnel($tunnel); };
@@ -1284,4 +1290,106 @@ sub round_powerof2 {
     return 2 << int(log($_[0]-1)/log(2));
 }
 
+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();
+    };
+    die $@ if $@;
+
+    my $close_tunnel = sub {
+       if (!$self->{tunnel}) {
+           $self->log('info', "closing tunnel for migration hook");
+           PVE::Tunnel::finish_tunnel($tunnel);
+       }
+    };
+
+    my $source = PVE::INotify::nodename();
+    my $target = $self->{node};
+
+    eval {
+       $self->log('info', "running hook $phase-migrate on target");
+       PVE::Tunnel::write_tunnel($tunnel, 30, "migrate-hook $vmid $phase 
$source $target");
+    };
+    my $err = $@;
+
+    if ($err =~ /no reply to command/) {
+       eval {
+           $close_tunnel->();
+       };
+       if ($@) {
+           die $err;
+       } else {
+           $self->log('warn', 'Got timeout when trying to run migrate-hook. 
Target doesn\'t support migrate hooks (old version?). Still continuing with 
migration.');
+           return;
+       }
+    } elsif ($err) {
+       $close_tunnel->();
+       die $err;
+    }
+
+    $self->log('info', "successfully started hook $phase-migrate on target");
+
+    my $running = 1;
+
+    while ($running) {
+       eval {
+           PVE::Tunnel::write_tunnel($tunnel, 30, "query-migrate-hook");
+           my $status = PVE::Tunnel::read_tunnel($tunnel, 30);
+
+           if ($status eq 'running') {
+               sleep(5);
+           } elsif ($status eq 'finished') {
+               my $output = MIME::Base64::decode(
+                   PVE::Tunnel::read_tunnel($tunnel, 30)
+               );
+
+               $self->log('info', "$phase-migrate hook ran successfully on 
target:\n" . $output);
+           } elsif ($status eq 'error') {
+               my $output = MIME::Base64::decode(
+                   PVE::Tunnel::read_tunnel($tunnel, 30)
+               );
+
+               my $msg = "An error occured during running the hookscript:\n" . 
$output;
+
+               if ($stop_on_error) {
+                   die $msg;
+               } else {
+                   $self->log('warn', $msg)
+               }
+           } else {
+               die "Invalid response!"
+           }
+
+           $running = $status eq 'running';
+       };
+       if ($@) {
+           $err = $@;
+           last;
+       }
+    }
+
+    eval {
+       $close_tunnel->();
+    };
+    die $err if $err; # use the initial error if it exists
+    die $@ if $@;
+}
+
 1;
diff --git a/test/MigrationTest/QemuMigrateMock.pm 
b/test/MigrationTest/QemuMigrateMock.pm
index f2c0281..e33a284 100644
--- a/test/MigrationTest/QemuMigrateMock.pm
+++ b/test/MigrationTest/QemuMigrateMock.pm
@@ -64,6 +64,8 @@ $tunnel_module->mock(
            my $vmid = $1;
            die "resuming wrong VM '$vmid'\n" if $vmid ne $test_vmid;
            return;
+       } elsif ($command =~ /^migrate-hook.*/) {
+           return;
        }
        die "write_tunnel (mocked) - implement me: $command\n";
     },
@@ -72,7 +74,12 @@ $tunnel_module->mock(
 my $qemu_migrate_module = Test::MockModule->new("PVE::QemuMigrate");
 $qemu_migrate_module->mock(
     fork_tunnel => sub {
-       die "fork_tunnel (mocked) - implement me\n"; # currently no call should 
lead here
+       return {
+           writer => "mocked",
+           reader => "mocked",
+           pid => 123456,
+           version => 1,
+       };
     },
     read_tunnel => sub {
        die "read_tunnel (mocked) - implement me\n"; # currently no call should 
lead here
@@ -298,6 +305,8 @@ $MigrationTest::Shared::tools_module->mock(
                        return 0;
                    } elsif ($cmd eq 'stop') {
                        return 0;
+                   } elsif ($cmd eq 'mtunnel') {
+                       return 0;
                    }
                    die "run_command (mocked) ssh qm command - implement me: 
${cmd_msg}";
                } elsif ($cmd eq 'pvesm') {
-- 
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