6f0bc0d86f
* Updated Jobs->update_progress to take 'picked_up_by' as an optional parameter, defaulting to '$$' (the caller's PID). * Created System->get_uptime() to return the current uptime in seconds. * Added a delay to anvil-manage-power to not proceed with a reboot if the uptime is less than 600 seconds. This way, if any future bug causes an infinite reboot, there will be more time to determine what's wrong and debug the system between reboots. Signed-off-by: Digimer <digimer@alteeve.ca>
258 lines
8.8 KiB
Perl
Executable File
258 lines
8.8 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
#
|
|
# This manages power on the host. It can set that a reboot is or is no longer required. It can also reboot or
|
|
# power off the machine.
|
|
#
|
|
# Examples;
|
|
# - Mark that a reboot is required - anvil-manage-power --reboot-needed 1
|
|
# - Clear that a reboot is needed - anvil-manage-power --reboot-needed 0
|
|
# - Report whether a reboot is needed or not - anvil-manage-power
|
|
# - Reboot the system - anvil-manage-power --reboot [-y]
|
|
# - Power the system off - anvil-manage-power --poweroff [-y]
|
|
#
|
|
# Exit codes;
|
|
# 0 = Normal exit.
|
|
# 1 = No database connections available.
|
|
#
|
|
# TODO: Don't reboot or power off until all external users are done with the database on this system (if
|
|
# applicable)
|
|
#
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Anvil::Tools;
|
|
|
|
# Disable buffering
|
|
$| = 1;
|
|
|
|
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
|
|
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
|
|
if (($running_directory =~ /^\./) && ($ENV{PWD}))
|
|
{
|
|
$running_directory =~ s/^\./$ENV{PWD}/;
|
|
}
|
|
|
|
my $anvil = Anvil::Tools->new({log_level => 2, log_secure => 1});
|
|
|
|
$anvil->Storage->read_config({file => $anvil->data->{path}{configs}{'anvil.conf'}});
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
|
|
|
|
# Read switches
|
|
$anvil->data->{switches}{'poweroff'} = "";
|
|
$anvil->data->{switches}{'power-off'} = "";
|
|
$anvil->data->{switches}{'reboot'} = "";
|
|
$anvil->data->{switches}{'y'} = "";
|
|
$anvil->data->{switches}{'yes'} = "";
|
|
$anvil->data->{switches}{'reboot-needed'} = "";
|
|
$anvil->data->{switches}{'job-uuid'} = "";
|
|
$anvil->data->{switches}{'no-delay'} = "";
|
|
$anvil->Get->switches;
|
|
|
|
if ($anvil->data->{switches}{'power-off'})
|
|
{
|
|
$anvil->data->{switches}{'poweroff'} = 1;
|
|
}
|
|
if ($anvil->data->{switches}{'yes'})
|
|
{
|
|
$anvil->data->{switches}{'y'} = 1;
|
|
}
|
|
|
|
# Connect to DBs.
|
|
$anvil->Database->connect;
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
|
|
if (not $anvil->data->{sys}{database}{connections})
|
|
{
|
|
# No databases, exit.
|
|
print $anvil->Words->string({key => "error_0003"})."\n";
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, key => "error_0003"});
|
|
$anvil->nice_exit({exit_code => 1});
|
|
}
|
|
|
|
# Are we being asked to reboot or power off?
|
|
if ($anvil->data->{switches}{'reboot'})
|
|
{
|
|
# Did the user confirm?
|
|
if ($anvil->data->{switches}{'y'})
|
|
{
|
|
do_poweroff($anvil, "reboot");
|
|
}
|
|
else
|
|
{
|
|
# Not yet, ask to confirm.
|
|
print $anvil->Words->string({key => "message_0059"})." ";
|
|
my $answer = <STDIN>;
|
|
chomp($answer);
|
|
if ($answer =~ /^y/i)
|
|
{
|
|
do_poweroff($anvil, "reboot");
|
|
}
|
|
else
|
|
{
|
|
# Abort and exit.
|
|
print $anvil->Words->string({key => "message_0061"})."\n";
|
|
$anvil->nice_exit({exit_code => 0});
|
|
}
|
|
}
|
|
}
|
|
if ($anvil->data->{switches}{'poweroff'})
|
|
{
|
|
# Did the user confirm?
|
|
if ($anvil->data->{switches}{'y'})
|
|
{
|
|
do_poweroff($anvil, "poweroff");
|
|
}
|
|
else
|
|
{
|
|
# Not yet, ask to confirm.
|
|
print $anvil->Words->string({key => "message_0060"})." ";
|
|
my $answer = <STDIN>;
|
|
chomp($answer);
|
|
if ($answer =~ /^y/i)
|
|
{
|
|
do_poweroff($anvil, "poweroff");
|
|
}
|
|
else
|
|
{
|
|
# Abort and exit.
|
|
print $anvil->Words->string({key => "message_0061"})."\n";
|
|
$anvil->nice_exit({exit_code => 0});
|
|
}
|
|
}
|
|
}
|
|
|
|
my $reboot_needed = $anvil->System->reboot_needed({debug => 2});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reboot_needed => $reboot_needed }});
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::reboot-needed" => $anvil->data->{switches}{'reboot-needed'} }});
|
|
if ($anvil->data->{switches}{'reboot-needed'} eq "1")
|
|
{
|
|
# Enable
|
|
if (not $reboot_needed)
|
|
{
|
|
$reboot_needed = $anvil->System->reboot_needed({debug => 2, set => 1});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reboot_needed => $reboot_needed }});
|
|
print $anvil->Words->string({key => "message_0048"})."\n";
|
|
}
|
|
else
|
|
{
|
|
# Was already set, do nothing
|
|
print $anvil->Words->string({key => "message_0049"})."\n";
|
|
}
|
|
}
|
|
elsif ($anvil->data->{switches}{'reboot-needed'} eq "0")
|
|
{
|
|
# Disabled
|
|
if ($reboot_needed)
|
|
{
|
|
$reboot_needed = $anvil->System->reboot_needed({debug => 2, set => 0});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reboot_needed => $reboot_needed }});
|
|
print $anvil->Words->string({key => "message_0050"})."\n";
|
|
}
|
|
else
|
|
{
|
|
# Was already disabled, do nothing
|
|
print $anvil->Words->string({key => "message_0051"})."\n";
|
|
}
|
|
}
|
|
elsif ($anvil->data->{switches}{'reboot-needed'})
|
|
{
|
|
# Bad call
|
|
print $anvil->Words->string({key => "message_0052", variables => { program => $THIS_FILE }})."\n";
|
|
}
|
|
|
|
# Get the current state
|
|
if ($reboot_needed)
|
|
{
|
|
# Report that we need to reboot
|
|
print $anvil->Words->string({key => "message_0053"})."\n";
|
|
}
|
|
else
|
|
{
|
|
# Report that we're not.
|
|
print $anvil->Words->string({key => "message_0054"})."\n";
|
|
}
|
|
|
|
# We're done
|
|
$anvil->nice_exit({exit_code => 0});
|
|
|
|
|
|
#############################################################################################################
|
|
# Private functions. #
|
|
#############################################################################################################
|
|
|
|
# This does a reboot or power off
|
|
sub do_poweroff
|
|
{
|
|
my ($anvil, $task) = @_;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { task => $task }});
|
|
|
|
# We'll wait until the system has at least 10 minutes of uptime, unless '--no-wait' was given.
|
|
my $uptime = $anvil->data->{switches}{'no-wait'} ? 0 : $anvil->System->get_uptime;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
"switches::no-wait" => $anvil->data->{switches}{'no-delay'},
|
|
uptime => $uptime,
|
|
}});
|
|
|
|
my $say_task = $task eq "poweroff" ? "message_0062" : "message_0063";
|
|
my $percent = $task eq "poweroff" ? 100 : 50;
|
|
print $anvil->Words->string({key => $say_task})."\n";
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => $say_task});
|
|
|
|
# To minimize the trouble of a problem where the reboot needed flag isn't cleared, and so the system
|
|
# wants to repeatedly reboot, we need to add a delay to not let anvil-daemon ask us to
|
|
# reboot/power-off until the system uptime is more than ten minutes.
|
|
if (($uptime) && ($uptime < 600))
|
|
{
|
|
# We'll wait until the system has been running for ten minutes.
|
|
my $difference = 600 - $uptime;
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0224", variables => {
|
|
task => $task eq "poweroff" ? "#!string!log_0225!#" : "#!string!log_0226!#",
|
|
difference => $difference,
|
|
uptime => $uptime,
|
|
say_time => $anvil->Get->date_and_time({offset => $difference, time_only => 1}),
|
|
}});
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => $say_task});
|
|
|
|
sleep $difference;
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0227", variables => { task => $task eq "poweroff" ? "#!string!log_0225!#" : "#!string!log_0226!#" }});
|
|
}
|
|
|
|
# If I don't have a job_uuid, try to find one.
|
|
my $job_uuid = "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::job-uuid" => $anvil->data->{switches}{'job-uuid'} }});
|
|
if ($anvil->data->{switches}{'job-uuid'})
|
|
{
|
|
$job_uuid = $anvil->data->{switches}{'job-uuid'};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
|
|
}
|
|
else
|
|
{
|
|
$job_uuid = $anvil->Job->get_job_uuid({debug => 2, program => $THIS_FILE});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
|
|
}
|
|
|
|
if ($job_uuid)
|
|
{
|
|
$anvil->Job->clear({job_uuid => $job_uuid});
|
|
$anvil->Job->update_progress({
|
|
debug => 2,
|
|
progress => $percent,
|
|
message => $say_task,
|
|
job_uuid => $job_uuid,
|
|
});
|
|
}
|
|
|
|
# Make sure the 'reboot needed' flag is set. When 'anvil-daemon' starts, it will use this to confirm
|
|
# that it is starting post-reboot and clear it.
|
|
$reboot_needed = $anvil->System->reboot_needed({set => 1});
|
|
|
|
# Now do the deed.
|
|
my $shell_call = $anvil->data->{path}{exe}{systemctl}." ".$task;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
|
|
my $output = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
|
|
|
|
# Unlikely we're still alive, but 'poweroff' and 'reboot' do return once enqueued, so...
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output }});
|
|
$anvil->nice_exit({exit_code => 0});
|
|
}
|