add startall/stopall API and init script

This commit is contained in:
Dietmar Maurer 2012-04-20 08:21:37 +02:00
parent 4b72af232c
commit b92400b6a7
6 changed files with 285 additions and 1 deletions

View File

@ -2,7 +2,7 @@ package PVE::API2::Nodes::Nodeinfo;
use strict;
use warnings;
use POSIX;
use POSIX qw(LONG_MAX);
use Filesys::Df;
use Time::Local qw(timegm_nocheck);
use PVE::pvecfg;
@ -19,6 +19,7 @@ use PVE::AccessControl;
use PVE::Storage;
use PVE::OpenVZ;
use PVE::APLInfo;
use PVE::QemuServer;
use PVE::API2::Subscription;
use PVE::API2::Services;
use PVE::API2::Network;
@ -120,6 +121,8 @@ __PACKAGE__->register_method ({
{ name => 'ubcfailcnt' },
{ name => 'network' },
{ name => 'aplinfo' },
{ name => 'startall' },
{ name => 'stopall' },
];
return $result;
@ -848,6 +851,244 @@ __PACKAGE__->register_method({
return $rpcenv->fork_worker('download', undef, $user, $worker);
}});
my $get_start_stop_list = sub {
my ($nodename, $autostart) = @_;
my $cc = PVE::Cluster::cfs_read_file('cluster.conf');
my $vmlist = PVE::Cluster::get_vmlist();
my $resList = {};
foreach my $vmid (keys %{$vmlist->{ids}}) {
my $d = $vmlist->{ids}->{$vmid};
my $startup;
eval {
return if $d->{node} ne $nodename;
my $bootorder = LONG_MAX;
if ($d->{type} eq 'openvz') {
my $conf = PVE::OpenVZ::load_config($vmid);
return if $autostart && !($conf->{onboot} && $conf->{onboot}->{value});
if ($conf->{bootorder} && defined($conf->{bootorder}->{value})) {
$bootorder = $conf->{bootorder}->{value};
}
$startup = { order => $bootorder };
} elsif ($d->{type} eq 'qemu') {
my $conf = PVE::QemuServer::load_config($vmid);
return if $autostart && !$conf->{onboot};
if ($conf->{startup}) {
$startup = PVE::QemuServer::parse_startup($conf->{startup});
$startup->{order} = $bootorder if !defined($startup->{order});
} else {
$startup = { order => $bootorder };
}
} else {
die "unknown VM type '$d->{type}'\n";
}
# skip ha managed VMs (started by rgmanager)
return if PVE::Cluster::cluster_conf_lookup_pvevm($cc, 0, $vmid, 1);
$resList->{$startup->{order}}->{$vmid} = $startup;
$resList->{$startup->{order}}->{$vmid}->{type} = $d->{type};
};
warn $@ if $@;
}
return $resList;
};
__PACKAGE__->register_method ({
name => 'startall',
path => 'startall',
method => 'POST',
protected => 1,
description => "Start all VMs and containers (when onboot=1).",
parameters => {
additionalProperties => 0,
properties => {
node => get_standard_option('pve-node'),
},
},
returns => {
type => 'string',
},
code => sub {
my ($param) = @_;
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
my $nodename = $param->{node};
$nodename = PVE::INotify::nodename() if $nodename eq 'localhost';
my $code = sub {
$rpcenv->{type} = 'priv'; # to start tasks in background
# wait up to 10 seconds for quorum
for (my $i = 10; $i >= 0; $i--) {
last if PVE::Cluster::check_cfs_quorum($i != 0 ? 1 : 0);
sleep(1);
}
my $startList = &$get_start_stop_list($nodename, 1);
foreach my $order (sort keys %$startList) {
my $vmlist = $startList->{$order};
foreach my $vmid (sort keys %$vmlist) {
my $d = $vmlist->{$vmid};
PVE::Cluster::check_cfs_quorum(); # abort when we loose quorum
eval {
my $default_delay = 0;
my $upid;
if ($d->{type} eq 'openvz') {
return if PVE::OpenVZ::check_running($vmid);
print STDERR "Starting CT $vmid\n";
$upid = PVE::API2::OpenVZ->vm_start({node => $nodename, vmid => $vmid });
} elsif ($d->{type} eq 'qemu') {
$default_delay = 3; # to redruce load
return if PVE::QemuServer::check_running($vmid, 1);
print STDERR "Starting VM $vmid\n";
$upid = PVE::API2::Qemu->vm_start({node => $nodename, vmid => $vmid });
} else {
die "unknown VM type '$d->{type}'\n";
}
my $res = PVE::Tools::upid_decode($upid);
while (PVE::ProcFSTools::check_process_running($res->{pid})) {
sleep(1);
}
my $status = PVE::Tools::upid_read_status($upid);
if ($status eq 'OK') {
# use default delay to reduce load
my $delay = defined($d->{up}) ? int($d->{up}) : $default_delay;
if ($delay > 0) {
print STDERR "Waiting for $delay seconds (startup delay)\n" if $d->{up};
for (my $i = 0; $i < $delay; $i++) {
sleep(1);
}
}
} else {
if ($d->{type} eq 'openvz') {
print STDERR "Starting CT $vmid failed: $status\n";
} elsif ($d->{type} eq 'qemu') {
print STDERR "Starting VM $vmid failed: status\n";
}
}
};
warn $@ if $@;
}
}
return;
};
return $rpcenv->fork_worker('startall', undef, $authuser, $code);
}});
my $create_stop_worker = sub {
my ($nodename, $type, $vmid, $down_timeout) = @_;
my $upid;
if ($type eq 'openvz') {
return if !PVE::OpenVZ::check_running($vmid);
my $timeout = defined($down_timeout) ? int($down_timeout) : 60;
print STDERR "Stoping CT $vmid (timeout = $timeout seconds)\n";
$upid = PVE::API2::OpenVZ->vm_shutdown({node => $nodename, vmid => $vmid,
timeout => $timeout, forceStop => 1 });
} elsif ($type eq 'qemu') {
return if !PVE::QemuServer::check_running($vmid, 1);
my $timeout = defined($down_timeout) ? int($down_timeout) : 60*3;
print STDERR "Stoping VM $vmid (timeout = $timeout seconds)\n";
$upid = PVE::API2::Qemu->vm_shutdown({node => $nodename, vmid => $vmid,
timeout => $timeout, forceStop => 1 });
} else {
die "unknown VM type '$type'\n";
}
my $res = PVE::Tools::upid_decode($upid);
return $res->{pid};
};
__PACKAGE__->register_method ({
name => 'stopall',
path => 'stopall',
method => 'POST',
protected => 1,
description => "Stop all VMs and Containers.",
parameters => {
additionalProperties => 0,
properties => {
node => get_standard_option('pve-node'),
},
},
returns => {
type => 'string',
},
code => sub {
my ($param) = @_;
my $rpcenv = PVE::RPCEnvironment::get();
my $authuser = $rpcenv->get_user();
my $nodename = $param->{node};
$nodename = PVE::INotify::nodename() if $nodename eq 'localhost';
my $code = sub {
$rpcenv->{type} = 'priv'; # to start tasks in background
my $stopList = &$get_start_stop_list($nodename);
my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
my $maxWorkers = $cpuinfo->{cpus};
foreach my $order (sort {$b <=> $a} keys %$stopList) {
my $vmlist = $stopList->{$order};
my $workers = {};
foreach my $vmid (sort {$b <=> $a} keys %$vmlist) {
my $d = $vmlist->{$vmid};
my $pid;
eval { $pid = &$create_stop_worker($nodename, $d->{type}, $vmid, $d->{down}); };
warn $@ if $@;
next if !$pid;
$workers->{$pid} = 1;
while (scalar(keys %$workers) >= $maxWorkers) {
foreach my $p (keys %$workers) {
if (!PVE::ProcFSTools::check_process_running($p)) {
delete $workers->{$p};
}
}
sleep(1);
}
}
while (scalar(keys %$workers)) {
foreach my $p (keys %$workers) {
if (!PVE::ProcFSTools::check_process_running($p)) {
delete $workers->{$p};
}
}
sleep(1);
}
}
return;
};
return $rpcenv->fork_worker('stopall', undef, $authuser, $code);
}});
package PVE::API2::Nodes;
use strict;

View File

@ -3,6 +3,7 @@ include ../../defines.mk
all:
SCRIPTS = \
pve-manager \
pvedaemon \
pvebanner \
pvestatd \

39
bin/init.d/pve-manager Executable file
View File

@ -0,0 +1,39 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: pve-manager
# Required-Start: $remote_fs apache2 qemu-server vz pvestatd
# Required-Stop: $remote_fs apache2 qemu-server vz pvestatd
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: PVE VM Manager
### END INIT INFO
. /lib/lsb/init-functions
PATH=/sbin:/bin:/usr/bin:/usr/sbin
DESC="PVE Status Daemon"
PVESH=/usr/bin/pvesh
test -f $PVESH || exit 0
case "$1" in
start)
echo "Starting VMs and Containers"
pvesh --nooutput create /nodes/localhost/startall
;;
stop)
echo "Stopping VMs and Containers"
pvesh --nooutput create /nodes/localhost/stopall
;;
reload|restart|force-reload)
# do nothing here
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|reload|restart|force-reload}" >&2
exit 1
;;
esac
exit 0

1
debian/conffiles vendored
View File

@ -1,3 +1,4 @@
/etc/init.d/pve-manager
/etc/init.d/pvedaemon
/etc/init.d/pvebanner
/etc/init.d/pvenetcommit

1
debian/postinst vendored
View File

@ -59,6 +59,7 @@ case "$1" in
update-rc.d pvestatd defaults 21 79 >/dev/null
update-rc.d pvebanner start 99 2 3 4 5 . >/dev/null
update-rc.d pvenetcommit start 15 S . >/dev/null
update-rc.d pve-manager defaults 25 75 >/dev/null
test -e /proxmox_install_mode || invoke-rc.d pvedaemon restart
test -e /proxmox_install_mode || invoke-rc.d pvestatd restart

1
debian/postrm vendored
View File

@ -8,6 +8,7 @@ if [ "$1" = purge ]; then
update-rc.d pvestatd remove >/dev/null 2>&1
update-rc.d pvebanner remove >/dev/null 2>&1
update-rc.d pvenetcommit remove >/dev/null 2>&1
update-rc.d pve-manager remove >/dev/null 2>&1
if [ -e /usr/share/debconf/confmodule ]; then
. /usr/share/debconf/confmodule