* Updates Tools->nice_exit to add the caller name to the exit status.

* Created Job->clear() to clear the job_picked_up_by column. Created Job->get_job_uuid() to return the job_uuid of an unfinished job matching a given job_command string (if any found).
* Updated striker->process_power to log the user out after confirming a poweroff or reboot action.
* Added anvil-daemon --startup-only to not enter the main loop and exit.
* Finished getting poweroff and reboot working (though more testing needed).

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 6 years ago
parent b7e4ba9123
commit 00565b123c
  1. 13
      Anvil/Tools.pm
  2. 10
      Anvil/Tools/Database.pm
  3. 4
      Anvil/Tools/Get.pm
  4. 123
      Anvil/Tools/Job.pm
  5. 7
      cgi-bin/striker
  6. 7
      share/words.xml
  7. 62
      tools/anvil-daemon
  8. 44
      tools/anvil-manage-power
  9. 29
      tools/anvil-update-system

@ -371,12 +371,21 @@ sub nice_exit
# Report the runtime.
my $end_time = Time::HiRes::time;
my $run_time = $end_time - $anvil->data->{ENV_VALUES}{START_TIME};
my $caller = ($0 =~ /^.*\/(.*)$/)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:ENV_VALUES::START_TIME' => $anvil->data->{ENV_VALUES}{START_TIME},
's2:end_time' => $end_time,
's3:run_time' => $run_time,
's4:caller' => $caller,
}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0135", variables => { 'caller' => $caller, runtime => $run_time }});
my ($package, $filename, $line) = caller;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:package' => $package,
's2:filename' => $filename,
's3:line' => $line,
}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0135", variables => { runtime => $run_time }});
# Close the log file.
if ($anvil->data->{HANDLE}{log_file})
@ -1056,7 +1065,7 @@ sub catch_sig
if ($signal)
{
print "Process with PID: [$$] exiting on SIG".$signal.".\n";
print "\n\nProcess with PID: [$$] exiting on SIG".$signal.".\n";
if ($anvil->data->{sys}{terminal}{stty})
{

@ -1307,6 +1307,10 @@ sub get_jobs
my $return = [];
my $ended_within = defined $parameter->{ended_within} ? $parameter->{ended_within} : 300;
my $job_host_uuid = defined $parameter->{job_host_uuid} ? $parameter->{job_host_uuid} : $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
ended_within => $ended_within,
job_host_uuid => $job_host_uuid,
}});
my $query = "
SELECT
@ -1327,11 +1331,11 @@ FROM
WHERE
job_host_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($job_host_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
@ -1351,7 +1355,7 @@ WHERE
my $modified_date = $row->[11];
my $started_seconds_ago = $job_picked_up_at ? (time - $job_picked_up_at) : 0;
my $updated_seconds_ago = $job_updated ? (time - $job_updated) : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
job_uuid => $job_uuid,
job_command => $job_command,
job_data => $job_data,

@ -45,7 +45,7 @@ Provides all methods related to getting access to frequently used data.
# Access to methods using '$anvil->Get->X'.
#
# Example using 'date_and_time()';
my $foo_path = $anvil->Get->date_and_time({...});
my $date = $anvil->Get->date_and_time({...});
=head1 METHODS
@ -384,7 +384,7 @@ sub date_and_time
my $time_only = defined $parameter->{time_only} ? $parameter->{time_only} : 0;
my $date_only = defined $parameter->{date_only} ? $parameter->{date_only} : 0;
# NOTE: This is used too early for normal error handling.
### NOTE: This is used too early for normal error handling.
# Are things sane?
if ($use_time =~ /D/)
{

@ -12,7 +12,9 @@ our $VERSION = "3.0.0";
my $THIS_FILE = "Job.pm";
### Methods;
#
# clear
# get_job_uuid
# update_progress
=pod
@ -75,6 +77,120 @@ sub parent
# Public methods #
#############################################################################################################
=head2 clear
This clears the C<< job_picked_up_by >> value for the given job.
Parameters;
=head3 job_uuid (required)
This is the C<< job_uuid >> of the job to clear.
=cut
sub clear
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $job_uuid = defined $parameter->{job_uuid} ? $parameter->{job_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_uuid => $job_uuid }});
# Return if we don't have a program name.
if ($job_uuid eq "")
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Job->clear()", parameter => "job_uuid" }});
return(1);
}
my $query = "
UPDATE
jobs
SET
job_picked_up_by = '0',
modified_date = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
job_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($job_uuid)."
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
return(0);
}
=head2 get_job_uuid
This takes the name of a program and looks in jobs for a pending job with the same command. If it is found, C<< jobs::job_uuid >> is set and the C<< job_uuid >> is returned. If no job is found, and empty string is returned.
Parameters;
=head3 host_uuid (optional, default Get->host_uuid())
If set, this will search for the job on a specific host.
=head3 program (required)
This is the program name to look for. Specifically, this string is used to search C<< job_command >> (anchored to the start of the column and a wild-card end, ie: C<< program => foo >> would find C<< foobar >> or C<< foo --bar >>). Be as specific as possible. If two or more results are found, no C<< job_uuid >> will be returned. There must be only one match for this method to work properly.
=cut
sub get_job_uuid
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $job_uuid = "";
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid;
my $program = defined $parameter->{program} ? $parameter->{program} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid,
program => $program,
}});
# Return if we don't have a program name.
if ($program eq "")
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Job->get_job_uuid()", parameter => "program" }});
return(1);
}
my $query = "
SELECT
job_uuid
FROM
jobs
WHERE
job_command LIKE ".$anvil->data->{sys}{database}{use_handle}->quote($program."%")."
AND
job_progress != '100'
AND
job_host_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($host_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
if ($count == 1)
{
# Found it
$job_uuid = defined $results->[0]->[0] ? $results->[0]->[0] : "";
$anvil->data->{jobs}{job_uuid} = $job_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
job_uuid => $job_uuid,
"jobs::job-uuid" => $anvil->data->{jobs}{'job-uuid'},
}});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
return($job_uuid);
}
=head2 update_progress
This updates the progress if we were called with a job UUID.
@ -107,7 +223,6 @@ sub update_progress
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $salt = "";
my $job_uuid = defined $parameter->{job_uuid} ? $parameter->{job_uuid} : "";
my $message = defined $parameter->{message} ? $parameter->{message} : "";
my $progress = defined $parameter->{progress} ? $parameter->{progress} : "";
@ -125,7 +240,7 @@ sub update_progress
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_uuid => $job_uuid }});
}
# Exit if we still don't have a job_uuid
# Return if we still don't have a job_uuid
if (not $job_uuid)
{
# Nothing we can do.
@ -133,7 +248,7 @@ sub update_progress
return(1);
}
# Exit if we don't have a progress.
# Return if we don't have a progress.
if ($progress eq "")
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Job->update_progress()", parameter => "progress" }});

@ -184,7 +184,7 @@ sub process_task
elsif ((defined $anvil->data->{cgi}{logout}) && ($anvil->data->{cgi}{logout}{value}))
{
# Bye now!
$anvil->Account->logout({debug => 3});
$anvil->Account->logout();
}
else
{
@ -312,6 +312,9 @@ sub process_power
description => $task eq "poweroff" ? "#!string!job_0008!#" : "#!string!job_0006!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
# Log the user out, just to be safe.
$anvil->Account->logout();
}
else
{
@ -850,7 +853,7 @@ sub check_availability
# If we have any running or recently finished jobs, we'll desplay them below.
my $jobs_list = "#!string!striker_0097!#";
my $return = $anvil->Database->get_jobs({debug => 2, ended_within => 300});
my $return = $anvil->Database->get_jobs({ended_within => 300});
my $count = @{$return};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
if ($count)

@ -101,6 +101,7 @@ The '-y' option prevents a confirmation prompt.
<key name="message_0061">Aborting.</key>
<key name="message_0062">Powering off the local system now.</key>
<key name="message_0063">Rebooting the local system now.</key>
<key name="message_0064">The Anvil! has restarted at: [#!variable!date_and_time!#] after powering back on.</key>
<!-- Log entries -->
<key name="log_0001">Starting: [#!variable!program!#].</key>
@ -270,7 +271,7 @@ The database connection error was:
<key name="log_0132">Connected to: [#!data!sys::database::connections!#] database(s).</key>
<key name="log_0133">Failed to read the system UUID. Received a non-UUID string: [#!variable!uuid!#]. Is the user: [#!variable!user!#] in the 'kmem' group?</key>
<key name="log_0134">The read host UUID: [#!variable!uuid!#] does not appear to be a valid UUID.</key>
<key name="log_0135">Runtime was approximately: [#!variable!runtime!#] seconds.</key>
<key name="log_0135">- #!variable!caller!# runtime was approximately: [#!variable!runtime!#] seconds.</key>
<key name="log_0136"><![CDATA[[ Error ] - The method: [#!variable!method!#] was called with either 'job_uuid': [#!variable!job_uuid!#] not being passed (or was not a valid UUID), or 'job_name': [#!variable!job_name!#] not being passed.]]></key>
<key name="log_0137"><![CDATA[[ Error ] - The method: [#!variable!method!#] was called with an invalid value for: [#!variable!variable_name!#]: -> [#!variable!variable_value!#]. See 'perldoc Anvil::Tools::#!variable!module!#' for valid options.]]></key>
<key name="log_0138"><![CDATA[[ Error ] - The method: [#!variable!method!#] was with an invalid 'job_progress': [#!variable!job_progress!#]. It needs to be a whole-number value between 0 and 100, inclusive.]]></key>
@ -483,8 +484,8 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st
<key name="striker_0097">There are no jobs currently running or recently completed.</key>
<key name="striker_0098">Back</key>
<key name="striker_0099">Job</key>
<key name="striker_0100">Reboot this system? If you proceed, this system will be withdrawn from the Anvil! and rebooted. Please be sure you have access in the rare chance that the system fails to boot back up.</key>
<key name="striker_0101">Power off this system? If you proceed, this system will be withdrawn from the Anvil! and powered off. You will need physical access to the machine to turn it back on in most cases. A properly condigured Striker dashboard will power on after a power cycle (via a PDU) or any machine with IPMI if you have access to a machine on the BCN.</key>
<key name="striker_0100">Reboot this system? If you proceed, you will be logged out and this system will be rebooted. Please be sure you have access in the rare chance that the system fails to boot back up.</key>
<key name="striker_0101">Power off this system? If you proceed, you will be logged out and this system will be powered off. You will need physical access to the machine to turn it back on in most cases. A properly condigured Striker dashboard will power on after a power cycle (via a PDU) or any machine with IPMI if you have access to a machine on the BCN.</key>
<!-- Strings used by jobs -->
<key name="job_0001">Configure Network</key>

@ -11,6 +11,11 @@
# TODO:
# - Need to check what kind of machine this is and not prep the database unless its a dashboard.
# - Add a "running: pending,yes,done,dead" and show an appropriate icon beside jobs
# - Decide if holding before the main loop until 'systemctl is-system-running' returns 'running' is a good
# idea or not.
#
# NOTE:
# - For later; 'reboot --force --force' immediately kills the OS, like disabling ACPI on EL6 and hitting the power button. Might be useful in ScanCore down the road.
#
use strict;
@ -63,6 +68,7 @@ $anvil->data->{switches}{'refresh-json'} = "";
$anvil->data->{switches}{'run-once'} = 0;
$anvil->data->{switches}{'main-loop-only'} = 0;
$anvil->data->{switches}{'no-start'} = 0;
$anvil->data->{switches}{'startup-only'} = 0;
$anvil->Get->switches;
if ($anvil->data->{switches}{'refresh-json'})
@ -90,7 +96,7 @@ while(1)
{
# Connect to the database(s)
$anvil->Storage->read_config({file => "/etc/anvil/anvil.conf"});
$anvil->Database->connect({debug => 2});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
if ($anvil->data->{sys}{database}{connections})
@ -124,12 +130,13 @@ while(1)
}
# Disconnect from the database(s) and sleep now.
$anvil->Database->disconnect({debug => 2});
$anvil->Database->disconnect();
sleep 2;
}
$anvil->nice_exit({code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
@ -146,6 +153,11 @@ sub run_once
# Check to see if we need to do boot-time tasks. We only run these if we've just booted
boot_time_tasks($anvil);
if ($anvil->data->{switches}{'startup-only'})
{
$anvil->nice_exit({code => 0});
}
return(0);
}
@ -214,6 +226,26 @@ AND
# Clear the reboot request.
$reboot_needed = $anvil->System->reboot_needed({set => 0});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reboot_needed => $reboot_needed }});
# Check to see if there was a reboot job in progress. If so, finish it off.
my $job_uuid = $anvil->Job->get_job_uuid({debug => 2, program => "anvil-manage-power"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
if ($job_uuid)
{
# Update the percentage to '100' and then clear the old PID.
my $date_time = $anvil->Get->date_and_time();
if ($anvil->data->{jobs}{job_uuid})
{
$anvil->Job->update_progress({
debug => 2,
progress => 100,
message => "message_0064,!!date_and_time!".$date_time."!!",
job_uuid => $job_uuid
});
}
$anvil->Job->clear({job_uuid => $job_uuid});
}
}
return(0);
@ -261,7 +293,7 @@ sub keep_running
# Free up memory
$anvil->data->{jobs}{handles}{$job_uuid}->cleanup();
clear_job($anvil, $job_uuid);
$anvil->Job->clear({job_uuid => $job_uuid});
}
}
}
@ -275,26 +307,6 @@ sub keep_running
return(0);
}
# This clears the 'job_picked_up_by'.
sub clear_job
{
my ($anvil, $job_uuid) = @_;
my $query = "
UPDATE
jobs
SET
job_picked_up_by = '0',
modified_date = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
job_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($job_uuid)."
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
return(0);
}
# This will check for any jobs that aren't at 100%. For each found, if 'picked_up_by' is set, a check is made
# to see if the PID is still alive. If it isn't, or if 'picked_up_by' is not set, the appropriate tool is
# invoked to handle it.
@ -310,7 +322,7 @@ sub run_jobs
my $jobs_file = "{\"jobs\":[\n";
# Get a list of pending or incomplete jobs.
my $return = $anvil->Database->get_jobs({debug => 2, ended_within => 300});
my $return = $anvil->Database->get_jobs({ended_within => 300});
my $count = @{$return};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'return' => $return,
@ -364,7 +376,7 @@ sub run_jobs
if (not exists $anvil->data->{pids}{$job_picked_up_by})
{
# If the job is done, just clear the 'job_picked_up_by' and be done.
clear_job($anvil, $job_uuid);
$anvil->Job->clear({job_uuid => $job_uuid});
if ($job_progress ne "100")
{
# The previous job is gone, but the job isn't finished. Start it again.

@ -70,7 +70,7 @@ if (not $anvil->data->{sys}{database}{connections})
if ($anvil->data->{switches}{'reboot'})
{
# Did the user confirm?
if ($anvil->data->{switches}{'reboot'} =~ /^y/i)
if ($anvil->data->{switches}{'y'})
{
do_poweroff($anvil, "reboot");
}
@ -95,7 +95,7 @@ if ($anvil->data->{switches}{'reboot'})
if ($anvil->data->{switches}{'poweroff'})
{
# Did the user confirm?
if ($anvil->data->{switches}{'poweroff'} =~ /^y/i)
if ($anvil->data->{switches}{'y'})
{
do_poweroff($anvil, "poweroff");
}
@ -178,19 +178,51 @@ $anvil->nice_exit({exit_code => 0});
# Private functions. #
#############################################################################################################
# This does a reboot, clearing the flag indicating a reboot is required in the process.
# 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 }});
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";
# Clear the "reboot needed" flag.
$reboot_needed = $anvil->System->reboot_needed({set => 0});
# 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});
# Set the progress to '50%' (anvil-daemon will set it to 100% when it starts post-boot).
# 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});
}

@ -58,32 +58,9 @@ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list
if (not $anvil->data->{switches}{'job-uuid'})
{
# See if a job is waiting to run.
my $query = "
SELECT
job_uuid
FROM
jobs
WHERE
job_command LIKE '".$THIS_FILE."%'
AND
job_progress != '100'
AND
job_host_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->Get->host_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
if ($count == 1)
{
# Found it
$anvil->data->{jobs}{job_uuid} = defined $results->[0]->[0] ? $results->[0]->[0] : "";
$anvil->data->{switches}{job_uuid} = $anvil->Job->get_job_uuid({debug => 2, program => $THIS_FILE});
$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'})
{
# Is it set and valid?
@ -199,8 +176,8 @@ sub update_progress
debug => 2,
progress => $progress,
message => $message,
job_uuid => $anvil->data->{jobs}{job_uuid}},
);
job_uuid => $anvil->data->{jobs}{job_uuid},
});
}
return(0);

Loading…
Cancel
Save