How to run VM hooks asynchronously

danielb

Renowned Member
Jun 1, 2018
231
64
68
38
Bordeaux (france)
For my need (see https://forum.proxmox.com/threads/running-hooks-when-incoming-migration-is-finished.54330 for some background), I need to run a hook script when a VM ends an incoming live migration. I'm trying to use the post-start hook. The idea : in the post-start hook, loop to see if the VM is running on the local node. If not, the migration is still running, if yes, it has finished the live migration and I can proceed with my custom script.

The problem is that hooks are blocking. Even post-start. As long as post-start has not returned, the migration won't proceed, as PVE consideres the VM is still starting. I tried to fork in my hook script, or to use a shell wrapper, calling the real one with &. But in both case it's the same. PVE dosn't start migration and juste blocks in the post-start hook. Not sure why, are hooks executed in a special cgroup which ensure even forks are ended ?

How can I fire a hook asynchronously ? I'd prefer not having to write a separate daemon which could receive signals from the hook script and do the async part
 
Hi,
You can do this with a fork of a new process.
 
This is where I'm lost. My hook is a perl script, and running in a simple fork() still blocks the hookThis is where it's getting strange. In my hook, I have something like this :


Code:
$SIG{CHLD} = 'IGNORE';

if ($phase eq 'post-start') {
  my $pid = fork();
  if ($pid) {
    print "Will run pre-start routine in the background\n";
  } elsif ( defined $pid ) {
    # Long running part which should be in the background
  }
}
Running this from the CLI, the script correctly detach itself. But when called but Proxmox as a hook, it's still blocking (in my case, it blocks the "Starting VM" part, and so the migration does not start. I'm probably doing it wrong, but I don't understand why it works from the CLI and not as a hook
 
Code:
#!/usr/bin/perl
use strict;
use warnings;
my $pid = fork();
if ($pid != 0) {
    exit;
} else {
    print "$$\n";
    sleep(1000);
    print "Done\n";
}
 
Code:
my $pid = fork();
if ($pid != 0) {
    POSIX::_exit 0;
} else {
close STDOUT;
close STDERR;
close STDIN;
POSIX::setsid();
#Do your things like 
sleep(100);
}