From 545f9a9bb5ba472b71caa10409bc0f873e97d1df Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 4 Sep 2018 18:57:09 -0400 Subject: [PATCH] * Renamed tools/anvil-reboot-needed to tools/anvil-manage-power and started adding support for rebooting and powering off to it. * Created the Anvil::Tools::Jobs module to handle general job processing task. Moved 'update_progress' from tools/anvil-update-system to it and generalized it. * Added some missing CDATA wrappers to the words XML file strings with '>' in it. Signed-off-by: Digimer --- Anvil/Tools.pm | 17 +- Anvil/Tools/Job.pm | 279 ++++++++++++++++++ cgi-bin/striker | 52 ++++ html/skins/alteeve/images/reboot_icon.xcf | Bin 80921 -> 80921 bytes .../alteeve/images/reboot_needed_icon.png | Bin 22593 -> 24911 bytes share/words.xml | 33 ++- tools/anvil-daemon | 2 +- tools/anvil-manage-power | 188 ++++++++++++ tools/anvil-reboot-needed | 101 ------- tools/anvil-update-system | 98 +----- 10 files changed, 563 insertions(+), 207 deletions(-) create mode 100755 Anvil/Tools/Job.pm create mode 100755 tools/anvil-manage-power delete mode 100755 tools/anvil-reboot-needed diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index de68dcc4..276c8284 100755 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -43,6 +43,7 @@ use Anvil::Tools::Alert; use Anvil::Tools::Database; use Anvil::Tools::Convert; use Anvil::Tools::Get; +use Anvil::Tools::Job; use Anvil::Tools::Log; use Anvil::Tools::Remote; use Anvil::Tools::Storage; @@ -120,6 +121,7 @@ sub new CONVERT => Anvil::Tools::Convert->new(), GET => Anvil::Tools::Get->new(), LOG => Anvil::Tools::Log->new(), + JOB => Anvil::Tools::Job->new(), REMOTE => Anvil::Tools::Remote->new(), STORAGE => Anvil::Tools::Storage->new(), SYSTEM => Anvil::Tools::System->new(), @@ -154,6 +156,7 @@ sub new $anvil->Convert->parent($anvil); $anvil->Get->parent($anvil); $anvil->Log->parent($anvil); + $anvil->Job->parent($anvil); $anvil->Remote->parent($anvil); $anvil->Storage->parent($anvil); $anvil->System->parent($anvil); @@ -456,6 +459,18 @@ sub Get return ($self->{HANDLE}{GET}); } +=head2 Job + +Access the C methods via 'C<< $anvil->Log->method >>'. + +=cut +sub Job +{ + my $self = shift; + + return ($self->{HANDLE}{JOB}); +} + =head2 Log Access the C methods via 'C<< $anvil->Log->method >>'. @@ -888,7 +903,7 @@ sub _set_paths 'anvil-manage-striker-peers' => "/usr/sbin/anvil-manage-striker-peers", 'anvil-prep-database' => "/usr/sbin/anvil-prep-database", 'anvil-update-states' => "/usr/sbin/anvil-update-states", - 'anvil-reboot-needed' => "/usr/sbin/anvil-reboot-needed", + 'anvil-manage-power' => "/usr/sbin/anvil-reboot-needed", 'anvil-report-memory' => "/usr/sbin/anvil-report-memory", 'chmod' => "/usr/bin/chmod", 'chown' => "/usr/bin/chown", diff --git a/Anvil/Tools/Job.pm b/Anvil/Tools/Job.pm new file mode 100755 index 00000000..305c043e --- /dev/null +++ b/Anvil/Tools/Job.pm @@ -0,0 +1,279 @@ +package Anvil::Tools::Job; +# +# This module contains methods used in job handling +# + +use strict; +use warnings; +use Data::Dumper; +use Scalar::Util qw(weaken isweak); + +our $VERSION = "3.0.0"; +my $THIS_FILE = "Job.pm"; + +### Methods; +# + +=pod + +=encoding utf8 + +=head1 NAME + +Anvil::Tools::Job + +Provides methods related to (background) job handling. + +=head1 SYNOPSIS + + use Anvil::Tools; + + # Get a common object handle on all Anvil::Tools modules. + my $anvil = Anvil::Tools->new(); + + # ... + +=head1 METHODS + +Methods in this module; + +=cut +sub new +{ + my $class = shift; + my $self = { + JOB => { + LANGUAGE => "", + }, + }; + + bless $self, $class; + + return ($self); +} + +# Get a handle on the Anvil::Tools object. I know that technically that is a sibling module, but it makes more +# sense in this case to think of it as a parent. +sub parent +{ + my $self = shift; + my $parent = shift; + + $self->{HANDLE}{TOOLS} = $parent if $parent; + + # Defend against memory leads. See Scalar::Util'. + if (not isweak($self->{HANDLE}{TOOLS})) + { + weaken($self->{HANDLE}{TOOLS});; + } + + return ($self->{HANDLE}{TOOLS}); +} + + +############################################################################################################# +# Public methods # +############################################################################################################# + +=head2 update_progress + +This updates the progress if we were called with a job UUID. + +This also sets C<< sys::last_update >>, allowing you to see how long it's been since the progress was last updated and trigger an update on a time based counter. + +Returns C<< 0 >> on success, C<< 1 >> on failure. + +B<< Note >>: Some special C<< job_status >> processing is done to support some specific callers. These should not impact generic calls of this method. + +Parameters; + +=head3 job_uuid (optional, default 'jobs::job_uuid') + +This is the UUID of the job to update. If it isn't set, but C<< jobs::job_uuid >> is set, it will be used. If that is also not set, + +=head3 message (optional) + +If set, this message will be appended to C<< job_status >>. If set to 'C<< clear >>', previous records will be removed. + +=head3 progress (required) + +This is a number to set the current progress to. + +=cut +sub update_progress +{ + my $self = shift; + my $parameter = shift; + 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} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + progress => $progress, + message => $message, + job_uuid => $job_uuid, + "jobs::job_uuid" => $anvil->data->{jobs}{job_uuid}, + }}); + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_uuid => $job_uuid }}); + if ((not $job_uuid) && ($anvil->data->{jobs}{job_uuid})) + { + $job_uuid = $anvil->data->{jobs}{job_uuid}; + $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 + if (not $job_uuid) + { + # Nothing we can do. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, priority => "alert", key => "log_0207"}); + return(1); + } + + # Exit 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" }}); + return(1); + } + + # Is the progress valid? + if (($progress =~ /\D/) or ($progress < 0) or ($progress > 100)) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, priority => "alert", key => "log_0209", variables => { progress => $progress }}); + return(1); + } + + # If 'sys::last_update' isn't set, set it now. + if (not defined $anvil->data->{sys}{last_update}) + { + $anvil->data->{sys}{last_update} = time; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::last_update" => $anvil->data->{sys}{last_update} }}); + } + + # Get the current job_status and append this new one. + my $job_picked_up_by = $$; + my $job_picked_up_at = 0; + my $job_status = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { message => $message, job_picked_up_by => $job_picked_up_by }}); + if ($message eq "clear") + { + $job_picked_up_by = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_picked_up_by => $job_picked_up_by }}); + } + else + { + my $query = " +SELECT + job_status, + job_picked_up_at +FROM + jobs +WHERE + job_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($job_uuid)." +;"; + $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 => $debug, list => { + results => $results, + count => $count, + }}); + + if (not $count) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, priority => "alert", key => "log_0208", variables => {job_uuid => $job_uuid}}); + return(1); + } + + $job_status = $results->[0]->[0]; + $job_picked_up_at = $results->[0]->[1]; + $job_status = "" if not defined $job_status; + $job_picked_up_at = 0 if not defined $job_picked_up_at; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + job_status => $job_status, + job_picked_up_at => $job_picked_up_at, + }}); + + # Set that the job is now picked up if the progress is '1' or it 'job_picked_up_at' + # is not set yet. + if ((not $job_picked_up_at) or ($progress eq "1")) + { + $job_picked_up_at = time; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_picked_up_at => $job_picked_up_at }}); + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { message => $message }}); + if (($message) && ($job_status)) + { + $job_status .= "\n"; + } + if ($message) + { + $job_status .= $message; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_status => $job_status }}); + } + } + + ### NOTE: This is used by 'anvil-update-system'. + # Insert counts + if ($job_status =~ /message_0058/gs) + { + my $downloaded = $anvil->data->{counts}{downloaded} ? $anvil->Convert->add_commas({number => $anvil->data->{counts}{downloaded}}) : 0; + my $installed = $anvil->data->{counts}{installed} ? $anvil->Convert->add_commas({number => $anvil->data->{counts}{installed}}) : 0; + my $verified = $anvil->data->{counts}{verified} ? $anvil->Convert->add_commas({number => $anvil->data->{counts}{verified}}) : 0; + my $lines = $anvil->data->{counts}{lines} ? $anvil->Convert->add_commas({number => $anvil->data->{counts}{lines}}) : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "s1:counts::downloaded" => $anvil->data->{counts}{downloaded}, + "s2:downloaded" => $downloaded, + "s3:counts::installed" => $anvil->data->{counts}{installed}, + "s4:installed" => $installed, + "s5:counts::verified" => $anvil->data->{counts}{verified}, + "s6:verified" => $verified, + "s7:counts::lines" => $anvil->data->{counts}{lines}, + "s8:lines" => $lines, + }}); + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ">> job_status" => $job_status }}); + $job_status =~ s/message_0058,!!downloaded!.*?!!,!!installed!.*?!!,!!verified!.*?!!,!!lines!.*?!!/message_0058,!!downloaded!$downloaded!!,!!installed!$installed!!,!!verified!$verified!!,!!lines!$lines!!/sm; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "<< job_status" => $job_status }}); + } + + my $query = " +UPDATE + jobs +SET + job_picked_up_by = ".$anvil->data->{sys}{database}{use_handle}->quote($job_picked_up_by).", + job_picked_up_at = ".$anvil->data->{sys}{database}{use_handle}->quote($job_picked_up_at).", + job_updated = ".$anvil->data->{sys}{database}{use_handle}->quote(time).", + job_progress = ".$anvil->data->{sys}{database}{use_handle}->quote($progress).", + job_status = ".$anvil->data->{sys}{database}{use_handle}->quote($job_status).", + 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 => $debug, list => { query => $query }}); + $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); + + # Note this update time + $anvil->data->{sys}{last_update} = time; + + return(0); +} + + +# =head3 +# +# Private Functions; +# +# =cut + +############################################################################################################# +# Private functions # +############################################################################################################# + +1; diff --git a/cgi-bin/striker b/cgi-bin/striker index 2fcaf741..5a33363a 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -234,6 +234,14 @@ sub process_task { process_update($anvil); } + elsif ($anvil->data->{cgi}{task}{value} eq "reboot") + { + process_reboot($anvil); + } + elsif ($anvil->data->{cgi}{task}{value} eq "poweroff") + { + process_poweroff($anvil); + } else { # What we show for the reboot icon and text depends on if a reboot is pending. @@ -272,6 +280,50 @@ sub process_task return(0); } +# This handles updating this Striker. +sub process_reboot +{ + my ($anvil) = @_; + + ### NOTE: This doesn't update Striker (the Alteeve) stack yet, just the base OK. + $anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{value}; + if ($anvil->data->{cgi}{confirm}{value}) + { + # Record the job! + my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ + debug => 2, + file => $THIS_FILE, + line => __LINE__, + job_command => "anvil-manage-power --reboot -y", + job_data => "", + job_name => "reboot::system", + job_title => "job_0003", + job_description => "job_0004", + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); + + # We don't need to store anything as hidden variables, we'll read it back from the database + # later. + $anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "system_update_recorded", variables => { + title_id => "", + message_id => "", + title => "#!string!striker_0044!#", + description => "#!string!striker_0088!#", + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }}); + + # Set maintenance mode. + $anvil->System->maintenance_mode({debug => 2, set => 1}); + } + else + { + # Show the screen the confirm the addition. + $anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "confirm-update"}); + } + + return(0); +} + # This handles updating this Striker. sub process_update { diff --git a/html/skins/alteeve/images/reboot_icon.xcf b/html/skins/alteeve/images/reboot_icon.xcf index 7540b1a5635db52dc5c30af03db257840a72146f..43b181334013ad06865f72cf4046d27e02f7713e 100644 GIT binary patch delta 24437 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 cXmmmhDO$ll@EK8-zRr)8D#aL;wH) delta 24434 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 SBg)d(`LS~KbnjdLQ~n?CileFk diff --git a/html/skins/alteeve/images/reboot_needed_icon.png b/html/skins/alteeve/images/reboot_needed_icon.png index bcfda97502ecd9b5cb14650474d11be842fe309f..c1c99acea7d25d2bbe7e15d8c10206791f90d743 100644 GIT binary patch literal 24911 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 S#9~9p08mlTkgt}t4EaBKyVA4( literal 22593 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 diff --git a/share/words.xml b/share/words.xml index 746d9d9f..8ea436ee 100644 --- a/share/words.xml +++ b/share/words.xml @@ -82,9 +82,12 @@ Report maintenance mode: #!variable!program!# This system has has been set to no longer need a reboot. This system was not in maintenance mode, nothing changed. Bad call. Usage: -Set that a reboot is required: #!variable!program!# --set 1 -Clear the need for a reboot: #!variable!program!# --set 0 +Set that a reboot is required: #!variable!program!# --reboot-needed 1 +Clear the need for a reboot: #!variable!program!# --reboot-neededset 0 Report if a reboot is needed: #!variable!program!# +Reboot the system: #!variable!program!# --reboot [-y] +Poweroff the system: #!variable!program!# --poweroff [-y] +The '-y' option prevents a confirmation prompt. This system needs to be rebooted. This system does NOT need to be rebooted. @@ -93,6 +96,9 @@ Report if a reboot is needed: #!variable!program!# No updates were found or needed. * Packages downloaded: [#!variable!downloaded!#], Installed or updated: [#!variable!installed!#], Verified: [#!variable!verified!#], Output lines: [#!variable!lines!#]. + Are you sure you want to reboot this system? [y/N]. + Are you sure you want to power off this system? [y/N]. + Aborting. Starting: [#!variable!program!#]. @@ -171,7 +177,7 @@ Connecting to Database with configuration ID: [#!variable!uuid!#] Database user: [#!variable!user!#] already exists with ID: [#!variable!uuid!#]. users_home() was asked to find the home directory for the user: [#!variable!user!#], but was unable to do so.]]> SSH session opened without a password to: [#!variable!target!#]. - The database: [#!variable!host!# -> #!variable!name!#] with the UUID: [#!variable!uuid!#] did not respond to pings and 'database::#!variable!uuid!#::ping' is not set to '0' in '#!data!path::configs::anvil.conf!#', skipping it. + #!variable!name!#] with the UUID: [#!variable!uuid!#] did not respond to pings and 'database::#!variable!uuid!#::ping' is not set to '0' in '#!data!path::configs::anvil.conf!#', skipping it.]]> [ Warning ] - The database: [#!variable!name!#] on host: [#!variable!host!#] with ID: [#!variable!uuid!#] can not be used, skipping it. The database connection error was: @@ -277,10 +283,10 @@ The database connection error was: A job to configure the network was found, and it was picked up by: [#!variable!pid!#], but that process is not running and it appears to only be: [#!variable!percent!# %] complete. Taking the job. The network: [#!variable!network!#] has something set for the IP [#!variable!ip!#], but it appears to be invalid. Ignoring this network. The network: [#!variable!network!#] is not set to be configured. Skipping it. - The Storage->backup() method was called with the source file: [#!variable!source_file!#], which does not appear to be a full path and file name (should start with '/'). - The Storage->backup() method was called with the source file: [#!variable!source_file!#], which does not appear to exist. - The Storage->backup() method was called with the source file: [#!variable!source_file!#], which can not be read (please check permissions and SELinux). - The Storage->backup() method was called with the source file: [#!variable!source_file!#], which isn't actually a file. + backup() method was called with the source file: [#!variable!source_file!#], which does not appear to be a full path and file name (should start with '/').]]> + backup() method was called with the source file: [#!variable!source_file!#], which does not appear to exist.]]> + backup() method was called with the source file: [#!variable!source_file!#], which can not be read (please check permissions and SELinux).]]> + backup() method was called with the source file: [#!variable!source_file!#], which isn't actually a file.]]> The file: [#!variable!source_file!#] has been backed up as: [#!variable!target_file!#]. Removing the old network configuration file: [#!variable!file!#] as part of the network reconfiguration. @@ -292,7 +298,7 @@ The database connection error was: read_file() tried to rsync the remote file: [#!variable!remote_file!#] to the local temporary file: [#!variable!local_file!#], but it did not arrive. There might be more information above.]]> The file: [#!variable!file!#] does not exist. read_config()' was called without a file name to read.]]> - The Storage->backup() method was asked to backup the file: [#!variable!source_file!#] on: [#!variable!target!#], but it looks like there was a problem connecting to the target. + backup() method was asked to backup the file: [#!variable!source_file!#] on: [#!variable!target!#], but it looks like there was a problem connecting to the target.]]> About to run the shell command: [#!variable!shell_call!#] on: [#!variable!target!#] as: [#!variable!remote_user!#] Failed to create the directory: [#!variable!directory!#] on: [#!variable!target!#] as: [#!variable!remote_user!#]. The error (if any) was: [#!variable!error!#] and the output (if any) was: [#!variable!output!#]. Failed to create the directory: [#!variable!directory!#]. The error (if any) was: [#!variable!error!#]. @@ -333,7 +339,10 @@ The database connection error was: Disconnected from all databases. Will reconnect when entering the main loop. Starting the background process: [#!variable!call!#] now. Background process: [#!variable!call!#] running with PID: [#!variable!pid!#]. - In Words->parse_banged_string(), while processing: [#!variable!message!#], a variable name was found to be missing. + parse_banged_string(), while processing: [#!variable!message!#], a variable name was found to be missing.]]> + update_progress() called without 'job_uuid' being set, and 'jobs::job_uuid' was also not set. Unable to find the job to update.]]> + update_progress() called with the 'job_uuid': [#!variable!job_uuid!#], which was not found. Unable to find the job to update.]]> + update_progress() called with 'progress' set to an invalid value: [#!variable!progress!#]. This must be a whole number between '0' and '100' (fractions not allowed).]]> Test @@ -513,8 +522,8 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st The: [#!variable!field!#] must be a positive integer. There was a problem reading your session details. To be safe, you have been logged out. Please try logging back in. It appears that your session has expired. To be safe, you have been logged out. Please try logging back in. - The user ID passed in to Account->read_details: [#!variable!uuid!#] is not a valid UUID. - The user ID passed in to Account->read_details: [#!variable!uuid!#] was not found in the database. + read_details: [#!variable!uuid!#] is not a valid UUID.]]> + read_details: [#!variable!uuid!#] was not found in the database.]]> Login failed, please try again. #!data!sys::log_file!#] for details.]]> #!variable!template!#] in the template file: [#!variable!file!#].]]> @@ -530,7 +539,7 @@ The update appears to have not completed successfully. The output was: ==== - In Words->parse_banged_string(), an infinite loop was detected while processing: [#!variable!message!#]. + parse_banged_string(), an infinite loop was detected while processing: [#!variable!message!#].]]> Yes diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 10d268d7..41f1be32 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -162,7 +162,7 @@ sub run_once # Clear the reboot request. my $output = $anvil->System->call({ debug => 2, - shell_call => $anvil->data->{path}{exe}{'anvil-reboot-needed'}." --set 0", + shell_call => $anvil->data->{path}{exe}{'anvil-reboot-needed'}." --reboot-needed 0", source => $THIS_FILE, line => __LINE__, }); diff --git a/tools/anvil-manage-power b/tools/anvil-manage-power new file mode 100755 index 00000000..33be0bce --- /dev/null +++ b/tools/anvil-manage-power @@ -0,0 +1,188 @@ +#!/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 => "/etc/anvil/anvil.conf"}); + +# 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->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 => 3, 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}{'reboot'} =~ /^y/i) + { + do_reboot($anvil); + } + else + { + # Not yet, ask to confirm. + print $anvil->Words->string({key => "message_0059"})." "; + my $answer = ; + chomp($answer); + if ($answer =~ /^y/i) + { + do_reboot($anvil); + } + 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}{'poweroff'} =~ /^y/i) + { + do_poweroff($anvil); + } + else + { + # Not yet, ask to confirm. + print $anvil->Words->string({key => "message_0060"})." "; + my $answer = ; + chomp($answer); + if ($answer =~ /^y/i) + { + do_poweroff($anvil); + } + 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're in mainteance mode + 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, clearing the flag indicating a reboot is required in the process. +sub do_reboot +{ + my ($anvil) = @_; + + + + $anvil->nice_exit({exit_code => 0}); +} diff --git a/tools/anvil-reboot-needed b/tools/anvil-reboot-needed deleted file mode 100755 index 33444405..00000000 --- a/tools/anvil-reboot-needed +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/perl -# -# This set, clear and report if the host needs to be rebooted. -# -# Examples; -# - Enable - anvil-reboot-needed --set 1 -# - Disable - anvil-reboot-needed --set 0 -# - Report - anvil-reboot-needed -# -# Exit codes; -# 0 = Normal exit. -# 1 = No database connections available. - -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 => "/etc/anvil/anvil.conf"}); - -# Read switches -$anvil->data->{switches}{set} = ""; -$anvil->Get->switches; - -# Connect to DBs. -$anvil->Database->connect; -$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, 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}); -} - -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::set" => $anvil->data->{switches}{set} }}); -if ($anvil->data->{switches}{set} 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}{set} 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}{set}) -{ - # Bad call - print $anvil->Words->string({key => "message_0052", variables => { program => $THIS_FILE }})."\n"; -} - -# Get the current state - -if ($reboot_needed) -{ - # Report that we're in mainteance mode - 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}); diff --git a/tools/anvil-update-system b/tools/anvil-update-system index 7e448597..a30b5dd2 100755 --- a/tools/anvil-update-system +++ b/tools/anvil-update-system @@ -141,7 +141,6 @@ WHERE } # Clea any old runs. -$anvil->data->{sys}{last_update} = time; update_progress($anvil, 0, "clear"); # We'll keep a count of lines and packages to show the user. @@ -196,97 +195,12 @@ sub update_progress if ($anvil->data->{jobs}{job_uuid}) { - # Get the current job_status and append this new one. - my $job_picked_up_by = $$; - my $job_picked_up_at = 0; - my $job_status = ""; - if ($message eq "clear") - { - $job_picked_up_by = 0; - } - else - { - my $query = " -SELECT - job_status, - job_picked_up_at -FROM - jobs -WHERE - job_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{jobs}{job_uuid})." -;"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); - - $job_status = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; - $job_picked_up_at = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[1]; - $job_status = "" if not defined $job_status; - $job_picked_up_at = 0 if not defined $job_picked_up_at; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - job_status => $job_status, - job_picked_up_at => $job_picked_up_at, - }}); - - # Set that the job is now picked up if the progress is '1' or it 'job_picked_up_at' - # is not set yet. - if ((not $job_picked_up_at) or ($progress eq "1")) - { - $job_picked_up_at = time; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_picked_up_at => $job_picked_up_at }}); - } - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message => $message }}); - if (($message) && ($job_status)) - { - $job_status .= "\n"; - } - if ($message) - { - $job_status .= $message; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_status => $job_status }}); - } - } - - # Insert counts - if ($job_status =~ /message_0058/gs) - { - my $downloaded = $anvil->data->{counts}{downloaded} ? $anvil->Convert->add_commas({number => $anvil->data->{counts}{downloaded}}) : 0; - my $installed = $anvil->data->{counts}{installed} ? $anvil->Convert->add_commas({number => $anvil->data->{counts}{installed}}) : 0; - my $verified = $anvil->data->{counts}{verified} ? $anvil->Convert->add_commas({number => $anvil->data->{counts}{verified}}) : 0; - my $lines = $anvil->data->{counts}{lines} ? $anvil->Convert->add_commas({number => $anvil->data->{counts}{lines}}) : 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "s1:counts::downloaded" => $anvil->data->{counts}{downloaded}, - "s2:downloaded" => $downloaded, - "s3:counts::installed" => $anvil->data->{counts}{installed}, - "s4:installed" => $installed, - "s5:counts::verified" => $anvil->data->{counts}{verified}, - "s6:verified" => $verified, - "s7:counts::lines" => $anvil->data->{counts}{lines}, - "s8:lines" => $lines, - }}); - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ">> job_status" => $job_status }}); - $job_status =~ s/message_0058,!!downloaded!.*?!!,!!installed!.*?!!,!!verified!.*?!!,!!lines!.*?!!/message_0058,!!downloaded!$downloaded!!,!!installed!$installed!!,!!verified!$verified!!,!!lines!$lines!!/sm; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< job_status" => $job_status }}); - } - - my $query = " -UPDATE - jobs -SET - job_picked_up_by = ".$anvil->data->{sys}{database}{use_handle}->quote($job_picked_up_by).", - job_picked_up_at = ".$anvil->data->{sys}{database}{use_handle}->quote($job_picked_up_at).", - job_updated = ".$anvil->data->{sys}{database}{use_handle}->quote(time).", - job_progress = ".$anvil->data->{sys}{database}{use_handle}->quote($progress).", - job_status = ".$anvil->data->{sys}{database}{use_handle}->quote($job_status).", - modified_date = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{sys}{database}{timestamp})." -WHERE - job_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->data->{jobs}{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__}); - - # Note this update time - $anvil->data->{sys}{last_update} = time; + $anvil->Job->update_progress({ + debug => 2, + progress => $progress, + message => $message, + job_uuid => $anvil->data->{jobs}{job_uuid}}, + ); } return(0);