add pre- start/stop hookscripts to VMs

this adds a new config option for it, and executes it on four
points in time:

'pre-start'
'post-start'
'pre-stop'
'post-stop'

on pre-start we abort if the script fails
and pre-stop will not be called if the vm crashes or if
the vm gets powered off from inside the guest

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2019-01-31 14:33:39 +01:00 committed by Thomas Lamprecht
parent 5442d14e6d
commit 9e784b1154
3 changed files with 17 additions and 0 deletions

View File

@ -1117,6 +1117,9 @@ my $update_vm_api = sub {
if ($param->{$opt} eq '1') { if ($param->{$opt} eq '1') {
$param->{$opt} = PVE::QemuServer::generate_uuid(); $param->{$opt} = PVE::QemuServer::generate_uuid();
} }
} elsif ($opt eq 'hookscript') {
eval { PVE::GuestHelpers::check_hookscript($param->{$opt}, $storecfg); };
raise_param_exc({ $opt => $@ }) if $@;
} }
} }

View File

@ -19,6 +19,7 @@ use PVE::INotify;
use PVE::RPCEnvironment; use PVE::RPCEnvironment;
use PVE::Exception qw(raise_param_exc); use PVE::Exception qw(raise_param_exc);
use PVE::Network; use PVE::Network;
use PVE::GuestHelpers;
use PVE::QemuServer; use PVE::QemuServer;
use PVE::QemuServer::ImportDisk; use PVE::QemuServer::ImportDisk;
use PVE::QemuServer::OVF; use PVE::QemuServer::OVF;
@ -786,6 +787,7 @@ __PACKAGE__->register_method({
# vm was shutdown from inside the guest or crashed, doing api cleanup # vm was shutdown from inside the guest or crashed, doing api cleanup
PVE::QemuServer::vm_stop_cleanup($storecfg, $vmid, $conf, 0, 0); PVE::QemuServer::vm_stop_cleanup($storecfg, $vmid, $conf, 0, 0);
} }
PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-stop');
}); });
warn "Finished cleanup for $vmid\n"; warn "Finished cleanup for $vmid\n";

View File

@ -30,6 +30,7 @@ use PVE::ProcFSTools;
use PVE::QemuConfig; use PVE::QemuConfig;
use PVE::QMPClient; use PVE::QMPClient;
use PVE::RPCEnvironment; use PVE::RPCEnvironment;
use PVE::GuestHelpers;
use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr); use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr);
use PVE::QemuServer::Memory; use PVE::QemuServer::Memory;
use PVE::QemuServer::USB qw(parse_usb_device); use PVE::QemuServer::USB qw(parse_usb_device);
@ -614,6 +615,12 @@ EODESCR
default => "1 (autogenerated)", default => "1 (autogenerated)",
optional => 1, optional => 1,
}, },
hookscript => {
type => 'string',
format => 'pve-volume-id',
optional => 1,
description => "Script that will be executed during various steps in the vms lifetime.",
},
}; };
my $confdesc_cloudinit = { my $confdesc_cloudinit = {
@ -4596,6 +4603,7 @@ my $fast_plug_option = {
'description' => 1, 'description' => 1,
'protection' => 1, 'protection' => 1,
'vmstatestorage' => 1, 'vmstatestorage' => 1,
'hookscript' => 1,
}; };
# hotplug changes in [PENDING] # hotplug changes in [PENDING]
@ -5114,6 +5122,8 @@ sub vm_start {
} }
} }
PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 1);
my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine); my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
my $migrate_port = 0; my $migrate_port = 0;
@ -5311,6 +5321,7 @@ sub vm_start {
property => "guest-stats-polling-interval", property => "guest-stats-polling-interval",
value => 2) if (!defined($conf->{balloon}) || $conf->{balloon}); value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start');
}); });
} }
@ -5483,6 +5494,7 @@ sub vm_stop {
my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup}); my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup});
$timeout = $opts->{down} if $opts->{down}; $timeout = $opts->{down} if $opts->{down};
} }
PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-stop');
} }
$timeout = 60 if !defined($timeout); $timeout = 60 if !defined($timeout);