* Created System->maintenance_mode to add "maintenance mode" support to Striker.

* Continuing work on adding the system update job support to Striker. Untested/Incomplete.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 6 years ago
parent 6aa74d3d96
commit fe33fbb239
  1. 6
      Anvil/Tools/Database.pm
  2. 78
      Anvil/Tools/System.pm
  3. 168
      cgi-bin/striker
  4. 16
      html/skins/alteeve/main.html
  5. 32
      html/skins/alteeve/striker.html
  6. 7
      share/words.xml
  7. 2
      tools/anvil-configure-striker
  8. 2
      tools/anvil.sql

@ -2439,7 +2439,7 @@ This is the command (usually a shell call) to run.
=head3 job_data (optional)
This is optional data used by C<< anvil-job >> when running a job.
This is used to pass information or store special progress data on a job.
=head3 job_description (required*)
@ -2461,11 +2461,11 @@ This is the C<< job_name >> to INSERT or UPDATE. If a C<< job_uuid >> is passed,
=head3 job_picked_up_at (optional)
When C<< anvil-jobs >> picks uup a job, it will record the (unix) time that it started.
When C<< anvil-daemon >> picks uup a job, it will record the (unix) time that it started.
=head3 job_picked_up_by (optional)
When C<< anvil-jobs >> picks up a job, it will record it's PID here.
When C<< anvil-daemon >> picks up a job, it will record it's PID here.
=head3 job_progress (required)

@ -24,6 +24,7 @@ my $THIS_FILE = "System.pm";
# get_ips
# hostname
# is_local
# maintenance_mode
# manage_firewall
# ping
# read_ssh_config
@ -876,6 +877,83 @@ sub is_local
return($is_local);
}
=head2 maintenance_mode
This sets, clears or checks if the local system is in maintenance mode. Any system in maintenance mode will not be used by normal Anvil! tasks.
This returns C<< 1 >> if maintenance mode is enabled and C<< 0 >> if disabled.
Parameters;
=head3 set (optional)
If this is set to C<< 1 >>, maintenance mode is enabled. If this is set to C<< 0 >>, maintenance mode is disabled.
=cut
sub maintenance_mode
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $set = defined $parameter->{set} ? $parameter->{set} : "";
if ($set)
{
# Am I enabling or disabling?
if ($set eq "1")
{
# Enabling
$anvil->Database->insert_or_update_variables({
variable_name => "maintenance_mode",
variable_value => "1",
variable_default => "0",
variable_description => "striker_0087",
variable_section => "system",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
update_value_only => 1,
});
}
elsif ($set eq "0")
{
# Disabling
$anvil->Database->insert_or_update_variables({
variable_name => "maintenance_mode",
variable_value => "0",
variable_default => "0",
variable_description => "striker_0087",
variable_section => "system",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
update_value_only => 1,
});
}
else
{
# Called with an invalid value.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "log_0197", variables => { set => $set }});
$set = "";
}
}
my ($maintenance_mode, $variable_uuid, $modified_date) = $anvil->Database->read_variable({debug => $debug, variable_name => "maintenance_mode"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
maintenance_mode => $maintenance_mode,
variable_uuid => $variable_uuid,
modified_date => $modified_date,
}});
if ($maintenance_mode eq "")
{
$maintenance_mode = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { maintenance_mode => $maintenance_mode }});
}
return($maintenance_mode);
}
=head2 manage_firewall
This method manages a firewalld firewall.

@ -63,7 +63,7 @@ if (not $anvil->data->{sys}{database}{connections})
# If any jobs are pending/running, show the "unavailable" option.
my $available = check_availability($anvil);
my $configured = $available ? check_if_configured($anvil) : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
available => $available,
configured => $configured,
}});
@ -195,7 +195,7 @@ sub process_task
# cookies were deleted (via C<< Account->logout() >>. The user needs to log back in.
# 3 - There user's hash is invalid, it is probably expired. The user has been logged out and
# needs to log back in.
my $cookie_problem = $anvil->Account->read_cookies({debug => 3});
my $cookie_problem = $anvil->Account->read_cookies({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { cookie_problem => $cookie_problem }});
if (not $cookie_problem)
{
@ -273,17 +273,31 @@ sub process_update
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{value};
if ($anvil->data->{cgi}{confirm}{value})
{
# Request the job and take the system offline until it's done.
# $anvil->Database->insert_or_update_variables({
# variable_name => "system::configured",
# variable_source_uuid => $anvil->Get->host_uuid,
# variable_source_table => "hosts",
# variable_value => 0,
# update_value_only => 1,
# });
# Record the job!
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
job_command => "anvil-update-system --uuid ".$anvil->Get->host_uuid,
job_data => "",
job_name => "update::system",
job_title => "job_0003",
job_description => "job_0004",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
# Done.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "update-requested"});
# 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
{
@ -699,7 +713,29 @@ sub configure_striker
elsif ($anvil->data->{cgi}{step}{value} eq "step3")
{
# User has confirmed, update the system!
$anvil->data->{form}{body} = save_job($anvil);
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
job_command => "anvil-configure-striker",
job_data => "form::config_step2",
job_name => "configure::network",
job_title => "job_0001",
job_description => "job_0002",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
# Set maintenance mode.
$anvil->System->maintenance_mode({debug => 2, set => 1});
# 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 => "network_job_recorded", variables => {
title_id => "",
message_id => "",
title => "#!string!striker_0044!#",
description => "#!string!striker_0045!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
}
else
{
@ -736,9 +772,17 @@ sub check_availability
{
my ($anvil) = @_;
my $debug = 3;
my $debug = 2;
my $available = 1;
my $query = "
# Set maintenance mode.
$available = $anvil->System->maintenance_mode({debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { available => $available }});
# TODO: Phase this out
if ($available)
{
my $query = "
SELECT
job_progress,
modified_date,
@ -752,78 +796,44 @@ AND
AND
job_host_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->Get->host_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 ($count)
{
# We're waiting for the network configuration
my $percent = $results->[0]->[0];
my $timestamp = $results->[0]->[1];
my $unixtime = $results->[0]->[2];
my $seconds_ago = $anvil->Convert->add_commas({number => (time - $unixtime)});
$available = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
available => $available,
percent => $percent,
seconds_ago => $seconds_ago,
timestamp => $timestamp,
unixtime => $unixtime,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->data->{say}{maintenance} = $anvil->Template->get({file => "striker.html", name => "striker-offline", variables => {
title_id => "",
message_id => "",
title => "#!string!striker_0046!#",
description => $anvil->Words->string({key => "striker_0047", variables => { percent => $percent, timestamp => $timestamp, seconds_ago => $seconds_ago }}),
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,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'say::maintenance' => $anvil->data->{say}{maintenance} }});
if ($count)
{
# We're waiting for the network configuration
my $percent = $results->[0]->[0];
my $timestamp = $results->[0]->[1];
my $unixtime = $results->[0]->[2];
my $seconds_ago = $anvil->Convert->add_commas({number => (time - $unixtime)});
$available = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
available => $available,
percent => $percent,
seconds_ago => $seconds_ago,
timestamp => $timestamp,
unixtime => $unixtime,
}});
$anvil->data->{say}{maintenance} = $anvil->Template->get({file => "striker.html", name => "striker-offline", variables => {
title_id => "",
message_id => "",
title => "#!string!striker_0046!#",
description => $anvil->Words->string({key => "striker_0047", variables => { percent => $percent, timestamp => $timestamp, seconds_ago => $seconds_ago }}),
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'say::maintenance' => $anvil->data->{say}{maintenance} }});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { available => $available }});
return($available);
}
# This requests the job to reconfigure the network be run
sub save_job
{
my ($anvil) = @_;
# Record the job!
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
job_command => "anvil-configure-striker",
job_data => "form::config_step2",
job_name => "configure::network",
job_title => "job_0001",
job_description => "job_0002",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
# TODO: Check that a job_uuid was returned and warn of a problem if not.
my $say_title = "#!string!striker_0044!#";
my $say_desciption = "#!string!striker_0045!#";
# We don't need to store anything as hidden variables, we'll read it back from the database later.
my $job_recorded_body = $anvil->Template->get({file => "main.html", name => "network_job_recorded", variables => {
title_id => "",
message_id => "",
title => $say_title,
description => $say_desciption,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { job_recorded_body => $job_recorded_body }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
return($job_recorded_body);
}
# This shows the user what is about to be done and asks the user to confirm.
sub config_step3
{

@ -177,22 +177,6 @@
</html>
<!-- end master -->
<!-- start network_job_recorded -->
<table>
<div id="network_job_recorded_div">
<tr>
<td>
<span name="#!variable!title_id!#" id="#!variable!title_id!#" class="config_header1">#!variable!title!#</span><br />
<span name="#!variable!message_id!#" id="#!variable!message_id!#" class="config_header2">#!variable!description!#</span>
<br />
<hr>
<a href="/" class="button">Reload</a>
</td>
</tr>
</div>
</table>
<!-- end network_job_recorded -->
<!-- start refresh_button_off -->
<img src="#!data!skin::url!#/images/refresh_off.png" class="top_icon">
<!-- end refresh_button_off -->

@ -447,3 +447,35 @@
</tr>
</table>
<!-- end striker-welcome -->
<!-- start network_job_recorded -->
<table>
<div id="network_job_recorded_div">
<tr>
<td>
<span name="#!variable!title_id!#" id="#!variable!title_id!#" class="config_header1">#!variable!title!#</span><br />
<span name="#!variable!message_id!#" id="#!variable!message_id!#" class="config_header2">#!variable!description!#</span>
<br />
<hr>
<a href="/" class="button">Reload</a>
</td>
</tr>
</div>
</table>
<!-- end network_job_recorded -->
<!-- start system_update_recorded -->
<table>
<div id="system_update_recorded_div">
<tr>
<td>
<span name="#!variable!title_id!#" id="#!variable!title_id!#" class="config_header1">#!variable!title!#</span><br />
<span name="#!variable!message_id!#" id="#!variable!message_id!#" class="config_header2">#!variable!description!#</span>
<br />
<hr>
<a href="/" class="button">Reload</a>
</td>
</tr>
</div>
</table>
<!-- end system_update_recorded -->

@ -280,7 +280,7 @@ The database connection error was:
<key name="log_0179">The user has been logged out.</key>
<key name="log_0180">The user hash in the user's cookie is valid.</key>
<key name="log_0181">The user hash in the user's cookie was valid yesterday, updating the stored hash and allowing the user to proceed.</key>
<key name="log_0182">The user hash in the user's coolkie is invalid. It is probably expired.</key>
<key name="log_0182">The user hash in the user's cookie is invalid. It is probably expired.</key>
<key name="log_0183">The user: [#!variable!user!#] logged in successfully.</key>
<key name="log_0184">Theew was a failed login attempt from: [#!variable!user_agent!#], trying to log in as: [#!variable!user!#]. log in rejected.</key>
<key name="log_0185"><![CDATA[<unknown>]]></key> <!-- Used in some cases when a variable isn't known -->
@ -295,6 +295,7 @@ The database connection error was:
<key name="log_0194">Switching the default database to read from to the database: [#!variable!server!#] prior to reconnect attempt.</key>
<key name="log_0195">Ready to try to reconnect to: [#!variable!server!#], but delaying for: [#!variable!delay!#] seconds to give the database a chance to come back online in case this is a transient issue.</key>
<key name="log_0196">Failed to reconnect to the database, and now no connections remail. Exiting.</key>
<key name="log_0197"><![CDATA[System->maintenance_mode() was passed an invalid 'set' value: [#!variable!set!#]. No action taken.]]></key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key>
@ -420,10 +421,14 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st
<key name="striker_0084">Confirmed</key>
<key name="striker_0085">This Striker has been marked as reconfigured. Reload to start the confguration process.</key>
<key name="striker_0086">Would you like to update the operating system on this machine? This Striker will be placed into maintenance mode until the update completes.</key>
<key name="striker_0087">When enabled on a Striker dashboard, the web interface will be disabled and ScanCore will not record to the local database. When enabled on a node, no servers will be allowed to run on it, and any already running on it will be migrated. When run on a DR node, that node will be disconnected from storage and no servers will be allowed to run on it. When disabled, all normal functions are available</key>
<key name="striker_0088">The system will be updated momentarily. This system will now be in maintenance mode until the update is complete.</key>
<!-- Strings used by jobs -->
<key name="job_0001">Configure Network</key>
<key name="job_0002">The network configuration will be updated based on the variables stored in the database. Reconnecting to the machine using the new IP address may be required.</key>
<key name="job_0003">Update Striker</key>
<key name="job_0004">This system is now scheduled to be updated.</key>
<!-- Warnings -->
<key name="striker_warning_0001">The IP address will change. You will need to reconnect after applying these changes.</key>

@ -78,6 +78,8 @@ $anvil->Database->insert_or_update_variables({
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
# Clear maintenance mode.
$anvil->System->maintenance_mode({debug => 2, set => 0});
### TODO: This is only until we can get the damn networking stable on reconfigure.
if (not $anvil->data->{switches}{'no-reboot'})

@ -357,7 +357,7 @@ CREATE TABLE jobs (
job_uuid uuid not null primary key, --
job_host_uuid uuid not null, -- This is the host that requested the job
job_command text not null, -- This is the command to run (usually a shell call).
job_data text not null, --
job_data text not null, -- A job can optionally use this to store miscellaneous data that doesn't belong elsewhere
job_picked_up_by numeric not null default 0, -- This is the PID of the 'anvil-jobs' script that picked up the job.
job_picked_up_at numeric not null default 0, -- This is unix timestamp of when the job was picked up.
job_updated numeric not null default 0, -- This is unix timestamp that is perdiodically updated for jobs that take a long time. It is used to help determine when a job is hung.

Loading…
Cancel
Save