* Started work on anvil-safe-start. The enable/disable logic and how it runs automatically is controlled by the database and the tool can be used to control anvil-safe-start on both the local and peer node. It will be started by ScanCore, if scancore starts within 10 minutes of the node booting. It will always be able to run manually.
Signed-off-by: Digimer <digimer@alteeve.ca>main
parent
75343aadff
commit
15e71768a1
4 changed files with 281 additions and 0 deletions
@ -0,0 +1,258 @@ |
||||
#!/usr/bin/perl |
||||
# |
||||
# This does boot-time sanity checks on nodes and then, if all is well, joins the cluster and boots servers. |
||||
# |
||||
# NOTE: Unlike M2, this is controlled by scancore's start, but only if scancore starts up within ten minutes |
||||
# of the node itself booting. This way, stopping/starting scancore won't call us repeatedly. This tool |
||||
# is enabled or disabled via the 'tool::anvil-safe-start::enabled' variable tied to the 'hosts' -> |
||||
# 'host_uuid' table. |
||||
# |
||||
# Exit codes; |
||||
# 0 = Normal exit. |
||||
# 1 = Any problem that causes an early exit. |
||||
# |
||||
# TODO: |
||||
# - Make this work on DR hosts. |
||||
# |
||||
|
||||
use strict; |
||||
use warnings; |
||||
use Anvil::Tools; |
||||
require POSIX; |
||||
|
||||
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; |
||||
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; |
||||
if (($running_directory =~ /^\./) && ($ENV{PWD})) |
||||
{ |
||||
$running_directory =~ s/^\./$ENV{PWD}/; |
||||
} |
||||
|
||||
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. |
||||
$| = 1; |
||||
|
||||
my $anvil = Anvil::Tools->new(); |
||||
$anvil->Get->switches; |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); |
||||
|
||||
# Make sure we're running as 'root' |
||||
# $< == real UID, $> == effective UID |
||||
if (($< != 0) && ($> != 0)) |
||||
{ |
||||
# Not root |
||||
print $anvil->Words->string({key => "error_0005"})."\n"; |
||||
$anvil->nice_exit({exit_code => 1}); |
||||
} |
||||
|
||||
# Connect to the database(s). If we have no connections, we'll proceed anyway as one of the 'run_once' tasks |
||||
# is to setup the database server. |
||||
$anvil->Database->connect(); |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); |
||||
|
||||
$anvil->data->{switches}{disable} = ""; |
||||
$anvil->data->{switches}{enable} = ""; |
||||
$anvil->data->{switches}{force} = ""; |
||||
$anvil->data->{switches}{'local'} = ""; |
||||
$anvil->data->{switches}{status} = ""; |
||||
$anvil->Get->switches; |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); |
||||
|
||||
|
||||
# If I have no databases, sleep until I do |
||||
if (not $anvil->data->{sys}{database}{connections}) |
||||
{ |
||||
# If this is a dashboard, try to configure and then connect to the local database. If this isn't a |
||||
# Wait until we have one. |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, secure => 0, key => "error_0075"}); |
||||
|
||||
until($anvil->data->{sys}{database}{connections}) |
||||
{ |
||||
sleep 10; |
||||
|
||||
$anvil->refresh(); |
||||
$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}) |
||||
{ |
||||
# Keep waiting |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 3, secure => 0, key => "log_0439"}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
# Check to see if we should run. Also checks/sets enable/disable requests. |
||||
prerun_checks($anvil); |
||||
|
||||
$anvil->nice_exit({exit_code => 0}); |
||||
|
||||
############################################################################################################# |
||||
# Functions # |
||||
############################################################################################################# |
||||
|
||||
# This checks to verify that we're a node, and if so, if this tool is enabled. If it's disabled or this isn't |
||||
# a node, this method will exit. |
||||
sub prerun_checks |
||||
{ |
||||
my ($anvil) = @_; |
||||
|
||||
$anvil->Database->get_hosts(); |
||||
$anvil->Database->get_anvils(); |
||||
|
||||
my $host_uuid = $anvil->Get->host_uuid(); |
||||
my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type}; |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
||||
host_uuid => $host_uuid, |
||||
host_type => $host_type, |
||||
}}); |
||||
|
||||
if ($host_type ne "node") |
||||
{ |
||||
# We're done. |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0598"}); |
||||
$anvil->nice_exit({exit_code => 0}); |
||||
} |
||||
|
||||
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid(); |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }}); |
||||
|
||||
if (not $anvil_uuid) |
||||
{ |
||||
# This is a node, but not in an Anvil! yet. |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0603"}); |
||||
$anvil->nice_exit({exit_code => 0}); |
||||
} |
||||
|
||||
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; |
||||
my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; |
||||
my $peer_host_uuid = $host_uuid eq $node1_host_uuid ? $node2_host_uuid : $node1_host_uuid; |
||||
|
||||
# Are we being asked to enable or disable? |
||||
my $nodes = [$host_uuid]; |
||||
my $set_to = 1; |
||||
my $message = ""; |
||||
if ($anvil->data->{switches}{enable}) |
||||
{ |
||||
# We're enabling, which message will we use? |
||||
$message = $anvil->data->{switches}{'local'} ? "log_0599" : "log_0600"; |
||||
} |
||||
elsif ($anvil->data->{switches}{disable}) |
||||
{ |
||||
# We're disabling. Which message? |
||||
$set_to = 0; |
||||
$message = $anvil->data->{switches}{'local'} ? "log_0601" : "log_0602"; |
||||
} |
||||
|
||||
# If we're updating the settings, do so and then exit. |
||||
if ($message) |
||||
{ |
||||
if (not $anvil->data->{switches}{'local'}) |
||||
{ |
||||
# Add our peer as well. |
||||
push @{$nodes}, $peer_host_uuid; |
||||
} |
||||
foreach my $host_uuid (@{$nodes}) |
||||
{ |
||||
my ($variable_uuid) = $anvil->Database->insert_or_update_variables({ |
||||
debug => 2, |
||||
variable_name => "tool::anvil-safe-start::enabled", |
||||
variable_value => $set_to, |
||||
variable_default => 1, |
||||
variable_description => "striker_0286", |
||||
variable_section => "system", |
||||
variable_source_uuid => $host_uuid, |
||||
variable_source_table => "hosts", |
||||
}); |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); |
||||
} |
||||
|
||||
# Record that it's been enabled. |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => $message}); |
||||
$anvil->nice_exit({exit_code => 0}); |
||||
} |
||||
|
||||
# Read my variables. |
||||
my ($local_enabled, $variable_uuid, $mtime, $modified_date) = $anvil->Database->read_variable({ |
||||
debug => 2, |
||||
variable_name => "tool::anvil-safe-start::enabled", |
||||
variable_source_table => "hosts", |
||||
variable_source_uuid => $host_uuid, |
||||
}); |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
||||
local_enabled => $local_enabled, |
||||
variable_uuid => $variable_uuid, |
||||
}}); |
||||
# No UUID means the value hasn't been recorded, so we default to 1. |
||||
if (not $variable_uuid) |
||||
{ |
||||
$local_enabled = 1; |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_enabled => $local_enabled }}); |
||||
} |
||||
|
||||
# Have we just been asked for the status? |
||||
if ($anvil->data->{switches}{status}) |
||||
{ |
||||
# Yes, check our peer as well. |
||||
my ($peer_enabled, $variable_uuid, $mtime, $modified_date) = $anvil->Database->read_variable({ |
||||
variable_name => "tool::anvil-safe-start::enabled", |
||||
variable_source_table => "hosts", |
||||
variable_source_uuid => $peer_host_uuid, |
||||
}); |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
||||
peer_enabled => $peer_enabled, |
||||
variable_uuid => $variable_uuid, |
||||
}}); |
||||
# No UUID means the value hasn't been recorded, so we default to 1. |
||||
if (not $variable_uuid) |
||||
{ |
||||
$peer_enabled = 1; |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_enabled => $peer_enabled }}); |
||||
} |
||||
|
||||
# What we tell the use slightly depends on which nodes are enabled. |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
||||
local_enabled => $local_enabled, |
||||
peer_enabled => $peer_enabled, |
||||
}}); |
||||
|
||||
my $message = ""; |
||||
if (($local_enabled) && ($peer_enabled)) |
||||
{ |
||||
# Both nodes are enabled. |
||||
$message = "message_0227"; |
||||
} |
||||
elsif ((not $local_enabled) && (not $peer_enabled)) |
||||
{ |
||||
# Both nodes are disabled |
||||
$message = "message_0228"; |
||||
} |
||||
elsif ($local_enabled) |
||||
{ |
||||
# We're enabled, the peer is disabled. |
||||
$message = "message_0229"; |
||||
} |
||||
else |
||||
{ |
||||
# We're disabled, the peer is enabled. |
||||
$message = "message_0230"; |
||||
} |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => $message}); |
||||
$anvil->nice_exit({exit_code => 0}); |
||||
} |
||||
|
||||
if (not $local_enabled) |
||||
{ |
||||
# Disabled. Forced? |
||||
if ($anvil->data->{switches}{force}) |
||||
{ |
||||
# Forced, run anyway. |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0232"}); |
||||
} |
||||
else |
||||
{ |
||||
# Exit. |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0231"}); |
||||
$anvil->nice_exit({exit_code => 0}); |
||||
} |
||||
} |
||||
|
||||
return(0); |
||||
} |
Loading…
Reference in new issue