Merge branch 'main' into minor-fixes-20210827

main
digimer-bot 3 years ago committed by GitHub
commit 4f6bdd739e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      Anvil/Tools.pm
  2. 10
      Anvil/Tools/Account.pm
  3. 5
      Anvil/Tools/Alert.pm
  4. 7
      Anvil/Tools/Convert.pm
  5. 113
      Anvil/Tools/DRBD.pm
  6. 268
      Anvil/Tools/Database.pm
  7. 89
      Anvil/Tools/Get.pm
  8. 18
      Anvil/Tools/Network.pm
  9. 244
      Anvil/Tools/ScanCore.pm
  10. 69
      Anvil/Tools/Server.pm
  11. 17
      Anvil/Tools/Storage.pm
  12. 196
      Anvil/Tools/System.pm
  13. 5
      anvil.conf
  14. 11
      anvil.spec.in
  15. 22
      cgi-bin/striker
  16. 4
      configure.ac
  17. 172
      notes
  18. 4
      scancore-agents/scan-apc-ups/scan-apc-ups
  19. 2
      scancore-agents/scan-cluster/scan-cluster
  20. 342
      scancore-agents/scan-network/scan-network
  21. 52
      share/words.xml
  22. 200
      striker-ui/package-lock.json
  23. 2
      striker-ui/package.json
  24. 2
      tools/Makefile.am
  25. 16
      tools/anvil-boot-server
  26. 6
      tools/anvil-check-memory
  27. 208
      tools/anvil-daemon
  28. 2
      tools/anvil-join-anvil
  29. 3
      tools/anvil-manage-power
  30. 8
      tools/anvil-manage-server
  31. 45
      tools/anvil-safe-start
  32. 2
      tools/anvil-safe-stop
  33. 2
      tools/anvil-sync-shared
  34. 15
      tools/anvil-update-states
  35. 3
      tools/anvil-update-system
  36. 38
      tools/scancore
  37. 2
      tools/striker-auto-initialize-all
  38. 381
      tools/striker-db-report
  39. 318
      tools/striker-file-manager
  40. 2
      tools/striker-get-peer-data
  41. 2
      tools/striker-manage-install-target
  42. 292
      tools/striker-prep-database
  43. 1
      units/anvil-daemon.service

@ -1102,6 +1102,7 @@ sub _set_paths
units => "/usr/lib/systemd/system",
},
exe => {
akmods => "/usr/sbin/akmods",
'alteeve-repo-setup' => "/usr/sbin/alteeve-repo-setup",
'anvil-boot-server' => "/usr/sbin/anvil-boot-server",
'anvil-change-password' => "/usr/sbin/anvil-change-password",
@ -1197,6 +1198,7 @@ sub _set_paths
md5sum => "/usr/bin/md5sum",
'mkdir' => "/usr/bin/mkdir",
modifyrepo_c => "/usr/bin/modifyrepo_c",
modprobe => "/usr/sbin/modprobe",
mv => "/usr/bin/mv",
nmap => "/usr/bin/nmap",
nmcli => "/bin/nmcli",
@ -1244,6 +1246,7 @@ sub _set_paths
su => "/usr/bin/su",
'subscription-manager' => "/usr/sbin/subscription-manager",
swapon => "/usr/sbin/swapon",
sysctl => "/usr/sbin/sysctl",
systemctl => "/usr/bin/systemctl",
timeout => "/usr/bin/timeout",
touch => "/usr/bin/touch",

@ -451,7 +451,8 @@ AND
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({debug => $debug, query => $query, source => $THIS_FILE, line => __LINE__});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0198", variables => { user => $anvil->data->{cgi}{username}{value} }});
my $user = $anvil->data->{cgi}{username}{value} ? $anvil->data->{cgi}{username}{value} : "--";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0198", variables => { user => $user }});
# Log that they're out
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0179"});
@ -573,7 +574,7 @@ AND
$anvil->data->{sys}{users}{user_name} = $results->[0]->[0];
$anvil->data->{sessions}{session_salt} = $results->[0]->[1];
$anvil->data->{sessions}{session_salt} = "" if not defined $anvil->data->{sessions}{session_salt};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::users::user_name" => $anvil->data->{sys}{users}{user_name},
"sessions::session_salt" => $anvil->data->{sessions}{session_salt},
}});
@ -592,8 +593,9 @@ AND
offset => -86400,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
today_hash => $today_hash,
yesterday_hash => $yesterday_hash,
"s1:cookie::anvil_user_hash" => $anvil->data->{cookie}{anvil_user_hash},
"s2:today_hash" => $today_hash,
"s3:yesterday_hash" => $yesterday_hash,
}});
# See if either hash matches what the user has stored.

@ -295,6 +295,7 @@ sub check_condition_age
# See if this variable has been set yet.
my ($variable_value, $variable_uuid, $epoch_modified_date, $modified_date) = $anvil->Database->read_variable({
debug => $debug,
variable_name => $name,
variable_source_table => $source_table,
variable_source_uuid => $host_uuid,
@ -319,8 +320,8 @@ sub check_condition_age
});
}
# if the value was 'clear', change it to 'set'.
if ($variable_value eq "clear")
# if the 'clear' parameter isn't set, and the value is 'clear', change it to 'set'.
if (($variable_value eq "clear") && (not $clear))
{
# Set it.
$variable_uuid = $anvil->Database->insert_or_update_variables({

@ -848,6 +848,12 @@ sub format_mmddyy_to_yymmdd
date => $date,
}});
# Sometimes we're passed '--' or '#!no_value!#' which is not strictly an error, so we'll return it back.
if (($date eq "--") or ($date eq "#!no_value!#"))
{
return($date);
}
if (not $date)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Convert->format_mmddyy_to_yymmdd()", parameter => "host_name" }});
@ -905,7 +911,6 @@ sub host_name_to_ip
}
### TODO: Check local cached information later.
# Try to resolve it using 'gethostip'.
my $shell_call = $anvil->data->{path}{exe}{gethostip}." -d ".$host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});

@ -26,6 +26,7 @@ my $THIS_FILE = "DRBD.pm";
# reload_defaults
# resource_uuid
# update_global_common
# _initialize_kmod
#
=pod
@ -1835,6 +1836,7 @@ sub get_status
return(0);
}
=head2 manage_resource
This takes a task, C<< up >>, C<< down >>, C<< primary >>, or C<< secondary >> and a resource name and acts on the request.
@ -3029,3 +3031,114 @@ sub update_global_common
#############################################################################################################
# Private functions #
#############################################################################################################
=head2 _initialize_kmod
This checks to see if the C<< drbd >> kernel module can load. If not, a check is made to see if an RPM that matches the kernel exists. If so, it is installed. If not, C<< akmods >> is asked to build and install the drbd kernel module.
Returns C<< 0 >> is the module loads or is already loaded. C<< !!error!! >> if not.
=cut
sub _initialize_kmod
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "DRBD->_initialize_kmod()" }});
my $kernel_release = $anvil->Get->kernel_release({debug => $debug});
my $shell_call = $anvil->data->{path}{exe}{modprobe}." drbd";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
kernel_release => $kernel_release,
shell_call => $shell_call,
}});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
if (not $return_code)
{
# Loaded fine
return(0);
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0676"});
my $install = 0;
my $shell_call = $anvil->data->{path}{exe}{dnf}." -q search kmod-drbd-".$kernel_release;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
foreach my $line (split/\n/, $output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /Name Exactly/)
{
# We can install.
$install = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { install => $install }});
last;
}
}
# Install or build?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { install => $install }});
if ($install)
{
### TODO: Should this be a background process?
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0677"});
my $shell_call = $anvil->data->{path}{exe}{dnf}." -y install kmod-drbd-".$kernel_release;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0678"});
my $shell_call = $anvil->data->{path}{exe}{akmods}." --force";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
}
# In either case, try again.
$output = undef;
$return_code = undef;
$shell_call = $anvil->data->{path}{exe}{modprobe}." drbd";
($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
if (not $return_code)
{
# Loaded fine
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0679"});
return(0);
}
else
{
# Failed
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "warning_0132"});
}
}
return('!!error!!');
}

@ -93,6 +93,7 @@ my $THIS_FILE = "Database.pm";
# resync_databases
# update_host_status
# write
# _add_to_local_config
# _age_out_data
# _archive_table
# _find_column
@ -778,6 +779,7 @@ If the method completes, C<< 0 >> is returned. If this method is called without
This method takes no parameters.
=cut
### TODO: Much of this logic is in striker-prep-database, consolidate!
sub configure_pgsql
{
my $self = shift;
@ -799,6 +801,23 @@ sub configure_pgsql
return(1);
}
# Make sure we have an entry in our own anvil.conf.
my $local_uuid = $anvil->Database->get_local_uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_uuid => $local_uuid }});
# If we didn't get the $local_uuid, then there is no entry for this system in anvil.conf yet, so we'll add it.
if (not $local_uuid)
{
$local_uuid = $anvil->Database->_add_to_local_config({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_uuid => $local_uuid }});
if ($local_uuid eq "!!error!!")
{
# Already logged the error, return.
return('!!error!!');
}
}
# First, is it running and is it initialized?
my $initialized = 0;
my $running = $anvil->System->check_daemon({debug => $debug, daemon => $anvil->data->{sys}{daemon}{postgresql}});
@ -806,7 +825,7 @@ sub configure_pgsql
if (not -e $anvil->data->{path}{configs}{'pg_hba.conf'})
{
# Initialize. Record that we did so, so that we know to start the daemon.
my ($output, $return_code) = $anvil->System->call({debug => 1, shell_call => $anvil->data->{path}{exe}{'postgresql-setup'}." initdb", source => $THIS_FILE, line => __LINE__});
my ($output, $return_code) = $anvil->System->call({debug => 1, shell_call => $anvil->data->{path}{exe}{'postgresql-setup'}." --initdb --unit postgresql", source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { output => $output, return_code => $return_code }});
# Did it succeed?
@ -933,14 +952,20 @@ sub configure_pgsql
}
# Start or restart the daemon?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:running' => $running,
's2:update_postgresql_file' => $update_postgresql_file,
's3:update_pg_hba_file' => $update_pg_hba_file,
}});
if (not $running)
{
# Did we initialize?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { initialized => $initialized }});
if ($initialized)
{
# Start the daemon.
my $return_code = $anvil->System->start_daemon({daemon => $anvil->data->{sys}{daemon}{postgresql}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { return_code => $return_code }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { return_code => $return_code }});
if ($return_code eq "0")
{
# Started the daemon.
@ -958,7 +983,7 @@ sub configure_pgsql
{
# Reload
my $return_code = $anvil->System->start_daemon({daemon => $anvil->data->{sys}{daemon}{postgresql}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { return_code => $return_code }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { return_code => $return_code }});
if ($return_code eq "0")
{
# Reloaded the daemon.
@ -972,6 +997,11 @@ sub configure_pgsql
}
# Do user and DB checks only if we're made a change above.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:initialized' => $initialized,
's2:update_postgresql_file' => $update_postgresql_file,
's3:update_pg_hba_file' => $update_pg_hba_file,
}});
if (($initialized) or ($update_postgresql_file) or ($update_pg_hba_file))
{
# Create the .pgpass file, if needed.
@ -1321,12 +1351,14 @@ sub connect
# If we're a Striker, see if we're configured.
my $local_host_type = $anvil->Get->host_type();
my $local_host_uuid = $anvil->Get->host_uuid();
my $db_count = keys %{$anvil->data->{database}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
local_host_type => $local_host_type,
local_host_uuid => $local_host_uuid,
check_if_configured => $check_if_configured,
real_uid => $<,
effective_uid => $>,
db_count => $db_count,
}});
# If requested, and if running with root access, set it up (or update it) if needed.
# This method just returns if nothing is needed.
@ -1347,15 +1379,18 @@ sub connect
if (($db_uuid) && ($db_uuid ne $uuid))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0191", variables => { db_uuid => $db_uuid, uuid => $uuid }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0191", variables => {
db_uuid => $db_uuid,
uuid => $uuid,
}});
next;
}
# Make sure values are set.
$anvil->data->{database}{$uuid}{port} = 5432 if not $anvil->data->{database}{$uuid}{port};
$anvil->data->{database}{$uuid}{name} = $anvil->data->{sys}{database}{name} if not $anvil->data->{database}{$uuid}{name};
$anvil->data->{database}{$uuid}{user} = $anvil->data->{sys}{database}{user} if not $anvil->data->{database}{$uuid}{user};
$anvil->data->{database}{$uuid}{password} = "" if not defined $anvil->data->{database}{$uuid}{password};
$anvil->data->{database}{$uuid}{port} = 5432 if not defined $anvil->data->{database}{$uuid}{port};
$anvil->data->{database}{$uuid}{name} = "anvil" if not $anvil->data->{database}{$uuid}{name};
$anvil->data->{database}{$uuid}{user} = "admin" if not $anvil->data->{database}{$uuid}{user};
$anvil->data->{database}{$uuid}{password} = "" if not defined $anvil->data->{database}{$uuid}{password};
my $driver = "DBI:Pg";
my $host = $anvil->data->{database}{$uuid}{host}; # This should fail if not set
@ -1371,6 +1406,13 @@ sub connect
password => $anvil->Log->is_secure($password),
}});
# If there's no password, skip.
if (not $password)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0668", variables => { uuid => $uuid }});
next;
}
# Some places will want to pull up the database user, so in case it isn't set (which is
# usual), set it as if we had read it from the config file using the default.
if (not $anvil->data->{database}{$uuid}{name})
@ -1708,7 +1750,7 @@ sub connect
}
# If we're a striker and no connections were found, start our database.
if (($local_host_type eq "striker") && (not $anvil->data->{sys}{database}{connections}))
if (($local_host_type eq "striker") && (not $anvil->data->{sys}{database}{connections}) && ($db_count > 1))
{
# Tell the user we're going to try to load and start.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0650"});
@ -12031,7 +12073,20 @@ sub insert_or_update_states
# If we were passed a database UUID, check for the open handle.
if ($uuid)
{
$anvil->data->{cache}{database_handle}{$uuid} = "" if not defined $anvil->data->{cache}{database_handle}{$uuid};
if ((not defined $anvil->data->{cache}{database_handle}{$uuid}) or (not $anvil->data->{cache}{database_handle}{$uuid}))
{
# Switch to another UUID
foreach my $this_uuid (keys %{$anvil->data->{cache}{database_handle}})
{
if ($anvil->data->{cache}{database_handle}{$this_uuid})
{
# Switch to this UUID
$uuid = $this_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }});
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"cache::database_handle::${uuid}" => $anvil->data->{cache}{database_handle}{$uuid},
}});
@ -15300,9 +15355,26 @@ sub query
}
elsif (not defined $anvil->data->{cache}{database_handle}{$uuid})
{
# Database handle is gone.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0073", variables => { uuid => $uuid }});
return("!!error!!");
# Database handle is gone. Switch to the read_uuid
my $old_uuid = $uuid;
$uuid = $anvil->data->{sys}{database}{read_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_uuid => $old_uuid,
uuid => $uuid,
}});
if (not defined $anvil->data->{cache}{database_handle}{$uuid})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0073", variables => { uuid => $uuid }});
return("!!error!!");
}
else
{
# Warn that we switched.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "log_0073", variables => {
old_uuid => $old_uuid,
new_uuid => $uuid,
}});
}
}
if (not $query)
{
@ -15332,12 +15404,29 @@ sub query
}
# Do the query.
my $DBreq = $anvil->data->{cache}{database_handle}{$uuid}->prepare($query) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0075", variables => {
local $@;
my $DBreq = eval { $anvil->data->{cache}{database_handle}{$uuid}->prepare($query) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0075", variables => {
query => (not $secure) ? $query : $anvil->Log->is_secure($query),
server => $say_server,
db_error => $DBI::errstr,
}}); };
if ($@)
{
### TODO: Report back somehow that the handle is dead.
$anvil->Database->disconnect({debug => $debug});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0675", variables => {
query => (not $secure) ? $query : $anvil->Log->is_secure($query),
server => $say_server,
eval_error => $@,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { DBreq => $DBreq }});
return("!!error!!");
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
query => (not $secure) ? $query : $anvil->Log->is_secure($query),
say_server => $say_server,
DBreq => $DBreq,
}});
# Execute on the query
$DBreq->execute() or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0076", variables => {
@ -15562,9 +15651,10 @@ sub refresh_timestamp
my $parameter = shift;
my $anvil = $self->parent;
my $query = "SELECT cast(now() AS timestamp with time zone);";
$anvil->data->{sys}{database}{timestamp} = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
my $query = "SELECT cast(now() AS timestamp with time zone);";
my $new_time = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->data->{sys}{database}{timestamp} = $new_time;
return($anvil->data->{sys}{database}{timestamp});
}
@ -15601,10 +15691,33 @@ sub resync_databases
return(0);
}
# If we're not a striker, don't resync ever.
my $host_type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
if ($host_type ne "striker")
{
# Not a dashboard, don't resync
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0686"});
return(1);
}
# If we're hosting servers, don't resync. Too high of a risk of oom-killer being triggered.
my $server_count = $anvil->Server->count_servers({debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_count => $server_count }});
if ($server_count)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0680", variables => { count => $server_count }});
return(0);
}
# Before resync, age out the data in each DB
$anvil->Database->_age_out_data({debug => $debug});
### NOTE: Don't sort this array, we need to resync in the order that the user passed the tables to us
### to avoid trouble with primary/foreign keys.
# We're going to use the array of tables assembles by _find_behind_databases() stored in
# 'sys::database::check_tables'
my $start_time = time;
foreach my $table (@{$anvil->data->{sys}{database}{check_tables}})
{
# We don't sync 'states' as it's transient and sometimes per-DB.
@ -16055,6 +16168,10 @@ sub resync_databases
$anvil->data->{sys}{database}{resync_needed} = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'sys::database::resync_needed' => $anvil->data->{sys}{database}{resync_needed} }});
my $time_taken = time - $start_time;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { time_taken => $time_taken }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0674", variables => { took => $time_taken }});
return(0);
}
@ -16372,6 +16489,77 @@ sub write
# Private functions #
#############################################################################################################
=head2 _add_to_local_config
This adds this machine to the local C<< /etc/anvil/anvil.conf >> file.
If successful, the host's UUID will be returned. If there's a problem, C<< !!error!! >> will be returned.
=cut
sub _add_to_local_config
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->_add_to_local_config()" }});
my $host_uuid = $anvil->Get->host_uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
if ((not exists $anvil->data->{database}{$host_uuid}{password}) or (not $anvil->data->{database}{$host_uuid}{password}))
{
# Use the default password used in kickstart scripts.
$anvil->data->{database}{$host_uuid}{password} = $anvil->data->{defaults}{kickstart}{password};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, secure => 1, level => $debug, list => {
"database::${host_uuid}::password" => $anvil->data->{database}{$host_uuid}{password},
}});
}
# Write the password to a file.
my $password_file = "/tmp/striker-manage-peers.".$anvil->Get->uuid;
$anvil->Storage->write_file({
debug => $debug,
secure => 1,
file => $password_file,
body => $anvil->data->{database}{$host_uuid}{password},
mode => "0600",
overwrite => 1,
});
# Make the shell call, and parse the output looking for our own entry
my $shell_call = $anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$anvil->Get->host_uuid." --host localhost --port 5432 --password-file ".$password_file." --ping 0".$anvil->Log->switches;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid,
shell_call => $shell_call,
}});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
# Remove the password.
unlink $password_file;
# Re-read the config and make sure we have our own entry.
$anvil->refresh();
# If we still don't have a local_uuid, something went wrong.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"database::${host_uuid}::host" => $anvil->data->{database}{$host_uuid}{host},
"database::${host_uuid}::port" => $anvil->data->{database}{$host_uuid}{port},
"database::${host_uuid}::password" => $anvil->Log->is_secure($anvil->data->{database}{$host_uuid}{password}),
"database::${host_uuid}::ping" => $anvil->data->{database}{$host_uuid}{ping},
}});
if (not $anvil->data->{database}{$host_uuid}{host})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0010"});
return('!!error!!');
}
return($host_uuid);
}
=head2 _age_out_data
@ -16513,10 +16701,12 @@ sub _age_out_data
# We don't use 'anvil->data' to prevent injecting SQL queries in anvil.conf
my $to_clean = {};
# Power, temperatures and ip addresses
$to_clean->{table}{temperature}{child_table}{temperature}{uuid_column} = "temperature_uuid";
$to_clean->{table}{power}{child_table}{power}{uuid_column} = "power_uuid";
$to_clean->{table}{ip_addresses}{child_table}{ip_addresses}{uuid_column} = "ip_address_uuid";
# Power, temperatures, ip addresses and variables
$to_clean->{table}{temperature}{child_table}{temperature}{uuid_column} = "temperature_uuid";
$to_clean->{table}{power}{child_table}{power}{uuid_column} = "power_uuid";
$to_clean->{table}{ip_addresses}{child_table}{ip_addresses}{uuid_column} = "ip_address_uuid";
$to_clean->{table}{variables}{child_table}{variables}{uuid_column} = "variable_uuid";
$to_clean->{table}{network_interfaces}{child_table}{network_interfaces}{uuid_column} = "network_interface_uuid";
# scan_apc_pdu
$to_clean->{table}{scan_apc_pdus}{child_table}{scan_apc_pdu_phases}{uuid_column} = "scan_apc_pdu_phase_uuid";
@ -16549,7 +16739,7 @@ sub _age_out_data
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { table => $table }});
# Does the table exist?
$query = "SELECT COUNT(*) FROM pg_catalog.pg_tables WHERE tablename='scan_apc_pdus' AND schemaname='public';";
$query = "SELECT COUNT(*) FROM pg_catalog.pg_tables WHERE tablename=".$anvil->Database->quote($table)." AND schemaname='public';";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
@ -16596,7 +16786,7 @@ sub _age_out_data
count => $count,
}});
if ($count)
if ($count > 1)
{
# Find how many records will be left. If it's 0, we'll use an OFFSET 1.
my $query = "SELECT history_id FROM history.".$child_table." WHERE ".$uuid_column." = ".$anvil->Database->quote($column_uuid)." AND modified_date > '".$old_timestamp."';";
@ -16617,16 +16807,17 @@ sub _age_out_data
}
else
{
# This would delete everything, reserve at least one record.
foreach my $row (@{$results})
{
my $history_id = $row->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { history_id => $history_id }});
# This would delete everything, reserve at
# least one record.
my $query = "SELECT history_id FROM history.".$child_table." WHERE ".$uuid_column." = ".$anvil->Database->quote($column_uuid)." ORDER BY modified_date DESC LIMIT 1;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $query = "DELETE FROM history.".$child_table." WHERE ".$uuid_column." = ".$anvil->Database->quote($column_uuid)." AND history_id = '".$history_id."';";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
push @{$queries}, $query;
}
my $history_id = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }});
$query = "DELETE FROM history.".$child_table." WHERE ".$uuid_column." = ".$anvil->Database->quote($column_uuid)." AND modified_date <= '".$old_timestamp."' AND history_id != '".$history_id."';";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
push @{$queries}, $query;
}
}
}
@ -17391,6 +17582,8 @@ This method takes a database UUID and tests the connection to it using the DBD '
This exists to handle the loss of a database mid-run where a normal query, which isn't wrapped in a query, could hang indefinately.
B<< Note >>: If there is no active handle, this returns 0 immediately.
=cut
sub _test_access
{
@ -17401,7 +17594,16 @@ sub _test_access
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->_test_access()" }});
my $uuid = $parameter->{uuid} ? $parameter->{uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
"cache::database_handle::${uuid}" => $anvil->data->{cache}{database_handle}{$uuid},
}});
# If the handle is down, return 0.
if ((not exists $anvil->data->{cache}{database_handle}{$uuid}) or (not $anvil->data->{cache}{database_handle}{$uuid}))
{
return(0);
}
# Make logging code a little cleaner
my $database_name = defined $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : $anvil->data->{sys}{database}{name};

@ -31,6 +31,7 @@ my $THIS_FILE = "Get.pm";
# host_uuid_from_name
# host_type
# host_uuid
# kernel_release
# md5sum
# os_type
# server_uuid_from_name
@ -1777,6 +1778,94 @@ sub host_uuid
return($anvil->{HOST}{UUID});
}
=head2 kernel_release
This returns the kernel release (same output as C<<uname -r>>) on the local or remote host. If there is a problem, C<< !!error!! >> is returned.
Parameters;
=head3 password (optional)
This is the password to use when connecting to a remote machine. If not set, but C<< target >> is, an attempt to connect without a password will be made.
=head3 port (optional)
This is the TCP port to use when connecting to a remote machine. If not set, but C<< target >> is, C<< 22 >> will be used.
=head3 remote_user (optional, default root)
If C<< target >> is set, this will be the user we connect to the remote machine as.
=head3 target (optional)
This is the IP or host name of the machine to read the kernel release. If this is not set, the local system's kernel release is checked.
=cut
sub kernel_release
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->kernel_release()" }});
my $password = defined $parameter->{password} ? $parameter->{password} : "";
my $port = defined $parameter->{port} ? $parameter->{port} : "";
my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root";
my $target = defined $parameter->{target} ? $parameter->{target} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
target => $target,
port => $port,
remote_user => $remote_user,
password => $anvil->Log->is_secure($password),
}});
my $kernel_release = "";
my $return_code = "";
my $shell_call = $anvil->data->{path}{exe}{uname}." --kernel-release";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
if ($anvil->Network->is_local({host => $target}))
{
# Local call
($kernel_release, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
kernel_release => $kernel_release,
return_code => $return_code,
}});
}
else
{
# Remote call
($kernel_release, my $error, $return_code) = $anvil->Remote->call({
debug => $debug,
shell_call => $shell_call,
target => $target,
port => $port,
password => $password,
remote_user => $remote_user,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
kernel_release => $kernel_release,
error => $error,
return_code => $return_code,
}});
if ($return_code)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "err", key => "error_0356", variables => {
target => $target,
output => $kernel_release,
return_code => $return_code,
}});
$kernel_release = "!!error!!";
}
}
return($kernel_release);
}
=head2 md5sum
This returns the C<< md5sum >> of a given file.

@ -2876,22 +2876,34 @@ sub ping
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
}
$shell_call .= " || ".$anvil->data->{path}{exe}{echo}." timeout";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my $pinged = 0;
my $average_ping_time = 0;
foreach my $try (1..$count)
{
last if $pinged;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count, try => $try }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
count => $count,
try => $try,
}});
my $output = "";
my $error = "";
# If the 'target' is set, we'll call over SSH unless 'target' is our host name.
if ($anvil->Network->is_local({host => $target}))
my $is_local = $anvil->Network->is_local({host => $target});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
target => $target,
is_local => $is_local,
}});
if ($is_local)
{
### Local calls
($output, my $return_code) = $anvil->System->call({shell_call => $shell_call});
($output, my $return_code) = $anvil->System->call({
debug => $debug,
shell_call => $shell_call,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
}
else

@ -21,6 +21,7 @@ my $THIS_FILE = "ScanCore.pm";
# check_health
# check_power
# check_temperature
# check_temperature_direct
# count_servers
# post_scan_analysis
# post_scan_analysis_dr
@ -198,7 +199,7 @@ sub agent_startup
if (($anvil->data->{scancore}{$agent}{disable}) && (not $anvil->data->{switches}{force}))
{
# Exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0646", variables => { program => $THIS_FILE }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0646", variables => { program => $agent }});
$anvil->nice_exit({exit_code => 0});
}
@ -1160,6 +1161,109 @@ ORDER BY
}
=head2 check_temperature_direct
This calls a target's IPMI interface to check the temperature sensors that are available. The status is returns as;
0 = Failed to read temperature sensors / IPMI unavailable
1 = All available temperatures are nominal.
2 = One of more sensors are in warning or critical.
Parameters;
=head3 host_uuid (Optional, default Get->host_uuid() )
This is the host's UUID to look at.
=cut
sub check_temperature_direct
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "ScanCore->check_temperature_direct()" }});
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid,
}});
# * 0 - Failed to read temperature sensors / IPMI unavailable
# * 1 - All available temperatures are nominal
# * 2 - One of more sensors are in warning or critical.
my $status = 0;
if ((not defined $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi}) or (not $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi}))
{
$anvil->Database->get_hosts_info({debug => $debug});
}
my $host_ipmi = $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi};
my $host_name = $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_ipmi => $host_ipmi,
host_name => $host_name,
}});
my ($ipmitool_command, $ipmi_password) = $anvil->Convert->fence_ipmilan_to_ipmitool({
debug => 2,
fence_ipmilan_command => $host_ipmi,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
ipmitool_command => $ipmitool_command,
ipmi_password => $anvil->Log->is_secure($ipmi_password),
}});
if ((not $ipmitool_command) or ($ipmitool_command eq "!!error!!"))
{
# No IPMI tool to call.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0573", variables => { host_name => $host_name }});
return($status);
}
$anvil->System->collect_ipmi_data({
debug => $debug,
host_name => $host_name,
ipmitool_command => $ipmitool_command,
ipmi_password => $ipmi_password,
});
# Now look for thermal values.
foreach my $sensor_name (sort {$a cmp $b} keys %{$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}})
{
my $current_value = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_value_sensor_value};
my $units = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_units};
my $sensor_status = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_status};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
current_value => $current_value,
sensor_name => $sensor_name,
units => $units,
sensor_status => $sensor_status,
}});
# If this is a temperature, check to see if it is outside its nominal range and, if
# so, record it into a hash for loading into ScanCore's 'temperature' table.
if ($units eq "C")
{
if ($sensor_status eq "ok")
{
# We've found at least one temperature sensor. Set status to '1' if not previously set
$status = 1 if not $status;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }});
}
else
{
# Sensor isn't OK yet.
$status = 2 if not $status;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }});
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }});
return($status);
}
=head2 count_servers
This returns the number of servers running on a given host, as reported by ScanCore (specifically, by counting the number of servers running on the host from the C<< servers >> table). It also counts the total amount of RAM in use by hosted servers.
@ -2527,9 +2631,7 @@ LIMIT 1;";
if (not $stop_reason)
{
$stop_reason = "unknown";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { stop_reason => $stop_reason }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0565", variables => { host_name => $host_name }});
}
if ($stop_reason eq "user")
@ -2538,7 +2640,71 @@ LIMIT 1;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0566", variables => { host_name => $host_name }});
next;
}
elsif (($stop_reason eq "power") or ($stop_reason eq "unknown"))
elsif ($stop_reason eq "unknown")
{
# Check both power and temp.
if ((not defined $anvil->data->{feature}{scancore}{disable}{'boot-unknown-stop'}) or (not exists $anvil->data->{feature}{scancore}{disable}{'boot-unknown-stop'}) or ($anvil->data->{feature}{scancore}{disable}{'boot-unknown-stop'} eq ""))
{
$anvil->data->{feature}{scancore}{disable}{'boot-unknown-stop'} = 1;
}
if (not $anvil->data->{feature}{scancore}{disable}{'boot-unknown-stop'})
{
# Ignore.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0671", variables => { host_name => $host_name }});
}
else
{
# Evaluate for boot.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0672", variables => { host_name => $host_name }});
# Check power
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0567", variables => { host_name => $host_name }});
my ($power_health, $shortest_time_on_batteries, $highest_charge_percentage, $estimated_hold_up_time) = $anvil->ScanCore->check_power({
debug => $debug,
anvil_uuid => $anvil_uuid,
anvil_name => $anvil_name,
host_uuid => $host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
power_health => $power_health,
shortest_time_on_batteries => $shortest_time_on_batteries,
highest_charge_percentage => $highest_charge_percentage,
estimated_hold_up_time => $estimated_hold_up_time,
}});
# Check temp.
my ($temp_health) = $anvil->ScanCore->check_temperature_direct({
debug => $debug,
host_uuid => $host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { temp_health => $temp_health }});
### Temp
# * 0 = Failed to read temperature sensors / IPMI unavailable
# * 1 = All available temperatures are nominal.
# * 2 = One of more sensors are in warning or critical.
### Power
# * 0 = No UPSes found for the host
# * 1 = One or more UPSes found and at least one has input power from mains.
# * 2 = One or more UPSes found, all are running on battery.
if (($temp_health eq "1") && ($power_health eq "1"))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0673", variables => { host_name => $host_name }});
$shell_call =~ s/--action status/ --action on/;
my ($output, $return_code) = $anvil->System->call({debug => $debug, timeout => 30, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
# Mark it as booting.
$anvil->Database->update_host_status({
debug => $debug,
host_uuid => $host_uuid,
host_status => "booting",
});
}
}
}
elsif ($stop_reason eq "power")
{
# Check now if the power is OK
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0567", variables => { host_name => $host_name }});
@ -2590,72 +2756,20 @@ LIMIT 1;";
}
elsif ($stop_reason eq "thermal")
{
### TODO: Switch to ->check_temperature()
# Check now if the temperature is OK.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0568", variables => { host_name => $host_name }});
my ($ipmitool_command, $ipmi_password) = $anvil->Convert->fence_ipmilan_to_ipmitool({
debug => 2,
fence_ipmilan_command => $host_ipmi,
my ($temp_health) = $anvil->ScanCore->check_temperature_direct({
debug => $debug,
host_uuid => $host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
ipmitool_command => $ipmitool_command,
ipmi_password => $anvil->Log->is_secure($ipmi_password),
}});
if ((not $ipmitool_command) or ($ipmitool_command eq "!!error!!"))
{
# No IPMI tool to call.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0573", variables => { host_name => $host_name }});
next;
}
$anvil->System->collect_ipmi_data({
host_name => $host_name,
ipmitool_command => $ipmitool_command,
ipmi_password => $ipmi_password,
});
### Temp
# * 0 = Failed to read temperature sensors / IPMI unavailable
# * 1 = All available temperatures are nominal.
# * 2 = One of more sensors are in warning or critical.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { temp_health => $temp_health }});
# Now look for thermal values.
my $sensor_found = 0;
my $temperatures_ok = 1;
foreach my $sensor_name (sort {$a cmp $b} keys %{$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}})
{
my $current_value = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_value_sensor_value};
my $units = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_units};
my $status = $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_status};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
current_value => $current_value,
sensor_name => $sensor_name,
units => $units,
status => $status,
}});
# If this is a temperature, check to see if it is outside its nominal range and, if
# so, record it into a hash for loading into ScanCore's 'temperature' table.
if ($units eq "C")
{
if (not $sensor_found)
{
# We've found at least one temperature sensor.
$sensor_found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { sensor_found => $sensor_found }});
}
if ($status ne "ok")
{
# Sensor isn't OK yet.
$temperatures_ok = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { temperatures_ok => $temperatures_ok }});
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
sensor_found => $sensor_found,
temperatures_ok => $temperatures_ok,
}});
if (($sensor_found) && ($temperatures_ok))
if ($temp_health eq "1")
{
### TODO: We'll want to revisit M2's restart cooldown logic. It never
### actually proved useful in M2, but it doesn't mean it wouldn't help

@ -14,6 +14,7 @@ my $THIS_FILE = "Server.pm";
### Methods;
# active_migrations
# boot_virsh
# count_servers
# find
# get_definition
# get_runtime
@ -263,6 +264,74 @@ WHERE
return($success);
}
=head2 count_servers
This method counts the number of hosted servers and returns that number. If C<< virsh >> is not available, C<< 0 >> is returned. Note that it's B< possible >>, though unlikely on an Anvil!, that a qemu server is running outside C<< libvirtd >>.
This method takes no parameters.
=cut
sub count_servers
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Server->count_servers()" }});
my $count = 0;
if (-e $anvil->data->{path}{exe}{virsh})
{
my $shell_call = $anvil->data->{path}{exe}{virsh}." list";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
foreach my $line (split/\n/, $output)
{
$line = $anvil->Words->clean_spaces({string => $line});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /^\d+ (.*) (.*?)$/)
{
=cut
* Server states;
running - The domain is currently running on a CPU
idle - The domain is idle, and not running or runnable. This can be caused because the domain is waiting on IO (a traditional wait state) or has gone to sleep because there was nothing else for it to do.
paused - The domain has been paused, usually occurring through the administrator running virsh suspend. When in a paused state the domain will still consume allocated resources like memory, but will not be eligible for scheduling by the hypervisor.
in shutdown - The domain is in the process of shutting down, i.e. the guest operating system has been notified and should be in the process of stopping its operations gracefully.
shut off - The domain is not running. Usually this indicates the domain has been shut down completely, or has not been started.
crashed - The domain has crashed, which is always a violent ending. Usually this state can only occur if the domain has been configured not to restart on crash.
pmsuspended - The domain has been suspended by guest power management, e.g. entered into s3 state.
=cut
my $name = $1;
my $status = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
status => $status,
name => $name,
}});
if ((lc($status) eq "running") or
(lc($status) eq "paused") or
(lc($status) eq "in shutdown") or
(lc($status) eq "pmsuspended"))
{
$count++;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }});
}
}
}
}
return($count);
}
=head2 find
This will look on the local or a remote machine for the list of servers that are running.

@ -2177,6 +2177,7 @@ sub get_storage_group_from_path
}
# Is this a DRBD path?
my $gathered_data = 0;
my $logical_volume = "";
if ($path !~ /drbd/)
{
@ -2188,8 +2189,9 @@ sub get_storage_group_from_path
# Looks like it. If the device path is '/dev/drbd/by-res/...' we'll need to pull out the
# resource name (server name) and volume number as the path only actually exists when DRBD is
# up and isn't referenced in the config file.
my $resource = "";
my $volume = "";
my $resource = "";
my $volume = "";
$gathered_data = 1;
$anvil->DRBD->gather_data({debug => $debug});
if ($path =~ /\/dev\/drbd\/by-res\/(.*)\/(\d+)$/)
{
@ -2342,10 +2344,13 @@ LIMIT 1
scan_drbd_resource_xml => $scan_drbd_resource_xml,
}});
$anvil->DRBD->gather_data({
debug => 3,
xml => $scan_drbd_resource_xml,
});
if (not $gathered_data)
{
$anvil->DRBD->gather_data({
debug => 3,
xml => $scan_drbd_resource_xml,
});
}
# Dig out the LV behind the volume.
foreach my $this_host_name (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{host}})

@ -654,6 +654,159 @@ sub check_memory
}
=head2 check_ram_use
This is meant to be used by daemons to check how much RAM it is using. It returns an anonymous array with the first value being C<< 0 >> if the in-use RAM is below the maximum, and C<< 1 >> it the in-use RAM is too high. The second value is the amount of RAM in use, in bytes. If the program is not found to be running, C<< 2, 0 >> is returned.
my ($problem, $used_ram) = $anvil->System->check_ram_use({
program => $THIS_FILE,
max_ram => 1073741824,
});
Parameters;
=head3 program (required)
This is generally C<< $THIS_FILE >>. Though this could be used to check the RAM use of other programs.
=head3 max_ram (optional, default '1073741824' (1 GiB))
This is the limit allowed. If the in-use RAM is greater than this amount, an alert will be generated and sent.
=cut
sub check_ram_use
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->check_ram_use()" }});
my $program = defined $parameter->{program} ? $parameter->{program} : "";
my $max_ram = defined $parameter->{max_ram} ? $parameter->{max_ram} : 1073741824;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
program => $program,
max_ram => $max_ram,
}});
# Find the PID(s) of the program.
my $problem = 0;
my $ram_used = 0;
# See if we're a daemon running under systemctl. If so, the memory reported includes all spawned
# child programs, swap, etc. Much more thorough.
my $shell_call = $anvil->data->{path}{exe}{systemctl}." status ".$program." --lines=0";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
foreach my $line (split/\n/, $output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /Memory: (.*)?/)
{
my $memory = $1;
my $in_bytes = $anvil->Convert->human_readable_to_bytes({size => $memory, base2 => 1});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
memory => $memory,
in_bytes => $anvil->Convert->add_commas({number => $in_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $in_bytes}).")",
}});
if ($in_bytes =~ /^\d+$/)
{
$ram_used = $in_bytes;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
ram_used => $anvil->Convert->add_commas({number => $ram_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}).")",
}});
}
last;
}
}
# If we didn't get the RAM from systemctl, read smaps
if (not $ram_used)
{
my $pids = $anvil->System->pids({debug => $debug, program_name => $program});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pids => $pids }});
my $pids_found = @{$pids};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pids_found => $pids_found }});
if (not $pids_found)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0135", variables => { program => $program }});
return(2, 0);
}
# Read in the smaps for each pid
foreach my $pid (sort {$a cmp $b} @{$pids})
{
my $smaps_path = "/proc/".$pid."/smaps";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { smaps_path => $smaps_path }});
# This will store the amount of RAM used by this specific PID.
$anvil->data->{memory}{pid}{$pid} = 0;
if (not -e $smaps_path)
{
# It is possible that the program just closed.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0433", variables => { pid => $pid }});
next;
}
# Read in the file.
my $body = $anvil->Storage->read_file({debug => $debug, file => $smaps_path});
foreach my $line (split/\n/, $body)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /^Private_Dirty:\s+(\d+) (.*B)$/)
{
my $size = $1;
my $type = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
type => $type,
size => $size,
}});
next if not $size;
next if $size =~ /\D/;
# This uses 'kB' for 'KiB' >_>
$type = lc($type);
$type =~ s/b$/ib/ if $type !~ /ib$/;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { type => $type }});
my $size_in_bytes = $anvil->Convert->human_readable_to_bytes({size => $size, type => $type, base2 => 1});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
size_in_bytes => $anvil->Convert->add_commas({number => $size_in_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $size_in_bytes}).")",
}});
$anvil->data->{memory}{pid}{$pid} += $size_in_bytes;
$ram_used += $size_in_bytes;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"memory::pid::${pid}" => $anvil->Convert->add_commas({number => $anvil->data->{memory}{pid}{$pid}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{memory}{pid}{$pid}}).")",
ram_used => $anvil->Convert->add_commas({number => $ram_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}).")",
}});
}
}
}
}
# Are we using too much RAM?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
max_ram => $anvil->Convert->add_commas({number => $max_ram})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_ram}).")",
ram_used => $anvil->Convert->add_commas({number => $ram_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}).")",
}});
if ($ram_used > $max_ram)
{
$problem = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { problem => $problem }});
}
return($problem, $ram_used);
}
=head2 check_ssh_keys
This method does several things;
@ -728,10 +881,29 @@ sub check_ssh_keys
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0270", variables => { user => $user }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{'ssh-keygen'}." -t rsa -N \"\" -b 8191 -f ".$ssh_private_key_file});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
if (-e $ssh_public_key_file)
{
# Success!
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0271", variables => { user => $user, output => $output }});
# Set the ownership
foreach my $file ($ssh_private_key_file, $ssh_public_key_file)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0682", variables => {
file => $file,
user => $user,
}});
$anvil->Storage->change_owner({
debug => 2,
path => $file,
user => $user,
group => $user,
});
}
}
else
{
@ -1770,6 +1942,16 @@ LIMIT 1
password_length => $password_length,
}});
# If the password has spaces, some IPMI BMCs won't allow them. If we need to use it, we'll take out
# the spaces and shrink the length.
my $ipmi_no_space_password = "";
if ($ipmi_password =~ /\s/)
{
$ipmi_no_space_password = $ipmi_password;
$ipmi_no_space_password =~ s/\s//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { ipmi_no_space_password => $ipmi_no_space_password }});
}
my $subnet_mask = "";
my $gateway = "";
my $in_network = "";
@ -1858,7 +2040,7 @@ LIMIT 1
if (not $has_ipmi)
{
# Return
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "err", key => "log_0499"});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, priority => "err", key => "log_0499"});
return(0);
}
@ -2075,6 +2257,7 @@ LIMIT 1
my $wait_until = time + 120;
while ($waiting)
{
my $debug = 2;
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{ipmitool}." user list ".$lan_channel});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
@ -2118,6 +2301,8 @@ LIMIT 1
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user_name => $user_name }});
last if $user_name;
# Try again later or give up?
if (time > $wait_until)
@ -2137,6 +2322,7 @@ LIMIT 1
sleep 10;
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { user_name => $user_name }});
if (not $user_name)
{
# Failed to find a user.
@ -2225,6 +2411,13 @@ LIMIT 1
}
else
{
# If we used the no-space password, set it as the ipmi_password now.
if ($ipmi_no_space_password)
{
$ipmi_password = $ipmi_no_space_password;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { ipmi_password => $ipmi_password }});
}
# Change the password and then try again.
my $escaped_ipmi_password = shell_quote($ipmi_password);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { escaped_ipmi_password => $escaped_ipmi_password }});
@ -3152,6 +3345,7 @@ sub host_name
return($host_name, $descriptive);
}
=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.

@ -11,6 +11,11 @@ sys::privacy::strong = 0
# feature, set this to '1'.
feature::scancore::disable::preventative-live-migration = 0
# If a node is found to be powered off, and there is no reason recorded in the database, it will be booted.
# The assumption is that an accidental power off occurred. If you would like to have nodes that power off
# stay off until manually started, set this to '0'
#feature::scancore::disable::boot-unknown-stop = 1
### Database
# Database connections;
#

@ -63,6 +63,7 @@ Requires: mailx
Requires: mlocate
Requires: net-snmp-utils
Requires: nvme-cli
Requires: pciutils
Requires: perl-Capture-Tiny
Requires: perl-Data-Dumper
Requires: perl-Data-Validate-Domain
@ -131,6 +132,7 @@ Requires: gdm
Requires: gnome-terminal
Requires: httpd
Requires: nmap
Requires: openssh-askpass
Requires: postgresql-server
Requires: syslinux
Requires: syslinux-nonlinux
@ -237,6 +239,8 @@ systemctl enable chronyd.service
systemctl start chronyd.service
systemctl enable anvil-daemon.service
systemctl restart anvil-daemon.service
systemctl enable scancore.service
systemctl restart scancore.service
%post striker
@ -252,9 +256,10 @@ then
systemctl enable gdm.service
fi
echo "Preparing the database"
striker-prep-database
anvil-update-states
### This is handled by anvil-daemon now
#echo "Preparing the database"
#striker-prep-database
#anvil-update-states
# Touch the system type file.
echo "Touching the system type file"

@ -265,7 +265,7 @@ sub process_task
$anvil->data->{cgi}{login}{value} = "" if not defined $anvil->data->{cgi}{login}{value};
$anvil->data->{cgi}{logout}{value} = "" if not defined $anvil->data->{cgi}{logout}{value};
$anvil->data->{cgi}{save}{value} = "" if not defined $anvil->data->{cgi}{save}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::login::value" => $anvil->data->{cgi}{login}{value},
"cgi::logout::value" => $anvil->data->{cgi}{logout}{value},
"cgi::save::value" => $anvil->data->{cgi}{save}{value},
@ -297,14 +297,14 @@ sub process_task
# 1 - No cookie was found or read. The user needs to log in
# 2 - There was a problem reading the user's UUID (it wasn't found in the database), so the
# 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
# 3 - Their 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();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { cookie_problem => $cookie_problem }});
my $cookie_problem = $anvil->Account->read_cookies({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cookie_problem => $cookie_problem }});
if (not $cookie_problem)
{
$logged_in = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { logged_in => $logged_in }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { logged_in => $logged_in }});
}
}
@ -3500,7 +3500,12 @@ sub sanity_check_manifest_step3
# Is the IP valid?
if (not $anvil->Validate->ipv4({ip => $anvil->data->{cgi}{$machine_ip_key}{value}, debug => 2}))
{
# Bad subnet
# Bad subnet. If this is DR IFN 1, and the value was empty, ignore it
# as there simply is no DR on this cluster.
if (($machine eq "dr1") && ($anvil->data->{cgi}{$machine_ip_key}{value} eq ""))
{
next;
}
my $say_network = "#!string!striker_0255!#";
if ($machine eq "node2") { $say_network = "#!string!striker_0256!#"; }
elsif ($machine eq "dr1") { $say_network = "#!string!striker_0257!#"; }
@ -4798,7 +4803,7 @@ sub process_fences
# We add in 'name'
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{unique} = "0";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{required} = "0";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{required} = "1";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{description} = "#!string!striker_0223!#";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{content_type} = "string";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{'default'} = "";
@ -6446,6 +6451,7 @@ sub process_power
my $job_description = "job_0006";
my $say_title = "#!string!job_0005!#";
my $say_description = "#!string!job_0006!#";
my $say_reason = "log_0199";
if ($task eq "poweroff")
{
$job_command = $anvil->data->{path}{exe}{'anvil-manage-power'}." --poweroff -y".$anvil->Log->switches;
@ -6453,7 +6459,9 @@ sub process_power
$job_description = "job_0008";
$say_title = "#!string!job_0007!#";
$say_description = "#!string!job_0008!#";
$say_reason = "log_0200";
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => $say_reason }});
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,

@ -103,9 +103,9 @@ AC_SUBST([OCFROOT])
ANVIL_PKG_CHECK_VAR([FASEXECPREFIX_TMP], [fence-agents], [exec_prefix], [${prefix}])
if test "${prefix}" != "/usr"; then
FASEXECPREFIX="${prefix}/$FASEXECPREFIX_TMP"
FASEXECPREFIX="${prefix}/${FASEXECPREFIX_TMP}"
else
FASEXECPREFIX="FASEXECPREFIX_TMP"
FASEXECPREFIX="${FASEXECPREFIX_TMP}"
fi
AC_SUBST([FASEXECPREFIX])

172
notes

@ -1,3 +1,29 @@
# Configure APC PDUs and UPSes
tcpip -i 10.201.2.3 -s 255.255.0.0 -g 10.201.255.254
web -h enable
web -s enable
snmp -S enable -c1 private -a1 writeplus
snmp -S enable -c2 public -a2 writeplus
Anvil! to Anvil! live migration;
1. Create LVs
2. Make sure /etc/hosts is populated
3. If DR is used, disconnect first to stay within the max-peers=3
3. Update dbrd config, A:1 -> A:2, A:1 -> B:1, B:1 -> B:2 (if both online and UpToDate, otherwise both from UpToDate)
4. Create drbd md on new Anvil!
5. drbdadm adjust on old nodes.
6. Wait for DRBD resource to sync to node 1 (it can sync to node 2 later)
7. Copy server's XML to new cluster
8. pcs resource unmanage srv01-cs8
9. Allow dual primary between A1:B1 (or A2:B1) -
[root@an-a01n01 ~]# pcs resource disable srv01-cs8
Warning: 'srv01-cs8' is unmanaged
[root@an-a01n01 ~]# pcs resource manage srv01-cs8
[root@an-a01n01 ~]# pcs resource delete srv01-cs8
Deleting Resource - srv01-cs8
10.
TODO:
- Remove this; (step 2) "This is the user name that you will log into Striker as and the name of the user that owns the database"
- Being set to the gateway, not the default DNS - "This is the domain name server(s) to use when resolving domain names. You can specify 2 or more, separated by commas."
@ -18,6 +44,8 @@ SELECT a.scan_apc_ups_name AS name, a.scan_apc_ups_serial_number AS sn, a.scan_a
============
dnf -y install augeas
Jenkins;
@ -742,9 +770,11 @@ mediawiki on EL8 install notes (starting from a minimal install);
dnf module reset php
dnf module enable php:7.4
# All
dnf install httpd php php-gd php-xml php-mbstring php-json \
vim bash-completion wget tar rsync mlocate php-pecl-apcu \
memcached php-pear icu php-intl php-pgsql bzip2
memcached php-pear icu php-intl php-pgsql bzip2 mod_ssl
### PostgreSQL
dnf install postgresql-server postgresql-plperl
@ -753,7 +783,9 @@ systemctl start postgresql.service
systemctl enable postgresql.service
### MariaDB
dnf install php-mysqlnd php-gd php-xml mariadb-server mariadb
dnf install httpd php php-gd php-xml php-mbstring php-json \
php-mysqlnd php-gd php-xml mariadb-server mariadb \
systemctl start mariadb
mysql_secure_installation
|Set root password? [Y/n] y
@ -766,40 +798,30 @@ mysql_secure_installation
|Reload privilege tables now? [Y/n] y
mysql -u root -p
### In mariadb
MariaDB [(none)]> CREATE DATABASE digimer_wiki;
MariaDB [(none)]> CREATE USER 'digimer'@'localhost' IDENTIFIED BY 'Initial1';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON digimer_wiki.* TO 'digimer'@'localhost';
MariaDB [(none)]> CREATE DATABASE an_wiki;
MariaDB [(none)]> CREATE USER 'alteeve'@'localhost' IDENTIFIED BY 'experience tell mineral';
MariaDB [(none)]> GRANT ALL PRIVILEGES ON an_wiki.* TO 'alteeve'@'localhost';
MariaDB [(none)]> FLUSH PRIVILEGES;
MariaDB [(none)]> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| digimer_wiki |
| an_wiki |
| information_schema |
| mysql |
| performance_schema |
+--------------------+
MariaDB [(none)]> SHOW GRANTS FOR 'digimer'@'localhost';
MariaDB [(none)]> SHOW GRANTS FOR 'alteeve'@'localhost';
+----------------------------------------------------------------------------------------------------------------+
| Grants for digimer@localhost |
+----------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `digimer`@`localhost` IDENTIFIED BY PASSWORD '*xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' |
| GRANT ALL PRIVILEGES ON `digimer_wiki`.* TO `digimer`@`localhost` |
| GRANT ALL PRIVILEGES ON `an_wiki`.* TO `digimer`@`localhost` |
+----------------------------------------------------------------------------------------------------------------+
MariaDB [(none)]> exit
# Back to terminal
systemctl enable mariadb
# Common
systemctl start httpd.service
systemctl enable httpd.service
systemctl start memcached.service
systemctl enable memcached.service
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https
systemctl restart firewalld
# diff -u /var/lib/pgsql/data/pg_hba.conf.orig /var/lib/pgsql/data/pg_hba.conf
====
--- /var/lib/pgsql/data/pg_hba.conf.orig 2021-02-17 02:50:10.959000000 -0500
@ -834,6 +856,47 @@ systemctl restart firewalld
;;;;
; Note: packaged extension modules are now loaded via the .ini files
# Download and install
cd /var/www/
wget https://releases.wikimedia.org/mediawiki/1.37/mediawiki-1.37.1.tar.gz
tar -xvzf mediawiki-1.37.1.tar.gz
cd /var/www/html
ln -s ../mediawiki-1.37.1 ./w
systemctl enable httpd.service
systemctl enable memcached.service
systemctl start httpd.service
systemctl start memcached.service
firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --zone=public --add-service=https --permanent
firewall-cmd --reload
### Certbot / Let's Encrypt
# EPEL / snapd
dnf config-manager --set-enabled powertools
dnf install epel-release epel-next-release
dnf install snapd
systemctl enable --now snapd.socket
ln -s /var/lib/snapd/snap /snap
### Setup vhost
# httpd.conf
### Log out and back in to ensure snapd path
# If the next step fails with "too early for operation, device not yet seeded or device model not acknowledged", restart snapd
snap install core
snap refresh core
snap install --classic certbot
# certbot
certbot --apache
# answer questions
====
Dell S4128T-ON Configuration
@ -960,19 +1023,24 @@ OS10(config)# write memory
OS10(config)# hostname zo-switch01
zo-switch01(config)# interface vlan 100
zo-switch01(conf-if-vl-100)# description BCN1
zo-switch01(config)# exit
zo-switch01(conf-if-vl-100)# interface range ethernet 1/1/1-1/1/14
zo-switch01(conf-range-eth1/1/1-1/1/10)# switchport access vlan 100
zo-switch01(conf-range-eth1/1/1-1/1/10)# no shutdown
zo-switch01(conf-range-eth1/1/1-1/1/10)# exit
zo-switch01(config)# interface vlan 200
zo-switch01(conf-if-vl-200)# description SN1
zo-switch01(conf-if-vl-200)# interface range ethernet 1/1/11-1/1/14
zo-switch01(conf-if-vl-200)# exit
zo-switch01(config)# interface range ethernet 1/1/11-1/1/14
zo-switch01(conf-range-eth1/1/11-1/1/14)# switchport access vlan 200
zo-switch01(conf-range-eth1/1/11-1/1/14)# no shutdown
zo-switch01(conf-range-eth1/1/11-1/1/14)# exit
zo-switch01(config)# interface vlan 300
zo-switch01(conf-if-vl-300)# description IFN1
zo-switch01(conf-if-vl-300)# interface range ethernet 1/1/15-1/1/24
zo-switch01(conf-if-vl-300)# exit
zo-switch01(config)# interface range ethernet 1/1/15-1/1/24
zo-switch01(conf-range-eth1/1/15-1/1/24)# switchport access vlan 300
zo-switch01(conf-range-eth1/1/15-1/1/24)# no shutdown
zo-switch01(conf-range-eth1/1/15-1/1/24)# exit
@ -1223,13 +1291,33 @@ rs-striker03(config-if)#switchport access vlan 100
rs-striker03(config-if)#no shutdown
rs-striker03(config-if)#exit
rs-striker03(config)#interface vlan 300
rs-striker03(config)#name IFN
rs-striker03(config-if-vlan300)#interface range gigabitethernet1/0/15-24,gigabitethernet2/0/15-24
rs-striker03(config-if)#switchport access vlan 300
rs-striker03(config-if)#no shutdown
rs-striker03(config-if)#exit
rs-striker03(config)#exit
#### NOTE: Put IP on VID 1!
rs-switch03(config)#show vlan
VLAN Name Ports Type
----- --------------- ------------- --------------
1 default Po1-128, Default
Gi1/0/1-12,
Te1/0/1-4,
Gi2/0/1-12,
Te2/0/1-4
300 IFN1 Gi1/0/13-24, Static
Gi2/0/13-24
rs-switch03(config)#interface vlan 1
rs-switch03(config-if-vlan1)#ip address 10.201.1.3 255.255.0.0
rs-switch03(config-if-vlan1)#exit
rs-switch03(config)#exit
rs-switch03#copy running-config startup-config
###########################
rs-striker03#show vlan
@ -1412,3 +1500,33 @@ totem.transport (str) = knet
Gi1/0/24 + Gi2/0/24
Dell LACP Config (OS10 - https://www.dell.com/support/kbdoc/en-us/000102901/dell-emc-networking-os10-how-to-set-up-virtual-link-trunking-vlt)
* On both switches;
zo-switch02# configure terminal
* IFN Port channel is 3
zo-switch02(config)# interface port-channel 3
zo-switch02(conf-if-po-3)# <165>1 2021-10-19T04:58:56.022086+00:00 zo-switch02 dn_alm 920 - - Node.1-Unit.1:PRI [event], Dell EMC (OS10) %IFM_ASTATE_UP: Interface admin state up :port-channel3
<165>1 2021-10-19T04:58:56.022722+00:00 zo-switch02 dn_alm 920 - - Node.1-Unit.1:PRI [event], Dell EMC (OS10) %IFM_OSTATE_DN: Interface operational state is down :port-channel3
zo-switch02(conf-if-po-3)# lacp fallback enable
zo-switch02(conf-if-po-3)# description IFN1
zo-switch02(conf-if-po-3)# exit
zo-switch02(config)# exit
zo-switch02# show port-channel summary
Flags: D - Down I - member up but inactive P - member up and active
U - Up (port-channel) F - Fallback Activated
--------------------------------------------------------------------------------
Group Port-Channel Type Protocol Member Ports
--------------------------------------------------------------------------------
3 port-channel3 (D) Eth STATIC
1000 port-channel1000 (U) Eth STATIC 1/1/25(P) 1/1/26(P)
zo-switch02# configure terminal
zo-switch02(config)# interface ethernet 1/1/24
zo-switch02(conf-if-eth1/1/24)# channel-group 3
zo-switch02(conf-if-eth1/1/24)# <165>1 2021-10-19T05:09:41.237808+00:00 zo-switch02 dn_alm 920 - - Node.1-Unit.1:PRI [event], Dell EMC (OS10) %IFM_OSTATE_UP: Interface operational state is up :port-channel3
exit
exit

@ -1480,8 +1480,8 @@ WHERE
my $alert_sent = 0;
my $variables = {
ups_name => $scan_apc_ups_name,
new_value => $scan_apc_ups_battery_model,
old_value => $old_scan_apc_ups_battery_model,
new_value => $scan_apc_ups_battery_percentage_charge,
old_value => $old_scan_apc_ups_battery_percentage_charge,
battery_number => $battery_number,
low_charge_clear => $anvil->data->{'scan-apc-ups'}{low_charge_percentage_ok},
low_charge_alert => $anvil->data->{'scan-apc-ups'}{low_charge_percentage_warning},

@ -214,7 +214,7 @@ sub check_fence_delay
}});
if ((not $local_server_count) && (not $peer_server_count))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0636"});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0636"});
return(0);
}
elsif (($local_server_count) && ($peer_server_count))

@ -565,6 +565,13 @@ sub collect_data
{
$media = lc($1);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }});
# This can be 'tp mii', which breaks json.
if ($media =~ /\t/)
{
$media =~ s/\t/,/g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }});
}
last;
}
}
@ -791,18 +798,303 @@ sub read_last_scan
return(0);
}
# There is a bug somewhere where interfaces and ip addresses are periodically being added twice per host.
# This checks for / cleans those up. Remove this when the core issue is resolved.
# There is a bug somewhere where interfaces, bridges and ip addresses are periodically being added twice per
# host. This checks for / cleans those up. Remove this when the core issue is resolved.
sub clear_duplicates
{
my ($anvil) = @_;
# Look for duplicate bridges.
my $query = "
SELECT
bridge_uuid,
bridge_name,
bridge_id,
bridge_mac_address
FROM
bridges
WHERE
bridge_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
ORDER BY
bridge_name ASC,
bridge_id DESC
;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { 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,
}});
foreach my $row (@{$results})
{
my $bridge_uuid = $row->[0];
my $bridge_name = $row->[1];
my $bridge_id = $row->[2];
my $bridge_mac_address = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
bridge_uuid => $bridge_uuid,
bridge_name => $bridge_name,
bridge_id => $bridge_id,
bridge_mac_address => $bridge_mac_address,
}});
if (not exists $anvil->data->{duplicate_bridges}{seen}{$bridge_name})
{
$anvil->data->{duplicate_bridges}{seen}{$bridge_name} = [];
}
push @{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}}, $bridge_uuid;
$anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_name} = $bridge_name;
$anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address} = $bridge_mac_address;
$anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id} = $bridge_id;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_name" => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_name},
"duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_id" => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id},
"duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_mac_address" => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address},
}});
$anvil->data->{deleted_bridges}{$bridge_uuid} = 0;
}
foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_bridges}{seen}})
{
my $count = @{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:bridge_name' => $bridge_name,
's2:count' => $count,
}});
if ($count > 1)
{
# Duplicate! Is one of them marked as DELETED?
foreach my $bridge_uuid (@{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}})
{
# Is this one deleted?
my $bridge_mac_address = $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address};
my $bridge_id = $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
bridge_uuid => $bridge_uuid,
bridge_mac_address => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address},
bridge_id => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id},
}});
if ($bridge_id eq "DELETED")
{
# Take this one out.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => {
name => $bridge_name,
uuid => $bridge_uuid,
}});
my $queries = [];
push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
push @{$queries}, "DELETE FROM history.bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
push @{$queries}, "DELETE FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
push @{$queries}, "DELETE FROM history.bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
push @{$queries}, "DELETE FROM bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
# Write it out.
$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
$count--;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
$anvil->data->{deleted_bridges}{$bridge_uuid} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"deleted_bridges::${bridge_uuid}" => $anvil->data->{deleted_bridges}{$bridge_uuid},
}});
}
last if $count == 1;
}
# If count is still > 1, we need to arbitrarily delete an interface.
if ($count > 1)
{
foreach my $bridge_uuid (@{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => {
name => $bridge_name,
uuid => $bridge_uuid,
}});
my $queries = [];
push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
push @{$queries}, "DELETE FROM history.bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
push @{$queries}, "DELETE FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
push @{$queries}, "DELETE FROM history.bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
push @{$queries}, "DELETE FROM bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
# Write it out.
$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
$count--;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
$anvil->data->{deleted_bridges}{$bridge_uuid} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"deleted_bridges::${bridge_uuid}" => $anvil->data->{deleted_bridges}{$bridge_uuid},
}});
}
last if $count == 1;
}
}
}
delete $anvil->data->{duplicate_bridges};
# Load the bridges again.
$anvil->Database->get_bridges({include_deleted => 1});
# Look for duplicate bonds.
$query = "
SELECT
bond_uuid,
bond_name,
bond_operational,
bond_mac_address,
bond_bridge_uuid
FROM
bonds
WHERE
bond_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
ORDER BY
bond_name ASC,
bond_operational DESC
;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
$count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $bond_uuid = $row->[0];
my $bond_name = $row->[1];
my $bond_operational = $row->[2];
my $bond_mac_address = $row->[3];
my $bond_bridge_uuid = defined $row->[4] ? $row->[4] : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
bond_uuid => $bond_uuid,
bond_name => $bond_name,
bond_operational => $bond_operational,
bond_mac_address => $bond_mac_address,
bond_bridge_uuid => $bond_bridge_uuid,
}});
if (not exists $anvil->data->{duplicate_bonds}{seen}{$bond_name})
{
$anvil->data->{duplicate_bonds}{seen}{$bond_name} = [];
}
push @{$anvil->data->{duplicate_bonds}{seen}{$bond_name}}, $bond_uuid;
$anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_name} = $bond_name;
$anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address} = $bond_mac_address;
$anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational} = $bond_operational;
$anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid} = $bond_bridge_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"duplicate_bonds::bond_uuid::${bond_uuid}::bond_name" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_name},
"duplicate_bonds::bond_uuid::${bond_uuid}::bond_operational" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational},
"duplicate_bonds::bond_uuid::${bond_uuid}::bond_mac_address" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address},
"duplicate_bonds::bond_uuid::${bond_uuid}::bond_bridge_uuid" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid},
}});
$anvil->data->{deleted_bonds}{$bond_uuid} = 0;
}
foreach my $bond_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_bonds}{seen}})
{
my $count = @{$anvil->data->{duplicate_bonds}{seen}{$bond_name}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:bond_name' => $bond_name,
's2:count' => $count,
}});
if ($count > 1)
{
# Duplicate! Is one of them marked as DELETED?
foreach my $bond_uuid (@{$anvil->data->{duplicate_bonds}{seen}{$bond_name}})
{
# Is this one deleted?
my $bond_mac_address = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address};
my $bond_operational = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational};
my $bond_bridge_uuid = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
bond_uuid => $bond_uuid,
bond_mac_address => $bond_mac_address,
bond_operational => $bond_operational,
bond_bridge_uuid => $bond_bridge_uuid,
}});
if ((($bond_bridge_uuid) && ($anvil->data->{deleted_bridges}{$bond_bridge_uuid})) or ($bond_operational eq "DELETED"))
{
# Take this one out.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => {
name => $bond_name,
uuid => $bond_uuid,
}});
my $queries = [];
push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
push @{$queries}, "DELETE FROM history.bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
push @{$queries}, "DELETE FROM bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
# Write it out.
$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
$count--;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
$anvil->data->{deleted_bonds}{$bond_uuid} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"deleted_bonds::${bond_uuid}" => $anvil->data->{deleted_bonds}{$bond_uuid},
}});
}
}
# If count is still > 1, we need to arbitrarily delete an interface.
if ($count > 1)
{
foreach my $bond_uuid (@{$anvil->data->{duplicate_bonds}{seen}{$bond_name}})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => {
name => $bond_name,
uuid => $bond_uuid,
}});
my $queries = [];
push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
push @{$queries}, "DELETE FROM history.bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
push @{$queries}, "DELETE FROM bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
# Write it out.
$anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__});
$count--;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
$anvil->data->{deleted_bonds}{$bond_uuid} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"deleted_bonds::${bond_uuid}" => $anvil->data->{deleted_bonds}{$bond_uuid},
}});
}
last if $count == 1;
}
}
}
delete $anvil->data->{duplicate_bonds};
# Look for duplicate network interfaces
$query = "
SELECT
network_interface_uuid,
network_interface_name,
network_interface_mac_address,
network_interface_operational
network_interface_operational,
network_interface_bond_uuid,
network_interface_bridge_uuid
FROM
network_interfaces
WHERE
@ -810,23 +1102,27 @@ WHERE
ORDER BY
network_interface_name ASC;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
$count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $network_interface_uuid = $row->[0];
my $network_interface_name = $row->[1];
my $network_interface_mac_address = $row->[2];
my $network_interface_operational = $row->[3];
my $network_interface_uuid = $row->[0];
my $network_interface_name = $row->[1];
my $network_interface_mac_address = $row->[2];
my $network_interface_operational = $row->[3];
my $network_interface_bond_uuid = defined $row->[4] ? $row->[4] : "";
my $network_interface_bridge_uuid = defined $row->[5] ? $row->[5] : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
network_interface_uuid => $network_interface_uuid,
network_interface_name => $network_interface_name,
network_interface_mac_address => $network_interface_mac_address,
network_interface_operational => $network_interface_operational,
network_interface_bond_uuid => $network_interface_bond_uuid,
network_interface_bridge_uuid => $network_interface_bridge_uuid,
}});
if (not exists $anvil->data->{duplicate_nics}{seen}{$network_interface_name})
@ -838,10 +1134,14 @@ ORDER BY
$anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_name} = $network_interface_name;
$anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address} = $network_interface_mac_address;
$anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} = $network_interface_operational;
$anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid} = $network_interface_bond_uuid;
$anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid} = $network_interface_bridge_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_name" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_name},
"duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address},
"duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_operational" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational},
"duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_bond_uuid" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid},
"duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_bridge_uuid" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid},
}});
}
foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_nics}{seen}})
@ -860,12 +1160,18 @@ ORDER BY
# Is this one deleted?
my $network_interface_mac_address = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address};
my $network_interface_operational = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational};
my $network_interface_bond_uuid = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid};
my $network_interface_bridge_uuid = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
network_interface_uuid => $network_interface_uuid,
network_interface_mac_address => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address},
network_interface_operational => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational},
network_interface_mac_address => $network_interface_mac_address,
network_interface_operational => $network_interface_operational,
network_interface_bond_uuid => $network_interface_bond_uuid,
network_interface_bridge_uuid => $network_interface_bridge_uuid,
}});
if ($network_interface_operational eq "DELETED")
if ((($network_interface_bond_uuid) && ($anvil->data->{deleted_bonds}{$network_interface_bond_uuid})) or
(($network_interface_bridge_uuid) && ($anvil->data->{deleted_bridges}{$network_interface_bridge_uuid})) or
($network_interface_operational eq "DELETED"))
{
# Take this one out.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0647", variables => {
@ -880,7 +1186,6 @@ ORDER BY
$count--;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
}
last if $count == 1;
}
# If count is still > 1, we need to arbitrarily delete an interface.
@ -894,6 +1199,7 @@ ORDER BY
}});
my $query = "DELETE FROM network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
$count--;
@ -997,6 +1303,7 @@ ORDER BY
}});
my $query = "DELETE FROM ip_addresses WHERE ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
$count--;
@ -1007,6 +1314,7 @@ ORDER BY
}
}
return(0);
}
@ -3450,9 +3758,11 @@ AND
# Don't set / clear interfaces that appear down but aren't named ifn/bcn/sn as they're probably
# unconfigured/unusued interfaces.
my $problem = 0;
my $check = 0;
if ($anvil->Network->is_our_interface({interface => $network_interface_name}))
my $problem = 0;
my $check = 0;
my $monitored = $anvil->Network->is_our_interface({interface => $network_interface_name});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { monitored => $monitored }});
if ($monitored)
{
# One we monitor
$check = 1;

@ -16,7 +16,7 @@ Author: Madison Kelly <mkelly@alteeve.ca>
<key name="brand_0002">Anvil!</key>
<key name="brand_0003">Striker</key>
<key name="brand_0004">ScanCore</key>
<key name="brand_0005"><![CDATA[&copy; 1997 - 2021 <a href="https://alteeve.com/" target="_new">Alteeve's Niche! Inc.</a>, Toronto, Ontario, Canada]]></key>
<key name="brand_0005"><![CDATA[&copy; 1997 - 2022 <a href="https://alteeve.com/" target="_new">Alteeve's Niche! Inc.</a>, Toronto, Ontario, Canada]]></key>
<key name="brand_0006"><![CDATA[<i>Anvil!</i>]]></key>
<key name="brand_0007">Node</key>
<key name="brand_0008">DR Host</key>
@ -501,6 +501,8 @@ The output, if any, was;
====
</key>
<key name="error_0355">Failed to load the database file: [#!variable!file!#]. Deleting it so it's not considered in the next load attempt.</key>
<key name="error_0356">Failed to read the kernel release on the host: [#!variable!target!#]. The return code was: [#!variable!return_code!#] (expected '0') and the release output, if any, was: [#!variable!output!#].</key>
<key name="error_0357">The program: [#!variable!program!#] is using: [#!variable!ram_used!#] (#!variable!ram_used_bytes!# Bytes). This is probably caused by a memory leak, so we will now exit so that systemctl can restart us. If this is happening repeatedly, please contact support.</key>
<!-- Files templates -->
<!-- NOTE: Translating these files requires an understanding of which lines are translatable -->
@ -1364,7 +1366,7 @@ Connecting to Database with configuration ID: [#!variable!uuid!#]
<key name="log_0057">Updated: [#!variable!file!#] to require passwords for access.</key>
<key name="log_0058"><![CDATA[[ Error ] - The method Remote->call() was called but the port: [#!variable!port!#] is invalid. It must be a digit between '1' and '65535'.]]></key>
<key name="log_0059">Started the PostgreSQL database server.</key>
<key name="log_0060">Database user: [#!variable!user!#] already exists with UUID: [#!variable!uuid!#].</key>
<key name="log_0060">Database user: [#!variable!user!#] already exists with UUID: [#!variable!id!#].</key>
<key name="log_0061"><![CDATA[[ Error ] - The method Get->users_home() was asked to find the home directory for the user: [#!variable!user!#], but was unable to do so.]]></key>
<key name="log_0062">SSH session opened without a password to: [#!variable!target!#].</key>
<key name="log_0063"><![CDATA[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.]]></key>
@ -1421,7 +1423,7 @@ The database connection error was:
- Record Locator: [#!variable!record_locator!#]
- Timestamp: .... [#!variable!modified_date!#]
</key>
<key name="log_0099">[ Error ] - There is no #!string!brand_0002!# database user set for the local machine. Please check: [#!data!path::config::anvil.conf!#]'s DB entry: [#!variable!uuid!#].</key>
<key name="log_0099">[ Warning ] - There is no #!string!brand_0002!# database user set for the local machine. Please check: [#!data!path::config::anvil.conf!#]'s DB entry: [#!variable!uuid!#]. Using 'admin'.</key>
<key name="log_0100">Database user: [#!variable!user!#] password has been set/updated.</key>
<key name="log_0101">Failed to connect to: [#!variable!target!#:#!variable!port!#], sleeping for a second and then trying again.</key>
<key name="log_0102">I am not recording the alert with message_key: [#!variable!message_key!#] to the database because its log level was lower than any recipients.</key>
@ -1521,8 +1523,8 @@ The database connection error was:
<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>
<key name="log_0198">The user: [#!variable!user!#] logged out successfully.</key>
<key name="log_0199">A system reboot is required, setting the database flag.</key>
<key name="log_0200">A system reboot is required, setting the database flag.</key>
<key name="log_0199">A system reboot has been requested via the Striker UI.</key>
<key name="log_0200">A system power-off has been requested via the Striker UI.</key>
<key name="log_0201">Unable to connect to any database. Will try to initialize the local system and then try again.</key>
<key name="log_0202">Failed to connect to any databases. Skipping the loop of the daemon.</key>
<key name="log_0203">Disconnected from all databases. Will reconnect when entering the main loop.</key>
@ -1947,7 +1949,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0562">The host: [#!variable!host_name!#] is up, no need to check if it needs booting.</key>
<key name="log_0563">The host: [#!variable!host_name!#] couldn't be reached directly, but IPMI reports that it is up. Could the IPMI BMC be hung or unplugged?</key>
<key name="log_0564">The host: [#!variable!host_name!#] is off. Will check now if it should be booted.</key>
<key name="log_0565">The host: [#!variable!host_name!#] has no stop reason, so we'll boot it up in case it lost power without warning.</key>
<key name="log_0565">The host: [#!variable!host_name!#] has no stop reason, so we'll check to see if we should power it on, in case it lost power or overheated without warning.</key>
<key name="log_0566">The host: [#!variable!host_name!#] was stopped by the user, so we'll leave it off.</key>
<key name="log_0567">The host: [#!variable!host_name!#] was powered off because of power loss. Checking to see if it is now safe to restart it.</key>
<key name="log_0568">The host: [#!variable!host_name!#] was powered off because of thermal issues. Checking to see if it is now safe to restart it.</key>
@ -1955,7 +1957,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0570">Unable to parse the install manifest uuid: [#!variable!manifest_uuid!#] for the Anvil! [#!variable!anvil_name!#]. As such, unable to determine what UPSes power the machine: [#!variable!host_name!#]. Unable to determine if the power feeding this node is OK or not.</key>
<key name="log_0571">The UPS referenced by the 'power_uuid': [#!variable!power_uuid!#] under the host: [#!variable!host_name!#] has no record of being on mains power, so we can't determine how long it's been on batteries. Setting the "shortest time on batteries" to zero seconds.</key>
<key name="log_0572">Marking the host as 'online' and clearing the host's stop reason.</key>
<key name="log_0573">The host: [#!variable!host_name!#] is off, but there appears to be a problem translating the 'fence_ipmilan' into a workable 'ipmitool' command. Unable to check the thermal data of the host, and so, unable to determine if it's safe to boot the node.</key>
<key name="log_0573">There appears to be a problem translating the 'fence_ipmilan' into a workable 'ipmitool' command for the host: [#!variable!host_name!#]. Unable to check the thermal data of the host.</key>
<key name="log_0574">The host: [#!variable!host_name!#] was powered off because of power loss. Power is back and the UPSes are sufficiently charged. Booting it back up now.</key>
<key name="log_0575">The host: [#!variable!host_name!#] was powered off for thermal reasons. All available thermal sensors read as OK now. Booting it back up now.</key>
<key name="log_0576">The file: [#!variable!file_path!#] isn't on (or isn't the right size on) Striker: [#!variable!host_name!#]. Not using it to pull from.</key>
@ -2056,6 +2058,33 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0663">The target can be reached on the dedicated migration network: [#!variable!target!#] via the IP address: [#!variable!ip!#], switching to use that for the RAM copy.</key>
<key name="log_0664">[ Note ] - The IP address: [#!variable!ip!#] with 'ip_address_uuid': [#!variable!uuid!#] is a duplicate, removing it from the database(s).</key>
<key name="log_0665">The database dump file: [#!variable!file!#] exists, skipping database setup.</key>
<key name="log_0666"><![CDATA[[ Error ] - The method Database->query() was asked to query the database with UUID: [#!variable!old_uuid!#] but there is no file handle open to the database. Switched the read to: [#!variable!new_uuid!#].]]></key>
<key name="log_0667">Opening the firewall zone: [#!variable!zone!#] to allow the service: [#!variable!service!#].</key>
<key name="log_0668">No password for the database on the host with UUID: [#!variable!uuid!#], skipping it.</key>
<key name="log_0669">The firewalld daemon isn't running, skipping firewall setup.</key>
<key name="log_0670">The postgresql server is installed.</key>
<key name="log_0671">The host: [#!variable!host_name!#] was powered off for an unknown reason, and 'feature::scancore::disable::boot-unknown-stop' is set to: [#!data!feature::scancore::disable::boot-unknown-stop!#]. Will not boot this host.</key>
<key name="log_0672">The host: [#!variable!host_name!#] was powered off for an unknown reason, and 'feature::scancore::disable::boot-unknown-stop' is set to: [#!data!feature::scancore::disable::boot-unknown-stop!#]. If power and temperature looks good, we'll boot it.</key>
<key name="log_0673">The host: [#!variable!host_name!#] has good power and temperature readings. Booting it back up now.</key>
<key name="log_0674">The resync has completed in: [#!variable!took!#] second(s).</key>
<key name="log_0675"><![CDATA[[ Error ] - There was a database handle error while preparing the database query: [#!variable!query!#] on: [#!variable!server!#]. The eval error was: [#!variable!eval_error!#]. Note that if the query reports '--', the query was listed as containing sensitive data and '$anvil->Log->secure' is not set. ]]></key>
<key name="log_0676">[ Note ] - The DRBD kernel module failed to load. It is possible the kernel was updated. We will check to see if we can install a pre-built RPM, or if we need to build one ourselves.</key>
<key name="log_0677">Found an installable DRBD kernel module RPM that matches the current kernel. Installing it now.</key>
<key name="log_0678">[ Note ] - We need to build the DRBD kernel module. This can take a few minutes, please be patient! Use 'journalctl -f' to monitor the build process.</key>
<key name="log_0679">Successfully built and installed the new DRBD kernel module!</key>
<key name="log_0680">We were asked to resync the database, but this host is hosting: [#!variable!count!#] server(s). Resync is not allowed when servers are running to reduce the risk the kernel's out of memory handler shooting a VM if the resync consumes too much RAM. You can see which servers are running with 'virsh list' and look for servers whose states are "running", "paused", "in shutdown" or "pmsuspended".</key>
<key name="log_0681">Testing that our short host name resolves to one of our IP prior to starting the cluster.</key>
<key name="log_0682">Changing the ownership of: [#!variable!file!#] to be owned by: [#!variable!user!#:#!variable!user!#].</key>
<key name="log_0683">Enabling 'ping' for all users.</key>
<key name="log_0684">The network interface: [#!variable!nic!#] on the host: [#!variable!host!#] is recorded in the 'history.network_interfaces' table, but has not corresponding entry in the public table. Removing it.</key>
<key name="log_0685">[ Note ] - The network bridge: [#!variable!name!#] with 'bridge_uuid': [#!variable!uuid!#] is a duplicate, removing it from the database(s).</key>
<key name="log_0686">Skipping resync, not a Striker dashboard.</key>
<key name="log_0687">### REBOOT REQUESTED ### - [#!variable!reason!#]</key>
<key name="log_0688">Reboot flag set by command line switch to 'anvil-manage-power'.</key>
<key name="log_0689">Poweroff flag set by command line switch to 'anvil-manage-power'.</key>
<key name="log_0690">Kernel updated, reboot queued.</key>
<key name="log_0691">Requested to power-off as part of the anvil-safe-stop job.</key>
<key name="log_0692">The anvil-safe-stop job has completed and will now power off.</key>
<!-- Messages for users (less technical than log entries), though sometimes used for logs, too. -->
<key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>
@ -2419,6 +2448,8 @@ Are you sure that you want to delete the server: [#!variable!server_name!#]? [Ty
<key name="message_0265">Failed to get server VM screenshot; got non-zero return code.</key>
<key name="message_0266">Finished attempting to get server VM screenshot; no operations happened because requirements not met.</key>>>> master
<key name="message_0267">Preparing to manage DR for a server.</key>
<key name="message_0268">UUID Column counts for: [history.#!variable!table!#]:</key>
<key name="message_0269">Counting entries for each unique: [#!variable!column!#] in the table [#!variable!table!#]. Please be patient.</key>
<!-- Success messages shown to the user -->
<key name="ok_0001">Saved the mail server information successfully!</key>
@ -3080,6 +3111,11 @@ The error was:
We will sleep a bit and try again.
</key>
<key name="warning_0130">[ Warning ] - The storage group: [#!variable!storage_group_name!#] had the host: [#!variable!host_name!#] as a member. This host is not a member (anymore?) of the Anvil!: [#!variable!anvil_name!#]. Removing it from the storage group now.</key>
<key name="warning_0131">[ Warning ] - The postgresql server is not installed yet. Sleeping for a bit, then will check again.</key>
<key name="warning_0132">[ Warning ] - Failed to build or install the DRBD kernel module! It is very unlikely that this machine will be able to run any servers until this is fixed.</key>
<key name="warning_0133">[ Warning ] - Table: [history.#!variable!table!#] not found.</key>
<key name="warning_0134">[ Warning ] - Holding off starting the cluster. Tested access to ourself, and failed. Is '/etc/hosts' populated? Will try again in ten seconds.</key>
<key name="warning_0135">[ Warning ] - The program: [#!variable!program!#] was not found to be running.</key>
<!-- The entries below here are not sequential, but use a key to find the entry. -->
<!-- Run 'striker-parse-os-list to find new entries. -->
@ -3809,7 +3845,7 @@ We will sleep a bit and try again.
<key name="brand_0002">Anvil!</key>
<key name="brand_0003">ストライカ</key>
<key name="brand_0004">スカンコア</key>
<key name="brand_0005"><![CDATA[&copy; 1997 - 2018 <a href="https://alteeve.com/" target="_new">Alteeve's Niche! Inc.</a>, トロント、オンタリオ、カナダ]]></key>
<key name="brand_0005"><![CDATA[&copy; 1997 - 2022 <a href="https://alteeve.com/" target="_new">Alteeve's Niche! Inc.</a>, トロント、オンタリオ、カナダ]]></key>
</language>
</words>

@ -68,9 +68,9 @@
},
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.14.9",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz",
"integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g=="
"version": "7.15.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w=="
}
}
},
@ -437,9 +437,9 @@
}
},
"@hapi/hoek": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz",
"integrity": "sha512-sqKVVVOe5ivCaXDWivIJYVSaEgdQK9ul7a4Kity5Iw7u9+wBAPbX1RMSnLLmp7O4Vzj0WOWwMAJsTL00xwaNug=="
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz",
"integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw=="
},
"@material-ui/core": {
"version": "4.11.4",
@ -518,14 +518,14 @@
}
},
"@napi-rs/triples": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.0.3.tgz",
"integrity": "sha512-jDJTpta+P4p1NZTFVLHJ/TLFVYVcOqv6l8xwOeBKNPMgY/zDYH/YH7SJbvrr/h1RcS9GzbPcLKGzpuK9cV56UA=="
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@napi-rs/triples/-/triples-1.1.0.tgz",
"integrity": "sha512-XQr74QaLeMiqhStEhLn1im9EOMnkypp7MZOwQhGzqp2Weu5eQJbpPxWxixxlYRKWPOmJjsk6qYfYH9kq43yc2w=="
},
"@next/env": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/@next/env/-/env-11.1.1.tgz",
"integrity": "sha512-UEAzlfKofotLmj9LIgNixAfXpRck9rt/1CU9Q4ZtNDueGBJQP3HUzPHlrLChltWY2TA5MOzDQGL82H0a3+i5Ag=="
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/@next/env/-/env-11.1.3.tgz",
"integrity": "sha512-5+vaeooJuWmICSlmVaAC8KG3O8hwKasACVfkHj58xQuCB5SW0TKW3hWxgxkBuefMBn1nM0yEVPKokXCsYjBtng=="
},
"@next/eslint-plugin-next": {
"version": "11.1.0",
@ -537,14 +537,14 @@
}
},
"@next/polyfill-module": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/@next/polyfill-module/-/polyfill-module-11.1.1.tgz",
"integrity": "sha512-9FyVSnz00WGdlLsgc2w1xL1Lm/Q25y6FYIyA+1WlJvT6LA2lbR78GKiHgedzUvrAatVGAcg/Og+d0d7B4tsJOg=="
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/@next/polyfill-module/-/polyfill-module-11.1.3.tgz",
"integrity": "sha512-7yr9cr4a0SrBoVE8psxXWK1wTFc8UzsY8Wc2cWGL7qA0hgtqACHaXC47M1ByJB410hFZenGrpE+KFaT1unQMyw=="
},
"@next/react-dev-overlay": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/@next/react-dev-overlay/-/react-dev-overlay-11.1.1.tgz",
"integrity": "sha512-CXc/A0DbSk5VXYu4+zr0fHm52Zh/LhPlLyVPEctJOZL64ccxkls5xGoXvgolJCku9L0pLjJzvdfAmhNLOp5dyw==",
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/@next/react-dev-overlay/-/react-dev-overlay-11.1.3.tgz",
"integrity": "sha512-zIwtMliSUR+IKl917ToFNB+0fD7bI5kYMdjHU/UEKpfIXAZPnXRHHISCvPDsczlr+bRsbjlUFW1CsNiuFedeuQ==",
"requires": {
"@babel/code-frame": "7.12.11",
"anser": "1.4.9",
@ -592,32 +592,32 @@
}
},
"@next/react-refresh-utils": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-11.1.1.tgz",
"integrity": "sha512-j186y+lWc8BHAuysAWvlOqO9Bp7E3BLK/d/Ju3W2sP5BCH5ZLyLG/p308zSy/O0MGTag0B038ZA1dCy/msouRQ=="
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-11.1.3.tgz",
"integrity": "sha512-144kD8q2nChw67V3AJJlPQ6NUJVFczyn10bhTynn9o2rY5DEnkzuBipcyMuQl2DqfxMkV7sn+yOCOYbrLCk9zg=="
},
"@next/swc-darwin-arm64": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-11.1.1.tgz",
"integrity": "sha512-KyB0aLpfQ+B2dsyGYpkM0ZwK3PV0t4C4b9yjgQc1VoTVnIjzXdDPnNOuVvmD849ZNOHfj3x8e2rlbxkj0lPm3A==",
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-11.1.3.tgz",
"integrity": "sha512-TwP4krjhs+uU9pesDYCShEXZrLSbJr78p12e7XnLBBaNf20SgWLlVmQUT9gX9KbWan5V0sUbJfmcS8MRNHgYuA==",
"optional": true
},
"@next/swc-darwin-x64": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-11.1.1.tgz",
"integrity": "sha512-B3ZXgrGx0bQplbrk2oggPjKPPsmyg8Fl0PJLMTVQ+erQ8g1m5QzyS9P6tB3SiIZa180JgENuguTHlVK5qEj4UA==",
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-11.1.3.tgz",
"integrity": "sha512-ZSWmkg/PxccHFNUSeBdrfaH8KwSkoeUtewXKvuYYt7Ph0yRsbqSyNIvhUezDua96lApiXXq6EL2d1THfeWomvw==",
"optional": true
},
"@next/swc-linux-x64-gnu": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-11.1.1.tgz",
"integrity": "sha512-qvZL7gSKF+E+GZ3L1XiTnE3cOh9rk0wkqimT/q+wwcZA4E720Lu4lrT79I3HPuj6i/JPgGvmNskcnYrDeaoFaw==",
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-11.1.3.tgz",
"integrity": "sha512-PrTBN0iZudAuj4jSbtXcdBdmfpaDCPIneG4Oms4zcs93KwMgLhivYW082Mvlgx9QVEiRm7+RkFpIVtG/i7JitA==",
"optional": true
},
"@next/swc-win32-x64-msvc": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-11.1.1.tgz",
"integrity": "sha512-jhnCiA1De1L+kA0gmHG1AJijHoxOcrETWziDWy8fcqSrM1NlC4aJ5Mnu6k0QMcM9MnmXTA4TQZOEv3kF7vhJUQ==",
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-11.1.3.tgz",
"integrity": "sha512-mRwbscVjRoHk+tDY7XbkT5d9FCwujFIQJpGp0XNb1i5OHCSDO8WW/C9cLEWS4LxKRbIZlTLYg1MTXqLQkvva8w==",
"optional": true
},
"@node-rs/helper": {
@ -959,9 +959,9 @@
}
},
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
},
"ansi-styles": {
"version": "3.2.1",
@ -1307,9 +1307,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001252",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001252.tgz",
"integrity": "sha512-I56jhWDGMtdILQORdusxBOH+Nl/KgQSdDmpJezYddnAkVOmnoU8zwjTV9xAjMIYxr0iPreEAVylCGcmHCjfaOw=="
"version": "1.0.30001285",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001285.tgz",
"integrity": "sha512-KAOkuUtcQ901MtmvxfKD+ODHH9YVDYnBt+TGYSz2KIfnq22CiArbUxXPN9067gNbgMlnNYRSwho8OPXZPALB9Q=="
},
"chalk": {
"version": "2.4.2",
@ -1871,9 +1871,9 @@
}
},
"electron-to-chromium": {
"version": "1.3.826",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.826.tgz",
"integrity": "sha512-bpLc4QU4B8PYmdO4MSu2ZBTMD8lAaEXRS43C09lB31BvYwuk9UxgBRXbY5OJBw7VuMGcg2MZG5FyTaP9u4PQnw=="
"version": "1.4.14",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.14.tgz",
"integrity": "sha512-RsGkAN9JEAYMObS72kzUsPPcPGMqX1rBqGuXi9aa4TBKLzICoLf+DAAtd0fVFzrniJqYzpby47gthCUoObfs0Q=="
},
"elliptic": {
"version": "6.5.4",
@ -2897,6 +2897,15 @@
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
"dev": true
},
"get-symbol-description": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
"integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
"requires": {
"call-bind": "^1.0.2",
"get-intrinsic": "^1.1.1"
}
},
"git-raw-commits": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.10.tgz",
@ -3340,6 +3349,11 @@
"integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=",
"dev": true
},
"is-shared-array-buffer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz",
"integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA=="
},
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
@ -3381,21 +3395,24 @@
},
"dependencies": {
"es-abstract": {
"version": "1.18.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz",
"integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==",
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
"integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
"requires": {
"call-bind": "^1.0.2",
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"get-intrinsic": "^1.1.1",
"get-symbol-description": "^1.0.0",
"has": "^1.0.3",
"has-symbols": "^1.0.2",
"internal-slot": "^1.0.3",
"is-callable": "^1.2.3",
"is-callable": "^1.2.4",
"is-negative-zero": "^2.0.1",
"is-regex": "^1.1.3",
"is-string": "^1.0.6",
"is-regex": "^1.1.4",
"is-shared-array-buffer": "^1.0.1",
"is-string": "^1.0.7",
"is-weakref": "^1.0.1",
"object-inspect": "^1.11.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.2",
@ -3404,6 +3421,11 @@
"unbox-primitive": "^1.0.1"
}
},
"is-callable": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
"integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w=="
},
"is-regex": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
@ -3422,9 +3444,9 @@
}
},
"object-inspect": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz",
"integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA=="
},
"unbox-primitive": {
"version": "1.0.1",
@ -3445,6 +3467,14 @@
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
"dev": true
},
"is-weakref": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz",
"integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==",
"requires": {
"call-bind": "^1.0.0"
}
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@ -4092,9 +4122,9 @@
"dev": true
},
"nanoid": {
"version": "3.1.25",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
"integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q=="
"version": "3.1.30",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ=="
},
"native-url": {
"version": "0.3.4",
@ -4111,20 +4141,20 @@
"dev": true
},
"next": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/next/-/next-11.1.1.tgz",
"integrity": "sha512-vfLJDkwAHsZUho5R1K4w49nfYhftUMWNmeNSjCtulOvnRBuEFb7ROyRZOQk7f29rMz02eLQrPZ9yiAmPsexL2g==",
"version": "11.1.3",
"resolved": "https://registry.npmjs.org/next/-/next-11.1.3.tgz",
"integrity": "sha512-ud/gKmnKQ8wtHC+pd1ZiqPRa7DdgulPkAk94MbpsspfNliwZkYs9SIYWhlLSyg+c661LzdUI2nZshvrtggSYWA==",
"requires": {
"@babel/runtime": "7.15.3",
"@hapi/accept": "5.0.2",
"@next/env": "11.1.1",
"@next/polyfill-module": "11.1.1",
"@next/react-dev-overlay": "11.1.1",
"@next/react-refresh-utils": "11.1.1",
"@next/swc-darwin-arm64": "11.1.1",
"@next/swc-darwin-x64": "11.1.1",
"@next/swc-linux-x64-gnu": "11.1.1",
"@next/swc-win32-x64-msvc": "11.1.1",
"@next/env": "11.1.3",
"@next/polyfill-module": "11.1.3",
"@next/react-dev-overlay": "11.1.3",
"@next/react-refresh-utils": "11.1.3",
"@next/swc-darwin-arm64": "11.1.3",
"@next/swc-darwin-x64": "11.1.3",
"@next/swc-linux-x64-gnu": "11.1.3",
"@next/swc-win32-x64-msvc": "11.1.3",
"@node-rs/helper": "1.2.1",
"assert": "2.0.0",
"ast-types": "0.13.2",
@ -4162,7 +4192,7 @@
"stream-browserify": "3.0.0",
"stream-http": "3.1.1",
"string_decoder": "1.3.0",
"styled-jsx": "4.0.0",
"styled-jsx": "4.0.1",
"timers-browserify": "2.0.12",
"tty-browserify": "0.0.1",
"use-subscription": "1.5.1",
@ -4356,9 +4386,9 @@
}
},
"node-releases": {
"version": "1.1.75",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz",
"integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw=="
"version": "1.1.77",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz",
"integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ=="
},
"normalize-package-data": {
"version": "3.0.2",
@ -5634,9 +5664,9 @@
"dev": true
},
"styled-jsx": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-4.0.0.tgz",
"integrity": "sha512-2USeoWMoJ/Lx5s2y1PxuvLy/cz2Yrr8cTySV3ILHU1Vmaw1bnV7suKdblLPjnyhMD+qzN7B1SWyh4UZTARn/WA==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-4.0.1.tgz",
"integrity": "sha512-Gcb49/dRB1k8B4hdK8vhW27Rlb2zujCk1fISrizCcToIs+55B4vmUM0N9Gi4nnVfFZWe55jRdWpAqH1ldAKWvQ==",
"requires": {
"@babel/plugin-syntax-jsx": "7.14.5",
"@babel/types": "7.15.0",
@ -6031,21 +6061,24 @@
},
"dependencies": {
"es-abstract": {
"version": "1.18.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz",
"integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==",
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
"integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
"requires": {
"call-bind": "^1.0.2",
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"get-intrinsic": "^1.1.1",
"get-symbol-description": "^1.0.0",
"has": "^1.0.3",
"has-symbols": "^1.0.2",
"internal-slot": "^1.0.3",
"is-callable": "^1.2.3",
"is-callable": "^1.2.4",
"is-negative-zero": "^2.0.1",
"is-regex": "^1.1.3",
"is-string": "^1.0.6",
"is-regex": "^1.1.4",
"is-shared-array-buffer": "^1.0.1",
"is-string": "^1.0.7",
"is-weakref": "^1.0.1",
"object-inspect": "^1.11.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.2",
@ -6054,6 +6087,11 @@
"unbox-primitive": "^1.0.1"
}
},
"is-callable": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
"integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w=="
},
"is-regex": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
@ -6072,9 +6110,9 @@
}
},
"object-inspect": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz",
"integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA=="
},
"unbox-primitive": {
"version": "1.0.1",

@ -17,7 +17,7 @@
"@material-ui/icons": "^4.11.2",
"@material-ui/styles": "^4.11.4",
"@novnc/novnc": "^1.2.0",
"next": "^11.1.1",
"next": "^11.1.3",
"pretty-bytes": "^5.6.0",
"react": "17.0.2",
"react-dom": "17.0.2",

@ -50,7 +50,7 @@ dist_sbin_SCRIPTS = \
striker-show-db-counts \
striker-auto-initialize-all
fencedir = $(FASEXECPREFIX)/sbin
fencedir = ${FASEXECPREFIX}/sbin
dist_fence_SCRIPTS = \
fence_delay \

@ -321,12 +321,16 @@ sub boot_all_servers
### TODO: Manage the boot order here.
# We top out at 90, bottom is 20.
my $server_count = keys %{$anvil->data->{cib}{parsed}{data}{server}};
my $increment = int(70 / $server_count);
my $percent = 15;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_count => $server_count,
increment => $increment,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_count => $server_count }});
if (not $server_count)
{
# No servers exist yet.
return(0);
}
my $increment = int(70 / $server_count);
my $percent = 15;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { increment => $increment }});
foreach my $server (sort {$a cmp $b} keys %{$anvil->data->{cib}{parsed}{data}{server}})
{
my $status = $anvil->data->{cib}{parsed}{data}{server}{$server}{status};

@ -50,10 +50,10 @@ if (not $anvil->data->{switches}{program})
# Find the PID(s) of the program.
$anvil->data->{sys}{pids} = $anvil->System->pids({ignore_me => 1, program_name => $anvil->data->{switches}{program}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { 'sys::pids' => $anvil->data->{sys}{pids} }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::pids' => $anvil->data->{sys}{pids} }});
my $pids_found = @{$anvil->data->{sys}{pids}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { pids_found => $pids_found }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { pids_found => $pids_found }});
if (not $pids_found)
{
@ -66,7 +66,7 @@ if (not $pids_found)
foreach my $pid (sort {$a cmp $b} @{$anvil->data->{sys}{pids}})
{
my $smaps_path = "/proc/".$pid."/smaps";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { smaps_path => $smaps_path }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { smaps_path => $smaps_path }});
# This will store the amount of RAM used by this specific PID.
$anvil->data->{memory}{pid}{$pid} = 0;

@ -91,7 +91,10 @@ $anvil->System->_check_anvil_conf();
# 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({check_if_configured => 1, check_for_resync => 1});
$anvil->Database->connect({
check_if_configured => 1,
check_for_resync => 1,
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0132"});
# If I have no databases, sleep for a second and then exit (systemd will restart us).
@ -105,8 +108,7 @@ if (not $anvil->data->{sys}{database}{connections})
prep_database($anvil);
# Try connecting again
$anvil->refresh();
$anvil->Database->connect();
$anvil->Database->connect({check_if_configured => 1, check_for_resync => 1});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
@ -244,6 +246,9 @@ while(1)
$anvil->nice_exit({exit_code => 0});
}
# Check how much RAM we're using.
check_ram($anvil);
# Disconnect from the database(s) and sleep now.
$anvil->Database->disconnect();
sleep(2);
@ -256,6 +261,41 @@ $anvil->nice_exit({exit_code => 0});
# Functions #
#############################################################################################################
# If we're using too much ram, send an alert and exit.
sub check_ram
{
my ($anvil) = @_;
# Problem 0 == ok, 1 == too much ram used, 2 == no pid found
my ($problem, $ram_used) = $anvil->System->check_ram_use({program => $THIS_FILE});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
ram_used => $anvil->Convert->add_commas({number => $ram_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}).")",
}});
if ($problem)
{
# Send an alert and exit.
$anvil->Alert->register({alert_level => "notice", message => "error_0357", variables => {
program => $THIS_FILE,
ram_used => $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}),
ram_used_bytes => $anvil->Convert->add_commas({number => $ram_used}),
}, set_by => $THIS_FILE, sort_position => 0});
$anvil->Email->send_alerts();
# Log the same
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0357", variables => {
program => $THIS_FILE,
ram_used => $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}),
ram_used_bytes => $anvil->Convert->add_commas({number => $ram_used}),
}});
# Exit with RC0 so that systemctl restarts
$anvil->nice_exit({exit_code => 0});
}
return(0);
}
# Check to see if we're mapping the network on this host.
sub check_if_mapping
{
@ -274,7 +314,7 @@ sub check_if_mapping
# shouldn't fire in practice).
my $expire_age = 86400;
my $map_network_age = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:map_network_value' => $map_network_value,
's2:map_network_mtime' => $map_network_mtime,
's3:map_network_modified_date' => $map_network_modified_date,
@ -411,6 +451,39 @@ sub check_network
check_firewall($anvil);
}
# Check that all users can ping.
if (1)
{
my $shell_call = $anvil->data->{path}{exe}{sysctl}." net.ipv4.ping_group_range";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output }});
if ($output =~ /net.ipv4.ping_group_range = (\d+)\t(\d+)$/)
{
my $lowest_uid = $1;
my $highest_uid = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
lowest_uid => $lowest_uid,
highest_uid => $highest_uid,
}});
if ($highest_uid < 2000)
{
# Tell the user we're enabling ping for all users.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0683"});
my $shell_call = $anvil->data->{path}{exe}{sysctl}." -w net.ipv4.ping_group_range=\"0 2147483647\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { output => $output }});
}
}
}
return(0);
}
@ -439,7 +512,7 @@ sub handle_periodic_tasks
check_install_target($anvil);
# Check that the users we care about have ssh public keys and they're recorded in ssh_keys.
$anvil->System->check_ssh_keys({debug => 3});
$anvil->System->check_ssh_keys({debug => 2});
$anvil->System->update_hosts({debug => 3});
@ -506,6 +579,9 @@ sub handle_periodic_tasks
# Check mail server config.
my $problem = $anvil->Email->check_config({debug => 3});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { problem => $problem }});
# Check if any files have been uploaded to /mnt/shared/incoming on striker
check_incoming($anvil);
}
# Now check to see if it's time to run less frequent tasks.
@ -533,6 +609,9 @@ sub handle_periodic_tasks
{
$first_uuid = $uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { first_uuid => $first_uuid }});
# Skip the first UUID so it doesn't evaluate for shutdown.
next;
}
elsif ($uuid eq $host_uuid)
{
@ -693,6 +772,77 @@ sub handle_periodic_tasks
return(0);
}
# On dashboards, this checks to see if any files are in /mnt/shared/incoming and, if so, that they've been processed.
sub check_incoming
{
my ($anvil) = @_;
my $system_type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { system_type => $system_type }});
if ($system_type eq "striker")
{
# Look for files in /mnt/shared/incoming that are not yet in the database.
my $directory = $anvil->data->{path}{directories}{shared}{incoming};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }});
local(*DIRECTORY);
opendir(DIRECTORY, $directory);
while(my $file = readdir(DIRECTORY))
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }});
next if $file eq ".";
next if $file eq "..";
next if $file =~ /^\./; # This is files being rsync'ed still
my $full_path = $directory."/".$file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }});
# Skip anything that is not a file.
next if not -f $full_path;
# Is this file already in the DB?
my $query = "SELECT file_uuid FROM files WHERE file_name = ".$anvil->Database->quote($file).";";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { 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 (not $count)
{
# Add it to the database.
my $size = (stat($full_path))[7];
my $say_size_human = $anvil->Convert->bytes_to_human_readable({'bytes' => $size});
my $say_size_comma = $anvil->Convert->add_commas({number => $size});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
size => $size,
say_size_human => $say_size_human,
say_size_comma => $say_size_comma,
}});
# Register a job to call anvil-sync-shared
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'},
job_data => "file=".$full_path,
job_name => "storage::move_incoming",
job_title => "job_0132",
job_description => "job_0133",
job_progress => 0,
job_host_uuid => $anvil->data->{sys}{host_uuid},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
}
}
closedir(DIRECTORY);
}
return(0);
}
# This calls striker-manage-install-target to see if the dhcpd is running or not. If it is or isn't, the config
# variable 'install-target::enabled' is set/updated. On non-Striker hosts, this simply returns without doing
# anything.
@ -761,7 +911,7 @@ sub run_once
# Check the ssh stuff.
# NOTE: This actually runs again in the minutes tasks, but needs to run on boot as well.
$anvil->System->check_ssh_keys();
$anvil->System->check_ssh_keys({debug => 2});
# Check setuid wrappers
check_setuid_wrappers($anvil);
@ -1124,11 +1274,12 @@ sub handle_special_cases
{
my ($anvil) = @_;
# RHBZ #1961562 - https://bugzilla.redhat.com/show_bug.cgi?id=1961562#c16
my $host_type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }});
if ($host_type ne "striker")
{
### TODO: Test that this is fixed. The bug is now ERRATA
# RHBZ #1961562 - https://bugzilla.redhat.com/show_bug.cgi?id=1961562#c16
# We're a node or DR host. We need to touch this file.
my $work_around_file = "/etc/qemu/firmware/50-edk2-ovmf-cc.json";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { work_around_file => $work_around_file }});
@ -1145,6 +1296,9 @@ sub handle_special_cases
group => "root",
});
}
# Make sure DRBD compiled after a kernel upgrade.
$anvil->DRBD->_initialize_kmod({debug => 2});
}
return(0);
@ -1156,6 +1310,7 @@ sub prep_database
my ($anvil) = @_;
# If there's a backup file, we're configured and possibly just off.
my $prep_database = 1;
foreach my $uuid (keys %{$anvil->data->{database}})
{
my $dump_file = $anvil->data->{path}{directories}{pgsql}."/".$anvil->data->{sys}{database}{name}."_db_dump.".$uuid.".sql";
@ -1165,7 +1320,8 @@ sub prep_database
{
# No need to prepare.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0665", variables => { file => $dump_file }});
return(0);
$prep_database = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { prep_database => $prep_database }});
}
}
@ -1174,13 +1330,37 @@ sub prep_database
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }});
if ($host_type eq "striker")
{
### NOTE: This failed once, in case / until it happens again, we'll force log level 2 and secure logging.
#my ($database_output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{'striker-prep-database'}.$anvil->Log->switches, source => $THIS_FILE, line => __LINE__ });
my ($database_output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{'striker-prep-database'}." -vv --log-secure", source => $THIS_FILE, line => __LINE__ });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
database_output => $database_output,
return_code => $return_code,
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
prep_database => $prep_database,
"sys::database::connections" => $anvil->data->{sys}{database}{connections},
}});
if ($prep_database)
{
### NOTE: This failed once, in case / until it happens again, we'll force log level 2 and secure logging.
my $shell_call = $anvil->data->{path}{exe}{'striker-prep-database'}." -vv --log-secure";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($database_output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call, source => $THIS_FILE, line => __LINE__ });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
database_output => $database_output,
return_code => $return_code,
}});
}
elsif (not $anvil->data->{sys}{database}{connections})
{
# Start the daemon locally, if needed.
my $running = $anvil->System->check_daemon({daemon => "postgresql"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { running => $running }});
if ($running == 2)
{
# Not installed, nothing to do.
}
elsif (not $running)
{
# Start it.
my $return_code = $anvil->System->start_daemon({daemon => "postgresql"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { return_code => $return_code }});
}
}
}
return(0);

@ -2190,7 +2190,7 @@ sub check_local_network
# Configure SSH by adding ours and our peer's SSH keys to ~/.ssh/known_hosts
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "job_0113"});
update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0113");
$anvil->System->check_ssh_keys({debug => 3});
$anvil->System->check_ssh_keys({debug => 2});
# Setup IPMI, if needed.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "job_0114"});

@ -130,6 +130,7 @@ if ($anvil->data->{switches}{'reboot-needed'} eq "1")
# Enable
if (not $reboot_needed)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => "log_0688" }});
$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";
@ -246,6 +247,8 @@ sub do_poweroff
# 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.
my $say_reason = $task eq "poweroff" ? "log_0689" : "log_0688";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => $say_reason }});
$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 }});

@ -661,6 +661,7 @@ sub interactive_configure_main
print "[ 3 ] - Storage\n";
print "[ 4 ] - Network\n";
print "[ 5 ] - Boot Order\n";
print "[ 6 ] - Cluster Management\n";
print "\n";
print "[ B ] - Back\n";
print "[ Q ] - Quit\n";
@ -696,6 +697,11 @@ sub interactive_configure_main
print "Going to Boot order menu\n";
sleep 1;
}
elsif ($answer eq "6")
{
print "Going to cluster manager menu\n";
sleep 1;
}
elsif (lc($answer) eq "b")
{
$anvil->data->{target_server}{server_name} = "";
@ -815,7 +821,7 @@ sub interactive_configure_storage
}});
my $this_storage_group_uuid = $anvil->Storage->get_storage_group_from_path({
debug => 3,
debug => 2,
anvil_uuid => $anvil_uuid,
path => $this_path,
});

@ -237,6 +237,51 @@ sub start_pacemaker
# Nope, start it.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "log_0608"});
# NOTE: In some odd cases, this can try to run before /etc/hosts has been populated. So wait
# until we can access ourself.
my $ok = 0;
until ($ok)
{
# Convert out short host name to an IP and verify that the IP is one of ours.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0681"});
my $local_bcn1_ip = $anvil->Convert->host_name_to_ip({debug => 2, host_name => $short_host_name});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_bcn1_ip => $local_bcn1_ip }});
if ($local_bcn1_ip)
{
# Is this one of our IPs, or is DNS being a little shit?
if (exists $anvil->data->{network}{$short_host_name})
{
delete $anvil->data->{network}{$short_host_name};
}
$anvil->Network->get_ips();
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$short_host_name}{interface}})
{
next if $anvil->data->{network}{$short_host_name}{interface}{$interface}{ip} eq "";
next if $anvil->data->{network}{$short_host_name}{interface}{$interface}{ip} =~ /^127\.0\.0\./;
my $this_ip = $anvil->data->{network}{$short_host_name}{interface}{$interface}{ip};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:interface' => $interface,
's2:this_ip' => $this_ip,
}});
if ($this_ip eq $local_bcn1_ip)
{
$ok = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ok => $ok }});
last;
}
}
}
if (not $ok)
{
# Sleep 10 seconds.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "warning_0134"});
sleep 10;
}
}
### TODO: A lot more testing is needed for degraded single-node start later.
### Should we use --all, or wait for our peer? For now, we wait.
#my $shell_call = $anvil->data->{path}{exe}{pcs}." cluster start --all";

@ -101,6 +101,7 @@ if ($anvil->data->{switches}{'job-uuid'})
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::power-off' => $anvil->data->{switches}{'power-off'},
}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => "log_0691" }});
}
if ($line =~ /stop-reason=(.*?)$/)
{
@ -156,6 +157,7 @@ if ($anvil->data->{switches}{'power-off'})
host_status => "stopping",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => "log_0692" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0325"});
$anvil->Job->update_progress({progress => 100, message => "job_0325"});

@ -48,7 +48,7 @@ if (not $anvil->data->{switches}{'job-uuid'})
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::job-uuid" => $anvil->data->{switches}{'job-uuid'} }});
}
# If we still don't have a job-uuit, go into interactive mode.
# If we still don't have a job-uuid, go into interactive mode.
if ($anvil->data->{switches}{'job-uuid'})
{
# Load the job data.

@ -42,6 +42,10 @@ process_interface_cache($anvil);
update_network($anvil);
# Write out the interface cache
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"cache::new_file" => $anvil->data->{cache}{new_file},
"path::data::network_cache" => $anvil->data->{path}{data}{network_cache},
}});
$anvil->Storage->write_file({
debug => 3,
body => $anvil->data->{cache}{new_file},
@ -446,7 +450,14 @@ sub update_network
if ($line =~ /Supported ports: \[ (.*?) \]/i)
{
$media = lc($1);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { media => $media }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }});
# This can be 'tp mii', which breaks json.
if ($media =~ /\t/)
{
$media =~ s/\t/,/g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }});
}
last;
}
}
@ -948,7 +959,7 @@ ORDER BY
network_interface_bond_uuid => defined $row->[9] ? $row->[9] : 'NULL',
network_interface_bridge_uuid => defined $row->[10] ? $row->[10] : 'NULL',
};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"network_interfaces::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address},
"network_interfaces::${network_interface_uuid}::network_interface_name" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_name},
"network_interfaces::${network_interface_uuid}::network_interface_speed" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed},

@ -173,8 +173,7 @@ sub run_os_update
if ($line =~ /^kernel /)
{
# Reboot will be needed.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0199"});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => "log_0690" }});
my $reboot_needed = $anvil->System->reboot_needed({set => 1});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { reboot_needed => $reboot_needed }});
}

@ -163,6 +163,9 @@ while(1)
# Clean up
cleanup_after_run($anvil);
# Check how much RAM we're using.
check_ram($anvil);
# Sleep until it's time to run again.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0249", variables => {
run_interval => $run_interval,
@ -181,6 +184,41 @@ $anvil->nice_exit({exit_code => 0});
# Functions #
#############################################################################################################
# If we're using too much ram, send an alert and exit.
sub check_ram
{
my ($anvil) = @_;
# Problem 0 == ok, 1 == too much ram used, 2 == no pid found
my ($problem, $ram_used) = $anvil->System->check_ram_use({program => $THIS_FILE});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
ram_used => $anvil->Convert->add_commas({number => $ram_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}).")",
}});
if ($problem)
{
# Send an alert and exit.
$anvil->Alert->register({alert_level => "notice", message => "error_0357", variables => {
program => $THIS_FILE,
ram_used => $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}),
ram_used_bytes => $anvil->Convert->add_commas({number => $ram_used}),
}, set_by => $THIS_FILE, sort_position => 0});
$anvil->Email->send_alerts();
# Log the same
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0357", variables => {
program => $THIS_FILE,
ram_used => $anvil->Convert->bytes_to_human_readable({'bytes' => $ram_used}),
ram_used_bytes => $anvil->Convert->add_commas({number => $ram_used}),
}});
# Exit with RC0 so that systemctl restarts
$anvil->nice_exit({exit_code => 0});
}
return(0);
}
# This cleans things up after a scan run has completed.
sub cleanup_after_run
{

@ -1425,7 +1425,7 @@ sub striker_stage1
{
my ($anvil) = @_;
### TODO: Validate all steps up front before starting anything.
# Validate
if ((not defined $anvil->data->{base}{organization_name}) or (not $anvil->data->{base}{organization_name}))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { variable => 'base::organization_name' }});

@ -0,0 +1,381 @@
#!/usr/bin/perl
#
# This tool looks at the database and counts how many records are in each database. Optionally, if given a
# table name, it will count the number of entries exist in the history schema for each record in the public
# schema. The goal being to help quickly identifying rapidly growing tables.
#
use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
use Text::Diff;
$| = 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();
$anvil->Database->connect({debug => 3, check_for_resync => 0});
$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.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003"});
$anvil->nice_exit({exit_code => 1});
}
# When set, records are counted in the public table, the the number of history entries for each columng is
# shown, sorted by frequency.
$anvil->data->{switches}{table} = "";
# When set, tables with less than the minium are ignored.
$anvil->data->{switches}{minimum} = 0;
$anvil->Get->switches();
$anvil->data->{switches}{minimum} =~ s/,//g;
if ($anvil->data->{switches}{table})
{
count_table($anvil);
}
else
{
count_all($anvil);
}
$anvil->nice_exit({exit_code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
sub count_table
{
my ($anvil) = @_;
# Make sure the table exists.
my $table = $anvil->Database->quote($anvil->data->{switches}{table});
$table =~ s/^\s+//;
$table =~ s/\s.*//;
$table =~ s/^'(.*)'$/$1/;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { table => $table }});
my $query = "
SELECT
COUNT(*)
FROM
information_schema.tables
WHERE
table_schema = 'history'
AND
table_name = '".$table."'
AND
table_catalog = 'anvil'
;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
if (not $count)
{
# Table doesn't exist.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "warning_0133", variables => { table => $table }});
$anvil->nice_exit({exit_code => 1});
}
my $uuid_width = 0;
my $count_width = 0;
my $column1 = $table."_uuid";
my $column2 = "";
my $column3 = "";
my $column4 = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { column1 => $column1 }});
if ($table =~ /^(.*)s$/)
{
$column2 = $1."_uuid";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { column2 => $column2 }});
}
if ($table =~ /^(.*)es$/)
{
$column3 = $1."_uuid";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { column3 => $column3 }});
}
if ($table =~ /^(.*)ies$/)
{
$column4 = $1."y_uuid";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { column4 => $column4 }});
}
$query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = 'anvil' AND table_schema = 'public' AND table_name = '".$table."' AND data_type = 'uuid' AND is_nullable = 'NO' AND column_name = ".$anvil->Database->quote($column1).";";
if ($column4)
{
$query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = 'anvil' AND table_schema = 'public' AND table_name = '".$table."' AND data_type = 'uuid' AND is_nullable = 'NO' AND (column_name = ".$anvil->Database->quote($column1)." OR column_name = ".$anvil->Database->quote($column2)." OR column_name = ".$anvil->Database->quote($column3)." OR column_name = ".$anvil->Database->quote($column4).");";
}
elsif ($column3)
{
$query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = 'anvil' AND table_schema = 'public' AND table_name = '".$table."' AND data_type = 'uuid' AND is_nullable = 'NO' AND (column_name = ".$anvil->Database->quote($column1)." OR column_name = ".$anvil->Database->quote($column2)." OR column_name = ".$anvil->Database->quote($column3).");";
}
elsif ($column2)
{
$query = "SELECT column_name FROM information_schema.columns WHERE table_catalog = 'anvil' AND table_schema = 'public' AND table_name = '".$table."' AND data_type = 'uuid' AND is_nullable = 'NO' AND (column_name = ".$anvil->Database->quote($column1)." OR column_name = ".$anvil->Database->quote($column2).");";
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
my $uuid_column = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$uuid_column = "" if not defined $uuid_column;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid_column => $uuid_column }});
if (not $uuid_column)
{
# This is a problem
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "err", key => "error_0311", variables => { table => $table }});
$anvil->nice_exit({exit_code => 1});
}
# This can take a while, ask the user to be patient.
print $anvil->Words->string({key => "message_0269", variables => {
table => $table,
column => $uuid_column,
}})."\n";
# Count how many entries exist for each UUID.
$query = "
SELECT
DISTINCT ".$uuid_column."
FROM
history.".$table."
;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
$count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $column_uuid = $row->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { column_uuid => $column_uuid }});
if (length($column_uuid) > $uuid_width)
{
$uuid_width = length($column_uuid);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid_width => $uuid_width }});
}
my $query = "
SELECT
COUNT(*)
FROM
history.".$table."
WHERE
".$uuid_column." = ".$anvil->Database->quote($column_uuid)."
;";
my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
my $comma_count = $anvil->Convert->add_commas({number => $count});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
count => $count,
comma_count => $comma_count,
}});
$anvil->data->{db_counts}{count}{$count}{$column_uuid} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"db_counts::count::${count}::${column_uuid}" => $anvil->data->{db_counts}{count}{$count}{$column_uuid},
}});
if (length($comma_count) > $count_width)
{
$count_width = length($comma_count);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count_width => $count_width }});
}
print ".";
}
print "\n";
my $queries = [];
my $divider = "-";
for (1..$uuid_width) { $divider .= "-"; }
$divider .= "-+-";
for (1..$count_width) { $divider .= "-"; }
$divider .= "-";
print $anvil->Words->string({key => "message_0268", variables => { table => $table }})."\n";
print $divider."\n";
foreach my $count (sort {$a <=> $b} keys %{$anvil->data->{db_counts}{count}})
{
my $comma_count = $anvil->Convert->add_commas({number => $count});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
count => $count,
comma_count => $comma_count,
}});
if (($anvil->data->{switches}{minimum}) && ($anvil->data->{switches}{minimum} =~ /^\d+$/) && ($count < $anvil->data->{switches}{minimum}))
{
# Skip it.
next;
}
# Sorting by UUID doesn't really make sense, but it provides consistency run over run.
foreach my $column_uuid (sort {$a cmp $b} keys %{$anvil->data->{db_counts}{count}{$count}})
{
print " ".sprintf("%${uuid_width}s", $column_uuid)." | ".sprintf("%${count_width}s", $comma_count)." \n";
# This will need to be updated by the person debugging a table.
#push @{$queries}, "SELECT variable_name, variable_value, variable_source_table, variable_source_uuid FROM variables WHERE variable_uuid = '".$column_uuid."';";
}
}
print $divider."\n";
# Enable this if you're trying to figure out what data is growing, it needs to be edited on a
# per-table basis.
if (0)
{
foreach my $query (@{$queries})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { 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 => 3, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $variable_name = $row->[0];
my $variable_value = $row->[1];
my $source_table = $row->[2];
my $source_uuid = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:variable_name' => $variable_name,
's2:variable_value' => $variable_value,
's3:source_table' => $source_table,
's4:source_uuid' => $source_uuid,
}});
if ($source_table eq "hosts")
{
my $host_name = $anvil->Get->host_name_from_uuid({host_uuid => $source_uuid});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
}
}
}
}
return(0);
}
sub count_all
{
my ($anvil) = @_;
my $longest_table = 0;
my $longest_public = 0;
my $longest_history = 0;
my $query = "
SELECT
table_schema,
table_name
FROM
information_schema.tables
WHERE
(table_schema = 'public' OR table_schema = 'history')
AND
table_catalog = 'anvil'
ORDER BY
table_name ASC,
table_schema DESC;
;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { 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,
}});
foreach my $row (@{$results})
{
my $table_schema = $row->[0];
my $table_name = $row->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
table_schema => $table_schema,
table_name => $table_name,
}});
if (not exists $anvil->data->{db_counts}{table}{$table_name})
{
$anvil->data->{db_counts}{table}{$table_name}{public} = 0;
$anvil->data->{db_counts}{table}{$table_name}{history} = -1;
}
if (length($table_name) > $longest_table)
{
$longest_table = length($table_name);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { longest_table => $longest_table }});
}
my $query = "SELECT COUNT(*) FROM ".$table_schema.".".$table_name.";";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
my $comma_count = $anvil->Convert->add_commas({number => $count});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
count => $count,
comma_count => $comma_count,
}});
if ($table_schema eq "public")
{
if (length($comma_count) > $longest_public)
{
$longest_public = length($comma_count);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { longest_public => $longest_public }});
}
}
else
{
if (length($comma_count) > $longest_history)
{
$longest_history = length($comma_count);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { longest_history => $longest_history }});
}
}
$anvil->data->{db_counts}{table}{$table_name}{$table_schema} = $count;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"db_counts::table::${table_name}::${table_schema}" => $anvil->data->{db_counts}{table}{$table_name}{$table_schema},
}});
}
my $say_table = $anvil->Words->string({key => "header_0062"});
my $say_public = $anvil->Words->string({key => "header_0063"});
my $say_history = $anvil->Words->string({key => "header_0064"});
my $divider = "-";
for (1..$longest_table) { $divider .= "-"; }
$divider .= "-+-";
for (1..$longest_public) { $divider .= "-"; }
$divider .= "-+-";
for (1..$longest_history) { $divider .= "-"; }
$divider .= "-";
print " ".sprintf("%${longest_table}s", "Table")." | ".sprintf("%${longest_public}s", $say_public)." | ".sprintf("%${longest_history}s", $say_history)." \n";
print $divider."\n";
foreach my $table_name (sort {$a cmp $b} keys %{$anvil->data->{db_counts}{table}})
{
if (($anvil->data->{switches}{minimum}) && ($anvil->data->{switches}{minimum} =~ /^\d+$/))
{
if (($anvil->data->{db_counts}{table}{$table_name}{public} < $anvil->data->{switches}{minimum}) &&
($anvil->data->{db_counts}{table}{$table_name}{history} < $anvil->data->{switches}{minimum}))
{
# Skip it.
next;
}
}
my $public = $anvil->Convert->add_commas({number => $anvil->data->{db_counts}{table}{$table_name}{public}});
my $history = $anvil->data->{db_counts}{table}{$table_name}{history} == -1 ? "--" : $anvil->Convert->add_commas({number => $anvil->data->{db_counts}{table}{$table_name}{history}});
print " ".sprintf("%${longest_table}s", $table_name)." | ".sprintf("%${longest_public}s", $public)." | ".sprintf("%${longest_history}s", $history)." \n";
}
print $divider."\n";
return(0);
}

@ -0,0 +1,318 @@
#!/usr/bin/perl
#
# This is the command line user interface for managing files on /mnt/shared/files on Strikers and made
# available on Anvil! systems.
#
use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
require POSIX;
use Term::Cap;
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();
# Read switches (target ([user@]host[:port]) and the file with the target's password.
$anvil->Get->switches;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }});
# Connect to the database(s).
$anvil->Database->connect;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0132"});
my $termios = new POSIX::Termios;
$termios->getattr;
my $ospeed = $termios->getospeed;
my $terminal = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed };
$terminal->Trequire(qw/ce ku kd/);
interactive_menu($anvil, $termios);
$anvil->nice_exit({exit_code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
sub interactive_menu
{
my ($anvil, $termios) = @_;
# This has to run on a striker, so is this a Striker?
my $host_type = $anvil->Get->host_type;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }});
if ($host_type ne "striker")
{
print "Managing files must be run on a Striker dashboard. Exiting\n";
$anvil->nice_exit({exit_code => 1});
}
$anvil->data->{manaing}{file} = "";
$anvil->data->{manaing}{anvil} = "";
while(1)
{
# Get a list of files we already know about. Database->get_anvils() also loads files and
# file_locations data
$anvil->Database->get_anvils;
my $longest_file_name = 0;
print $terminal->Tputs('cl');
print "-=] Anvil! File Management\n\n";
# Show the main menu.
print "[ 1 ] - Add a new file.\n";
print "[ 2 ] - Manage an existing file.\n";
print "[ 3 ] - Manage files on an Anvil!\n";
print "\n";
print "[ Q ] - Quit\n";
print "\n";
print $terminal->Tgoto('cm', 0, 8)."? ";
my $answer = <STDIN>;
chomp $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
if ($answer eq "1")
{
interactive_menu_add_file($anvil, $terminal);
}
elsif ($answer eq "2")
{
interactive_menu_manage_file($anvil, $terminal);
}
elsif ($answer eq "2")
{
interactive_menu_manage_anvil($anvil, $terminal);
}
elsif (lc($answer) eq "q")
{
print "NO CARRIER, good bye.\n";
$anvil->nice_exit({exit_code => 0});
}
}
return(0);
}
sub interactive_menu_add_file
{
my ($anvil, $terminal) = @_;
print $terminal->Tputs('cl');
print "-=] Anvil! File Management - Add a new file\n\n";
# Build a list of files in /mnt/shared/incoming/ that are not yet in the database.
get_file_list($anvil);
# Start the array with an empty entry so that users can answer '1' for the first file.
my $files = [""];
foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{manage_files}})
{
if ($anvil->data->{manage_files}{$file_name}{file_new})
{
push @{$files}, $file_name;
}
}
my $file_count = (@{$files} - 1);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_count => $file_count }});
if (not $file_count)
{
print "<No new files found in: [".$anvil->data->{path}{directories}{shared}{incoming}."]>\n";
# Show the main menu.
print "\n";
print "[ B ] - Back\n";
print "[ Q ] - Quit\n";
print "\n";
print $terminal->Tgoto('cm', 0, 7)."? ";
my $answer = <STDIN>;
chomp $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
if (lc($answer) eq "b")
{
interactive_menu($anvil, $terminal);
}
elsif (lc($answer) eq "q")
{
print "NO CARRIER, good bye.\n";
$anvil->nice_exit({exit_code => 0});
}
else
{
interactive_menu_add_file($anvil, $terminal);
}
}
else
{
my $pad = 1;
if ($file_count > 9)
{
$pad = 2;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { pad => $pad }});
foreach my $i (0..$file_count)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "files->[".$i."]" => $files->[$i] }});
next if $files->[$i] eq "";
my $file_name = $files->[$i];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_name => $file_name }});
print "[ ".sprintf("%${pad}s", $i)." ] - ".$file_name."\n";
}
print "\n";
print "[ B ] - Back\n";
print "[ Q ] - Quit\n";
print "\n";
print $terminal->Tgoto('cm', 0, ($file_count + 6))."Which file would you like to add? ";
my $answer = <STDIN>;
chomp $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
if (($answer =~ /^\d+$/) && (exists $files->[$answer]) and ($files->[$answer]))
{
my $file_name = $files->[$answer];
print $terminal->Tputs('cl');
print "-=] Anvil! File Management - Add a new file\n\n";
print "Confirm addition of: [".$file_name."] [y/N] ?\n";
my $answer = <STDIN>;
chomp $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
if ($answer =~ /^y/i)
{
print "Creating a job to add the file. Please be patient, it should be added shortly.\n";
my $out_file = $anvil->data->{path}{directories}{shared}{incoming}."/".$file_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { out_file => $out_file }});
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'},
job_data => "file=".$out_file,
job_name => "storage::move_incoming",
job_title => "job_0132",
job_description => "job_0133",
job_progress => 0,
job_host_uuid => $anvil->data->{sys}{host_uuid},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
print "- Job created as: [".$job_uuid."]\n\n";
print "Press any key to return to the main menu.\n";
my $answer = <STDIN>;
chomp $answer;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }});
interactive_menu($anvil, $terminal);
}
else
{
print "Aborted.\n";
sleep 1;
interactive_menu_add_file($anvil, $terminal);
}
}
elsif (lc($answer) eq "b")
{
interactive_menu($anvil, $terminal);
}
elsif (lc($answer) eq "q")
{
print "NO CARRIER, good bye.\n";
$anvil->nice_exit({exit_code => 0});
}
else
{
interactive_menu_add_file($anvil, $terminal);
}
}
return(0);
}
sub interactive_menu_manage_file
{
my ($anvil, $terminal) = @_;
print $terminal->Tputs('cl');
print "-=] Anvil! File Management - Manage an existing file\n\n";
if (0)
{
}
else
{
print "NO CARRIER, good bye.\n";
$anvil->nice_exit({exit_code => 0});
}
return(0);
}
sub interactive_menu_manage_anvil
{
my ($anvil, $terminal) = @_;
print $terminal->Tputs('cl');
print "-=] Anvil! File Management - Manage Files on an Anvil!\n\n";
if (0)
{
}
else
{
print "NO CARRIER, good bye.\n";
$anvil->nice_exit({exit_code => 0});
}
return(0);
}
# This looks for files in /mnt/shared/incoming and collects their file_uuid, if found in the database.
sub get_file_list
{
my ($anvil) = @_;
if (exists $anvil->data->{manage_files})
{
delete $anvil->data->{manage_files};
}
my $directory = $anvil->data->{path}{directories}{shared}{incoming};
local(*DIRECTORY);
opendir(DIRECTORY, $directory);
while(my $file_name = readdir(DIRECTORY))
{
next if $file_name eq ".";
next if $file_name eq "..";
# Ignore hidden files (which includes files still being copied)
next if $file_name =~ /^\./;
my $full_path = $directory."/".$file_name;
# No file should match, but just in case...
if (exists $anvil->data->{files}{file_name}{$file_name})
{
### TODO: Log that this is a duplicate.
$anvil->data->{manage_files}{$file_name}{file_uuid} = $anvil->data->{files}{file_name}{$file_name}{file_uuid};
$anvil->data->{manage_files}{$file_name}{file_new} = 0;
}
else
{
$anvil->data->{manage_files}{$file_name}{file_uuid} = "";
$anvil->data->{manage_files}{$file_name}{file_new} = 1;
}
}
closedir(DIRECTORY);
return(0);
}

@ -340,7 +340,7 @@ sub get_password
}
my $query = "SELECT state_note FROM states WHERE state_uuid = ".$anvil->Database->quote($anvil->data->{switches}{'state-uuid'}).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $password = $anvil->Database->query({uuid => $anvil->data->{sys}{host_uuid}, debug => 3, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$password = "" if not defined $password;

@ -176,7 +176,7 @@ if ($anvil->data->{switches}{disable})
# Exit if we're not configured yet
my $configured = $anvil->System->check_if_configured;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configured => $configured }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { configured => $configured }});
if (not $configured)
{
print $anvil->Words->string({key => "error_0046"})."\n";

@ -10,6 +10,9 @@
# 3 = ScanCore user not set in the local ID in anvil.conf
# 4 = Failed to create the database user.
# 5 = PostgreSQL not installed.
#
# TODO: Much of this logic is duplicated in Database->configure_pgsql(), we should remove this tool entirely
# and use that.
use strict;
use warnings;
@ -29,7 +32,9 @@ $| = 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 }});
$anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }});
$anvil->System->_check_anvil_conf({debug => 2});
@ -39,8 +44,14 @@ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list
# If we didn't get the $local_uuid, then there is no entry for this system in anvil.conf yet, so we'll add it.
if (not $local_uuid)
{
$local_uuid = add_to_local_config($anvil);
$local_uuid = $anvil->Database->_add_to_local_config({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_uuid => $local_uuid }});
if ($local_uuid eq "!!error!!")
{
# Already logged the error, exit.
$anvil->nice_exit({exit_code => 1});
}
}
# Now configure!
@ -49,15 +60,39 @@ if ($local_uuid)
# Start checks
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::service::postgresql" => $anvil->data->{sys}{daemon}{postgresql} }});
my $running = $anvil->System->check_daemon({debug => 3, daemon => $anvil->data->{sys}{daemon}{postgresql}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { running => $running }});
if ($running eq "2")
# Check that the firewall is open.
configure_firewall($anvil);
# Wait until postgresql is installed, in case we're running during initial dnf install.
my $installed = 0;
until($installed)
{
# Not installed.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0144"});
$anvil->nice_exit({exit_code => 5});
my $shell_call = $anvil->data->{path}{exe}{rpm}." -q postgresql-server";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 3, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
output => $output,
return_code => $return_code,
}});
if ($return_code)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0131"});
sleep 5;
}
else
{
# Installed.
$installed = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { installed => $installed }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0670"});
}
}
elsif (not $running)
my $running = $anvil->System->check_daemon({debug => 2, daemon => $anvil->data->{sys}{daemon}{postgresql}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { running => $running }});
if (not $running)
{
# Do we need to initialize the databae?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "path::configs::pg_hba.conf" => $anvil->data->{path}{configs}{'pg_hba.conf'} }});
@ -69,8 +104,11 @@ if ($local_uuid)
else
{
# Initialize.
my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{'postgresql-setup'}." --initdb --unit postgresql", source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
my $shell_call = $anvil->data->{path}{exe}{'postgresql-setup'}." --initdb --unit postgresql";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
output => $output,
return_code => $return_code,
}});
@ -245,10 +283,13 @@ if ($local_uuid)
if (not $database_user)
{
# No database user defined
$database_user = "admin";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0099", variables => { uuid => $local_uuid }});
$anvil->nice_exit({exit_code => 3});
}
my ($user_list, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT usename, usesysid FROM pg_catalog.pg_user;'\"", source => $THIS_FILE, line => __LINE__});
my $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT usename, usesysid FROM pg_catalog.pg_user;'\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($user_list, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
user_list => $user_list,
return_code => $return_code,
@ -259,7 +300,10 @@ if ($local_uuid)
{
# User exists already
my $id = $1;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0060", variables => { user => $database_user, id => $id }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0060", variables => {
user => $database_user,
id => $id,
}});
$create_user = 0;
last;
}
@ -268,13 +312,18 @@ if ($local_uuid)
if ($create_user)
{
# Create the user
my ($create_output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createuser}." --no-superuser --createdb --no-createrole $database_user\"", source => $THIS_FILE, line => __LINE__});
my $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createuser}." --no-superuser --createdb --no-createrole $database_user\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($create_output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
create_output => $create_output,
user_list => $user_list,
}});
(my $user_list, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT usename, usesysid FROM pg_catalog.pg_user;'\"", source => $THIS_FILE, line => __LINE__});
undef $shell_call;
$shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT usename, usesysid FROM pg_catalog.pg_user;'\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
(my $user_list, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
create_output => $create_output,
user_list => $user_list,
@ -296,26 +345,28 @@ if ($local_uuid)
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0096", variables => { user => $database_user }});
$anvil->nice_exit({exit_code => 4});
}
}
# Update/set the passwords.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { "database::${local_uuid}::password" => $anvil->data->{database}{$local_uuid}{password} }});
if ($anvil->data->{database}{$local_uuid}{password})
# Update/set the passwords.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { "database::${local_uuid}::password" => $anvil->data->{database}{$local_uuid}{password} }});
if ($anvil->data->{database}{$local_uuid}{password})
{
foreach my $user ("postgres", $database_user)
{
foreach my $user ("postgres", $database_user)
my $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c \\\"ALTER ROLE $user WITH PASSWORD '".$anvil->data->{database}{$local_uuid}{password}."';\\\"\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($update_output, $return_code) = $anvil->System->call({secure => 1, shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => {
update_output => $update_output,
return_code => $return_code,
}});
foreach my $line (split/\n/, $user_list)
{
my ($update_output, $return_code) = $anvil->System->call({secure => 1, shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c \\\"ALTER ROLE $user WITH PASSWORD '".$anvil->data->{database}{$local_uuid}{password}."';\\\"\"", source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => {
update_output => $update_output,
return_code => $return_code,
}});
foreach my $line (split/\n/, $user_list)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /ALTER ROLE/)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /ALTER ROLE/)
{
# Password set
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0100", variables => { user => $user }});
}
# Password set
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0100", variables => { user => $user }});
}
}
}
@ -325,9 +376,17 @@ if ($local_uuid)
my $create_database = 1;
my $database_name = $anvil->data->{database}{$local_uuid}{name} ? $anvil->data->{database}{$local_uuid}{name} : $anvil->data->{sys}{database}{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { database_name => $database_name }});
if (not $database_name)
{
$database_name = "anvil";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { database_name => $database_name }});
}
undef $return_code;
(my $database_list, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT datname FROM pg_catalog.pg_database;'\"", source => $THIS_FILE, line => __LINE__});
undef $shell_call;
$shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT datname FROM pg_catalog.pg_database;'\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
(my $database_list, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
database_list => $database_list,
return_code => $return_code,
@ -343,25 +402,32 @@ if ($local_uuid)
last;
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { create_database => $create_database }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { create_database => $create_database }});
if ($create_database)
{
my ($create_output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createdb}." --owner ".$database_user." ".$database_name."\"", source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
my $shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{createdb}." --owner ".$database_user." ".$database_name."\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }});
my ($create_output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
create_output => $create_output,
return_code => $return_code,
}});
undef $return_code;
my $database_exists = 0;
(my $database_list, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT datname FROM pg_catalog.pg_database;'\"", source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
undef $shell_call;
my $database_exists = 0;
$shell_call = $anvil->data->{path}{exe}{su}." - postgres -c \"".$anvil->data->{path}{exe}{psql}." template1 -c 'SELECT datname FROM pg_catalog.pg_database;'\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }});
(my $database_list, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
database_list => $database_list,
return_code => $return_code,
}});
foreach my $line (split/\n/, $database_list)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { line => $line }});
if ($line =~ /^ $database_name$/)
{
# Database created
@ -373,11 +439,14 @@ if ($local_uuid)
if (not $database_exists)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0109", variables => { database => $database_name }});
$anvil->nice_exit({exit_code => 5});
}
}
# Remove the temporary password file.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
created_pgpass => $created_pgpass,
"path::secure::postgres_pgpass" => $anvil->data->{path}{secure}{postgres_pgpass},
}});
if (($created_pgpass) && (-e $anvil->data->{path}{secure}{postgres_pgpass}))
{
unlink $anvil->data->{path}{secure}{postgres_pgpass};
@ -394,6 +463,7 @@ if ($local_uuid)
### TODO: This will need to set the proper SELinux context.
# Apache run scripts can't call the system UUID, so we'll write it to a text file.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "path::data::host_uuid" => $anvil->data->{path}{data}{host_uuid} }});
if (not -e $anvil->data->{path}{data}{host_uuid})
{
$anvil->Storage->write_file({
@ -410,6 +480,7 @@ if ($local_uuid)
# Log level 3 creates so much logging that it hits journald's rate limiting (1000 logs per 30
# seconds). So we need to disable it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "path::configs::journald_anvil" => $anvil->data->{path}{configs}{'journald_anvil'} }});
if (not -e $anvil->data->{path}{configs}{'journald_anvil'})
{
# Write the file to disable journald rate limiting.
@ -432,7 +503,10 @@ RateLimitBurst=0
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0012", variables => { file => $anvil->data->{path}{configs}{'journald_anvil'} }});
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{systemctl}." restart systemd-journald.service", source => $THIS_FILE, line => __LINE__});
my $shell_call = $anvil->data->{path}{exe}{systemctl}." restart systemd-journald.service";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
@ -452,48 +526,122 @@ $anvil->nice_exit({exit_code => 0});
# Functions #
#############################################################################################################
# This adds this machine to the local anvil.conf file.
sub add_to_local_config
sub configure_firewall
{
my ($anvil) = @_;
# Write the password to a file.
my $password_file = "/tmp/striker-manage-peers.".$anvil->Get->uuid;
$anvil->Storage->write_file({
debug => 3,
secure => 1,
file => $password_file,
body => "Initial1",
mode => "0600",
overwrite => 1,
});
# Make the shell call, and parse the output looking for our own entry
my $host_uuid = $anvil->Get->host_uuid();
my ($output, $return_code) = $anvil->System->call({
debug => 2,
shell_call => $anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$anvil->Get->host_uuid." --host localhost --port 5432 --password-file ".$password_file." --ping 0".$anvil->Log->switches,
source => $THIS_FILE,
line => __LINE__,
});
# What zones are there?
my $in_zone = "";
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --get-active-zones";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
# Remove the password.
unlink $password_file;
# If the return code was 252, firewalld isn't running.
if ($return_code eq "252")
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0669"});
return(0);
}
foreach my $line (split/\n/, $output)
{
if ($line =~ /^\S/)
{
$in_zone = $line;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_zone => $in_zone }});
$anvil->data->{firewall}{zone}{$in_zone}{active} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"firewall::zone::${in_zone}::active" => $anvil->data->{firewall}{zone}{$in_zone}{active},
}});
}
elsif ($line =~ /^\s+interfaces: (.*)$/)
{
my $interfaces = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interfaces => $interfaces }});
$anvil->data->{firewall}{zone}{$in_zone}{interfaces} = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"firewall::zone::${in_zone}::interfaces" => $anvil->data->{firewall}{zone}{$in_zone}{interfaces},
}});
}
}
my $reload = 0;
foreach my $zone (sort {$a cmp $b} keys %{$anvil->data->{firewall}{zone}})
{
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --permanent --info-zone=".$zone;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
foreach my $line (split/\n/, $output)
{
if ($line =~ /^\s+services: (.*)$/)
{
my $services = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { services => $services }});
foreach my $service (split/ /, $services)
{
$anvil->data->{firewall}{zone}{$in_zone}{service}{$service} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"firewall::zone::${in_zone}::service::${service}" => $anvil->data->{firewall}{zone}{$in_zone}{service}{$service},
}});
}
}
}
# Is postgres open?
if ((not exists $anvil->data->{firewall}{zone}{$in_zone}{service}{postgresql}) or (not $anvil->data->{firewall}{zone}{$in_zone}{service}{postgresql}))
{
### TODO: Switch this to System->manage_firewall().
# Enable it.
my $service = "postgresql";
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
service => $service,
reload => $reload,
}});
# Re-read the config and make sure we have our own entry.
$anvil->Storage->read_config({file => $anvil->data->{path}{configs}{'anvil.conf'}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0667", variables => {
zone => $zone,
service => $service,
}});
# If we still don't have a local_uuid, something went wrong.
if (not $anvil->data->{database}{$host_uuid}{host})
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --zone=".$zone." --permanent --add-service=".$service;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
}
}
# Reload the firewall?
if ($reload)
{
print $anvil->Words->string({key => "error_0010"})."\n";
$anvil->nice_exit({exit_code => 1});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0139"});
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --reload";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
}
return($host_uuid);
return(0);
}

@ -4,7 +4,6 @@ Wants=network.target
[Service]
Type=simple
ExecStartPre=-/bin/sh -c "if [ -f /usr/sbin/akmods ]; then /usr/sbin/modprobe drbd || /usr/sbin/akmods --force; fi"
ExecStart=/usr/sbin/anvil-daemon
ExecStop=/bin/kill -WINCH ${MAINPID}
Restart=always

Loading…
Cancel
Save