mirror of
https://git.proxmox.com/git/pve-manager
synced 2025-08-07 14:15:18 +00:00
add startall/stopall API and init script
This commit is contained in:
parent
4b72af232c
commit
b92400b6a7
@ -2,7 +2,7 @@ package PVE::API2::Nodes::Nodeinfo;
|
|||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use POSIX;
|
use POSIX qw(LONG_MAX);
|
||||||
use Filesys::Df;
|
use Filesys::Df;
|
||||||
use Time::Local qw(timegm_nocheck);
|
use Time::Local qw(timegm_nocheck);
|
||||||
use PVE::pvecfg;
|
use PVE::pvecfg;
|
||||||
@ -19,6 +19,7 @@ use PVE::AccessControl;
|
|||||||
use PVE::Storage;
|
use PVE::Storage;
|
||||||
use PVE::OpenVZ;
|
use PVE::OpenVZ;
|
||||||
use PVE::APLInfo;
|
use PVE::APLInfo;
|
||||||
|
use PVE::QemuServer;
|
||||||
use PVE::API2::Subscription;
|
use PVE::API2::Subscription;
|
||||||
use PVE::API2::Services;
|
use PVE::API2::Services;
|
||||||
use PVE::API2::Network;
|
use PVE::API2::Network;
|
||||||
@ -120,6 +121,8 @@ __PACKAGE__->register_method ({
|
|||||||
{ name => 'ubcfailcnt' },
|
{ name => 'ubcfailcnt' },
|
||||||
{ name => 'network' },
|
{ name => 'network' },
|
||||||
{ name => 'aplinfo' },
|
{ name => 'aplinfo' },
|
||||||
|
{ name => 'startall' },
|
||||||
|
{ name => 'stopall' },
|
||||||
];
|
];
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
@ -848,6 +851,244 @@ __PACKAGE__->register_method({
|
|||||||
return $rpcenv->fork_worker('download', undef, $user, $worker);
|
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;
|
package PVE::API2::Nodes;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
@ -3,6 +3,7 @@ include ../../defines.mk
|
|||||||
all:
|
all:
|
||||||
|
|
||||||
SCRIPTS = \
|
SCRIPTS = \
|
||||||
|
pve-manager \
|
||||||
pvedaemon \
|
pvedaemon \
|
||||||
pvebanner \
|
pvebanner \
|
||||||
pvestatd \
|
pvestatd \
|
||||||
|
39
bin/init.d/pve-manager
Executable file
39
bin/init.d/pve-manager
Executable 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
1
debian/conffiles
vendored
@ -1,3 +1,4 @@
|
|||||||
|
/etc/init.d/pve-manager
|
||||||
/etc/init.d/pvedaemon
|
/etc/init.d/pvedaemon
|
||||||
/etc/init.d/pvebanner
|
/etc/init.d/pvebanner
|
||||||
/etc/init.d/pvenetcommit
|
/etc/init.d/pvenetcommit
|
||||||
|
1
debian/postinst
vendored
1
debian/postinst
vendored
@ -59,6 +59,7 @@ case "$1" in
|
|||||||
update-rc.d pvestatd defaults 21 79 >/dev/null
|
update-rc.d pvestatd defaults 21 79 >/dev/null
|
||||||
update-rc.d pvebanner start 99 2 3 4 5 . >/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 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 pvedaemon restart
|
||||||
test -e /proxmox_install_mode || invoke-rc.d pvestatd restart
|
test -e /proxmox_install_mode || invoke-rc.d pvestatd restart
|
||||||
|
1
debian/postrm
vendored
1
debian/postrm
vendored
@ -8,6 +8,7 @@ if [ "$1" = purge ]; then
|
|||||||
update-rc.d pvestatd remove >/dev/null 2>&1
|
update-rc.d pvestatd remove >/dev/null 2>&1
|
||||||
update-rc.d pvebanner 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 pvenetcommit remove >/dev/null 2>&1
|
||||||
|
update-rc.d pve-manager remove >/dev/null 2>&1
|
||||||
|
|
||||||
if [ -e /usr/share/debconf/confmodule ]; then
|
if [ -e /usr/share/debconf/confmodule ]; then
|
||||||
. /usr/share/debconf/confmodule
|
. /usr/share/debconf/confmodule
|
||||||
|
Loading…
Reference in New Issue
Block a user