Ansible roles
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

111 lines
3.7 KiB

#!/usr/bin/perl -w
use strict;
use warnings;
use File::Basename;
use JSON;
use Logger::Syslog;
$SIG{CHLD} = 'IGNORE';
info( "GUEST HOOK: " . join( ' ', @ARGV ) );
my $vmid = shift;
my $phase = shift;
if ( not -l '/etc/pve/local' ) {
error( "Can't find /etc/pve/local link" );
die;
} elsif ( not defined $vmid or not defined $phase ) {
error( "Need to pass both vmid and phase arguments" );
die;
} elsif ( $vmid !~ m/^\d+$/ ) {
error( "vmid must be only numerical" );
die;
}
# We must identify the local node
my $local_node = basename( readlink( '/etc/pve/local' ) );
if ( $phase eq 'pre-start' ) {
info( "Runing pre-start hook for guest $vmid" );
} elsif ( $phase eq 'post-start' ) {
info( "Running post-start hook for guest $vmid" );
# A VM has just started. Let's check if it's already on the local node
# If it's an incoming live migration, it might still be running on another node
# All of this must run in the background because hooks are synchronous
my $pid = fork();
if ( $pid != 0 ) {
# main script can stop now, everything will run in a forked process
POSIX::_exit 0;
} elsif ( defined $pid ) {
# All those fh must be closed for the fork to be independant of its parent
close STDOUT;
close STDERR;
close STDIN;
POSIX::setsid();
my $i = 0;
my $guest_found = 0;
# We'll loop for up to 30min, which should be sufficient. If migration takes longer than that,
# something is probably wrong
LOOP: while ( $i lt 1800 ) {
# Here, we query the API for all the VM
my $resources = from_json( qx(pvesh get /cluster/resources --type=vm --output-format=json) );
# Then we loop through all the VM to find the one we're interested in
foreach my $vm ( @{$resources} ){
next if ( $vm->{id} !~ m{^(qemu|lxc)/$vmid$} );
# OK, we found the guest $vmid
info("Found guest $vmid, running on node " . $vm->{node});
$guest_found = 1;
# Is the guest running on local node ? If yes, it means migration is finished, and we
# can redirect IP failover and routing table
if ( $vm->{node} eq $local_node ) {
# pve-online use this env var to check if we must unplug/replug the WAN NIC
$ENV{PVE_GUEST_TYPE} = $1;
# And here we go !
qx(/bin/systemd-cat /usr/local/bin/pve-online --update-routes --update-gre --migrate-ipfo=$vmid);
# Update routing table of the other online nodes
my $nodes = from_json( qx(pvesh get /nodes --output-format=json) );
foreach my $node ( @{$nodes} ) {
if ( $node->{status} eq 'online' and $node->{node} ne $local_node ) {
info("Updating routing table of node $node->{node}");
qx(ssh -o ConnectTimeout=3 -l root $node->{node} /usr/local/bin/pve-online --update-routes);
}
}
# And we're done, stop looping
last LOOP;
# Guest is not running on the local node = migration is still running
# Wait a bit and start again
} else {
info( "Guest $vmid is still running on node " . $vm->{node} . " not yet on $local_node. Waiting a bit more for migration to finish" );
sleep 1;
next LOOP;
}
}
# We looped through all the guests and couldn't find the one we're looking for, nothing more we can do
if ( not $guest_found ) {
error( "No such guest with id $vmid" );
die;
}
}
}
} elsif ( $phase eq 'pre-stop' ) {
info( "Running pre-stop hook" );
} elsif ( $phase eq 'post-stop' ) {
info( "Running post-stop hook" );
# Just remove routes if needed
qx(/bin/systemd-cat /usr/local/bin/pve-online --update-routes)
} else {
error( "Unknown hook phase : $phase" );
die;
}