We sometimes need to execute a script on our host when starting or stopping a VM.
I was using another solution not elegant that broke after a proxmox update.
And after researching the proxmox documentation a supported solution is available.
We first need to edit our /etc/pve/storage.cfg
adding the snippets directory to the host as below :
dir: local
path /var/lib/vz
content backup,vztmpl,iso,snippets
# Entry added manually for the ZFS local storage after the migration
zfspool: local-zfs
pool rpool/data
sparse
content images,rootdir
lvmthin: HV2-FW2
thinpool HV2-FW2
vgname HV2-FW2
content images,rootdir
nodes hv2
After refreshing our proxmox GUI the folder snippets will be created according to our /etc/pve/storage.cfg
according to the output below :
root@hv2:/var/lib/vz/snippets# ll /var/lib/vz/
total 26
drwxr-xr-x 2 root root 4 Aug 26 2020 dump
drwxr-xr-x 2 root root 2 Dec 3 2019 images
drwxr-xr-x 2 root root 3 Jul 1 13:35 snippets
drwxr-xr-x 5 root root 5 Jan 9 2020 template
Copy the example script to the snippets folder with the command below :
root@hv2:~# cp /usr/share/pve-docs/examples/guest-example-hookscript.pl /var/lib/vz/snippets/network.pl
We could write a custom perl script, but unfortunately, I am not familiar with perl and the example script is detailed enough to be used.
The documentation is not clear if a bash script is supported. I will eventually test and update the article if it works.
The script is executed in 4 stages of the VM life ( pre-start, post-start, pre-stop, post-stop ) and we are interested in the post-start stage since the script to be executed in the host will configure the VM network.
We will copy the example script to the recently created folder /var/lib/vz/snippets/network.pl
and change the post-start block to execute the desired bash script as seen below :
#!/usr/bin/perl
# Exmple hook script for PVE guests (hookscript config option)
# You can set this via pct/qm with
# pct set <vmid> -hookscript <volume-id>
# qm set <vmid> -hookscript <volume-id>
# where <volume-id> has to be an executable file in the snippets folder
# of any storage with directories e.g.:
# qm set 100 -hookscript local:snippets/hookscript.pl
use strict;
use warnings;
print "GUEST HOOK: " . join(' ', @ARGV). "\n";
# First argument is the vmid
my $vmid = shift;
# Second argument is the phase
my $phase = shift;
if ($phase eq 'pre-start') {
# First phase 'pre-start' will be executed before the guest
# ist started. Exiting with a code != 0 will abort the start
print "$vmid is starting.\n";
# print "preparations failed, aborting."
# exit(1);
} elsif ($phase eq 'post-start') {
# Second phase 'post-start' will be executed after the guest
# successfully started.
print "$vmid started, executing network script.\n";
# I believe that the output should be captured and tested
# to return the correct exit code.
system("/bin/bash /root/network/config/hv2_net_vps.sh $vmid")
} elsif ($phase eq 'pre-stop') {
# Third phase 'pre-stop' will be executed before stopping the guest
# via the API. Will not be executed if the guest is stopped from
# within e.g., with a 'poweroff'
print "$vmid will be stopped.\n";
} elsif ($phase eq 'post-stop') {
# Last phase 'post-stop' will be executed after the guest stopped.
# This should even be executed in case the guest crashes or stopped
# unexpectedly.
print "$vmid stopped. Doing cleanup.\n";
} else {
die "got unknown phase '$phase'\n";
}
exit(0);
I have added the line :
system("/bin/bash /root/network/config/hv2_net_vps.sh $vmid")
I am using the function system()
to invoke a bash script passing the VMID as an argument. You can adapt the example to your needs.
It worth mention that I could not see the pre-stop or post-stop be executed when the VM was shut down from within its OS. Although stated on the example that post-stop should be executed when the VM is stopped from the OS or crashed.
The last step is to execute the command below to activate the hookscript :
qm set 101 --hookscript local:snippets/network.pl
101
- is your VM_ID.
We now can see the script being executed when the VM starts.
