* Created Convert->fence_ipmilan_to_ipmitool() that takes a 'fence_ipmilan' call and converts it into a direct 'ipmitool' call.

* Created Database->get_power() that loads data from the special 'power' table.
* Fixed a bug in calls to Network->ping() where some weren't formatted properly for receiving two string variables.
* Updated Database->get_anvils() to record the machine types when recording host information.
* Updated Database->get_hosts_info() to also load the 'host_ipmi' column.
* Updated Database->get_upses() to store the link to the 'power' -> 'power_uuid', when available.
* Created ScanCore->call_scan_agents() that does the work of actually calling scan agents, moving the logic out from the scancore daemon.
* Created ScanCore->check_power() that takes a host and the anvil it is in and returns if it's on batteries or not. If it is, the time on batteries and estimate hold-up time is returned. If not, the highest charge percentage is returned.
* Created ScanCore->post_scan_analysis() that is a wrapper for calling the new ->post_scan_analysis_dr(), ->post_scan_analysis_node() and ->post_scan_analysis_striker(). Of which, _dr and _node are still empty, but _striker is complete.
** ->post_scan_analysis_striker() is complete. It now boots a node after a power loss if the UPSes powering it are OK (at least one has mains power, and the main-powered UPS(es) have reached the minimum charge percentage). If it's thermal, IPMI is called and so long as at least one thermal sensor is found and it/they are all OK, it is booted. For now, M2's thermal reboot delay logic hasn't been replicated, as it added a lot of complexity and didn't prove practically useful.
* Created System->collect_ipmi_data() and moved 'scan_ipmitool's ipmitool call and parse into that method. This was done to allow ScanCore->post_scan_analysis_striker() to also call IPMI on a remote machine during thermal down events without reimplementing the logic.
* Updated scan-ipmitool to only record temperature data for data collected locally. Also renamed 'machine' variables and hash keys to 'host_name' to clarify what is being stored.
* Updated scancore to clear the 'system::stop_reason' variable.
* Added missing packages to striker-manage-install-target.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 4 years ago
parent 0b2407e78b
commit 96bc1f0b78
  1. 95
      Anvil/Tools/Convert.pm
  2. 184
      Anvil/Tools/Database.pm
  3. 18
      Anvil/Tools/Network.pm
  4. 827
      Anvil/Tools/ScanCore.pm
  5. 304
      Anvil/Tools/System.pm
  6. 7
      scancore-agents/scan-apc-pdu/scan-apc-pdu
  7. 9
      scancore-agents/scan-apc-ups/scan-apc-ups
  8. 719
      scancore-agents/scan-ipmitool/scan-ipmitool
  9. 20
      scancore-agents/scan-ipmitool/scan-ipmitool.xml
  10. 20
      share/words.xml
  11. 162
      tools/scancore
  12. 48
      tools/striker-manage-install-target
  13. 39
      tools/test.pl

@ -17,6 +17,7 @@ my $THIS_FILE = "Convert.pm";
# celsius_to_fahrenheit
# cidr
# fahrenheit_to_celsius
# fence_ipmilan_to_ipmitool
# format_mmddyy_to_yymmdd
# host_name_to_ip
# human_readable_to_bytes
@ -726,6 +727,100 @@ sub fahrenheit_to_celsius
}
=head2 fence_ipmilan_to_ipmitool
This takes a C<< fence_ipmilan >> command and converts it into an C<< ipmitool >> command. The C<< action >> is ignored, as this method is meant to be called when one machine wants to check the health of another machine.
On error, C<< !!error!! >> is returned. Otherwise, a shell call and the user password will be returned as two values.
Parameters;
=head3 fence_ipmilan_command (required)
This is the C<< fence_ipmilan >> command to be translated.
=cut
sub fence_ipmilan_to_ipmitool
{
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 => "Convert->fence_ipmilan_to_ipmitool()" }});
my $fence_ipmilan_command = defined $parameter->{fence_ipmilan_command} ? $parameter->{fence_ipmilan_command} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
fence_ipmilan_command => $fence_ipmilan_command,
}});
if (not $fence_ipmilan_command)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Convert->fence_ipmilan_to_ipmitool()", parameter => "fence_ipmilan_to_ipmitool" }});
return("!!error!!", "!!error!!");
}
elsif ($fence_ipmilan_command !~ /fence_ipmilan /)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0168", variables => { command => $fence_ipmilan_command }});
return("!!error!!", "!!error!!");
}
my $ipmitool_command = $anvil->data->{path}{exe}{ipmitool};
my $ipmi_password = "";
if (($fence_ipmilan_command =~ /-A (.*?) /) or ($fence_ipmilan_command =~ /-auth (.*?) /))
{
# IPMI Lan Auth type (md5, password, or none)
$ipmitool_command .= " -A ".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ipmitool_command => $ipmitool_command }});
}
if (($fence_ipmilan_command =~ /-a (.*?) /) or ($fence_ipmilan_command =~ /-ip (.*?) /))
{
# IPMI Lan IP to talk to
$ipmitool_command .= " -H ".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ipmitool_command => $ipmitool_command }});
}
if (($fence_ipmilan_command =~ /-P /) or ($fence_ipmilan_command =~ /-lanplus /))
{
# Use Lanplus to improve security of connection
$ipmitool_command .= " -I lanplus";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ipmitool_command => $ipmitool_command }});
}
if (($fence_ipmilan_command =~ /-l (.*?) /) or ($fence_ipmilan_command =~ /-username (.*?) /))
{
# Username/Login (if required) to control power on IPMI device
$ipmitool_command .= " -U ".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ipmitool_command => $ipmitool_command }});
}
if (($fence_ipmilan_command =~ /-C (.*?) /) or ($fence_ipmilan_command =~ /-cipher (.*?) /))
{
# Ciphersuite to use (same as ipmitool -C parameter)
$ipmitool_command .= " -C ".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ipmitool_command => $ipmitool_command }});
}
if (($fence_ipmilan_command =~ /-L (.*?) /) or ($fence_ipmilan_command =~ /-privlvl (.*?) /))
{
# Privilege level on IPMI device
$ipmitool_command .= " -L ".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ipmitool_command => $ipmitool_command }});
}
if (($fence_ipmilan_command =~ /-p (.*?) -/) or ($fence_ipmilan_command =~ /-password (.*?) -/) or ($fence_ipmilan_command =~ /-password '(.*?)'/) or ($fence_ipmilan_command =~ /-password (.*)$/))
{
# Password (if required) to control power on IPMI device
$ipmi_password = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, secure => 1, level => $debug, list => { ">> ipmi_password" => $ipmi_password }});
$ipmi_password =~ s/^'(.*?)'$/$1/;
$ipmi_password =~ s/\\'/'/g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, secure => 1, level => $debug, list => { "<< ipmi_password" => $ipmi_password }});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
ipmitool_command => $ipmitool_command,
ipmi_password => $anvil->Log->is_secure($ipmi_password),
}});
return($ipmitool_command, $ipmi_password);
}
=head2 format_mmddyy_to_yymmdd
This converts a C<< mm/dd/yy >> or C<< mm/dd/yyyy >> string into the more sensible yy/mm/dd or yyyy/mm/dd string.

@ -39,6 +39,7 @@ my $THIS_FILE = "Database.pm";
# get_servers
# get_ssh_keys
# get_tables_from_schema
# get_power
# get_upses
# initialize
# insert_or_update_anvils
@ -1234,17 +1235,20 @@ sub connect
if ((not $no_ping) && ($anvil->data->{database}{$uuid}{ping}))
{
# Can I ping?
my ($pinged) = $anvil->Network->ping({
my ($pinged, $average_time) = $anvil->Network->ping({
debug => $debug,
ping => $host,
count => 1,
timeout => $anvil->data->{database}{$uuid}{ping},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
pinged => $pinged,
average_time => $average_time,
}});
my $ping_time = tv_interval ($start_time, [gettimeofday]);
#print "[".$ping_time."] - Pinged: [$host:$port:$name:$user]\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pinged => $pinged }});
if (not $pinged)
{
# Didn't ping and 'database::<uuid>::ping' not set. Record this
@ -2015,27 +2019,33 @@ WHERE
{
$anvil->data->{anvils}{host_uuid}{$anvil_node1_host_uuid}{anvil_name} = $anvil_name;
$anvil->data->{anvils}{host_uuid}{$anvil_node1_host_uuid}{anvil_uuid} = $anvil_uuid;
$anvil->data->{anvils}{host_uuid}{$anvil_node1_host_uuid}{role} = "node1";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::host_uuid::${anvil_node1_host_uuid}::anvil_name" => $anvil->data->{anvils}{host_uuid}{$anvil_node1_host_uuid}{anvil_name},
"anvils::host_uuid::${anvil_node1_host_uuid}::anvil_uuid" => $anvil->data->{anvils}{host_uuid}{$anvil_node1_host_uuid}{anvil_uuid},
"anvils::host_uuid::${anvil_node1_host_uuid}::role" => $anvil->data->{anvils}{host_uuid}{$anvil_node1_host_uuid}{role},
}});
}
if ($anvil_node2_host_uuid)
{
$anvil->data->{anvils}{host_uuid}{$anvil_node2_host_uuid}{anvil_name} = $anvil_name;
$anvil->data->{anvils}{host_uuid}{$anvil_node2_host_uuid}{anvil_uuid} = $anvil_uuid;
$anvil->data->{anvils}{host_uuid}{$anvil_node2_host_uuid}{role} = "node2";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::host_uuid::${anvil_node2_host_uuid}::anvil_name" => $anvil->data->{anvils}{host_uuid}{$anvil_node2_host_uuid}{anvil_name},
"anvils::host_uuid::${anvil_node2_host_uuid}::anvil_uuid" => $anvil->data->{anvils}{host_uuid}{$anvil_node2_host_uuid}{anvil_uuid},
"anvils::host_uuid::${anvil_node2_host_uuid}::role" => $anvil->data->{anvils}{host_uuid}{$anvil_node2_host_uuid}{role},
}});
}
if ($anvil_dr1_host_uuid)
{
$anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{anvil_name} = $anvil_name;
$anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{anvil_uuid} = $anvil_uuid;
$anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{role} = "dr1";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::host_uuid::${anvil_dr1_host_uuid}::anvil_name" => $anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{anvil_name},
"anvils::host_uuid::${anvil_dr1_host_uuid}::anvil_uuid" => $anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{anvil_uuid},
"anvils::host_uuid::${anvil_dr1_host_uuid}::role" => $anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{role},
}});
}
}
@ -2368,12 +2378,16 @@ sub get_hosts_info
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->get_hosts_info()" }});
# Load anvil data so we can find passwords.
$anvil->Database->get_anvils({debug => $debug});
my $query = "
SELECT
host_uuid,
host_name,
host_type,
host_key
host_key,
host_ipmi
FROM
hosts
;";
@ -2391,20 +2405,51 @@ FROM
my $host_name = $row->[1];
my $host_type = $row->[2];
my $host_key = $row->[3];
my $host_ipmi = $row->[4];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid,
host_name => $host_name,
host_type => $host_type,
host_key => $host_key,
host_ipmi => $anvil->Log->is_secure($host_ipmi),
}});
$anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_name} = $host_name;
$anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_type} = $host_type;
$anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_key} = $host_key;
$anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi} = $host_ipmi;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"machine::host_uuid::${host_uuid}::hosts::host_name" => $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_name},
"machine::host_uuid::${host_uuid}::hosts::host_type" => $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_type},
"machine::host_uuid::${host_uuid}::hosts::host_key" => $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_key},
"machine::host_uuid::${host_uuid}::hosts::host_ipmi" => $anvil->Log->is_secure($anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi}),
}});
# If this is an Anvil! member, pull it's IP.
$anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{name} = "";
$anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{uuid} = "";
$anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{role} = "";
$anvil->data->{machine}{host_uuid}{$host_uuid}{password} = "";
if (exists $anvil->data->{anvils}{host_uuid}{$host_uuid})
{
my $anvil_uuid = $anvil->data->{anvils}{host_uuid}{$host_uuid}{anvil_uuid};
$anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{name} = $anvil->data->{anvils}{host_uuid}{$host_uuid}{anvil_name};
$anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{uuid} = $anvil_uuid;
$anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{role} = $anvil->data->{anvils}{host_uuid}{$host_uuid}{role};
$anvil->data->{machine}{host_uuid}{$host_uuid}{password} = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"machine::host_uuid::${host_uuid}::anvil::name" => $anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{name},
"machine::host_uuid::${host_uuid}::anvil::uuid" => $anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{uuid},
"machine::host_uuid::${host_uuid}::anvil::role" => $anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{role},
"machine::host_uuid::${host_uuid}::password" => $anvil->Log->is_secure($anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{password}),
}});
}
elsif (exists $anvil->data->{database}{$host_uuid})
{
$anvil->data->{machine}{host_uuid}{$host_uuid}{password} = $anvil->data->{database}{$host_uuid}{password};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"machine::host_uuid::${host_uuid}::password" => $anvil->Log->is_secure($anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{password}),
}});
}
# Read in the variables.
my $query = "
@ -2436,8 +2481,9 @@ AND
}});
}
# Read in the IP addresses and network information.
# Read in the IP addresses and network information. Data is loaded under
# 'network::host_uuid::x'.
$anvil->Network->load_interfces({debug => $debug, host_uuid => $host_uuid});
}
return(0);
@ -3840,6 +3886,111 @@ sub get_tables_from_schema
}
=head2 get_power
This loads the special C<< power >> table, which complements the C<< upses >> table. This helps ScanCore determine when nodes need to shut down or can be power back up during power events.
* power::power_uuid::<power_uuid>::power_ups_uuid
* power::power_uuid::<power_uuid>::power_on_battery
* power::power_uuid::<power_uuid>::power_seconds_left
* power::power_uuid::<power_uuid>::power_charge_percentage
* power::power_uuid::<power_uuid>::modified_date_unix
And, to allow for lookup by name;
* power::power_ups_uuid::<power_ups_uuid>::power_uuid
* power::power_ups_uuid::<power_ups_uuid>::power_on_battery
* power::power_ups_uuid::<power_ups_uuid>::power_seconds_left
* power::power_ups_uuid::<power_ups_uuid>::power_charge_percentage
* power::power_ups_uuid::<power_ups_uuid>::modified_date_unix
B<< Note >>: The C<< modified_date >> is cast as a unix time stamp.
If the hash was already populated, it is cleared before repopulating to ensure no stray data remains.
This method takes no parameters.
=cut
sub get_power
{
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->get_power()" }});
if (exists $anvil->data->{power})
{
delete $anvil->data->{power};
}
my $query = "
SELECT
power_uuid,
power_ups_uuid,
power_on_battery,
power_seconds_left,
power_charge_percentage,
round(extract(epoch from modified_date))
FROM
power
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $power_uuid = $row->[0];
my $power_ups_uuid = $row->[1];
my $power_on_battery = $row->[2];
my $power_seconds_left = $row->[3];
my $power_charge_percentage = $row->[4];
my $modified_date_unix = $row->[5];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
power_uuid => $power_uuid,
power_ups_uuid => $power_ups_uuid,
power_on_battery => $power_on_battery,
power_seconds_left => $power_seconds_left,
power_charge_percentage => $power_charge_percentage,
modified_date_unix => $modified_date_unix,
}});
# Record the data in the hash, too.
$anvil->data->{power}{power_uuid}{$power_uuid}{power_ups_uuid} = $power_ups_uuid;
$anvil->data->{power}{power_uuid}{$power_uuid}{power_on_battery} = $power_on_battery;
$anvil->data->{power}{power_uuid}{$power_uuid}{power_seconds_left} = $power_seconds_left;
$anvil->data->{power}{power_uuid}{$power_uuid}{power_charge_percentage} = $power_charge_percentage;
$anvil->data->{power}{power_uuid}{$power_uuid}{modified_date_unix} = $modified_date_unix;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"power::power_uuid::${power_uuid}::power_ups_uuid" => $anvil->data->{power}{power_uuid}{$power_uuid}{power_ups_uuid},
"power::power_uuid::${power_uuid}::power_on_battery" => $anvil->data->{power}{power_uuid}{$power_uuid}{power_on_battery},
"power::power_uuid::${power_uuid}::power_seconds_left" => $anvil->data->{power}{power_uuid}{$power_uuid}{power_seconds_left},
"power::power_uuid::${power_uuid}::power_charge_percentage" => $anvil->data->{power}{power_uuid}{$power_uuid}{power_charge_percentage},
"power::power_uuid::${power_uuid}::modified_date_unix" => $anvil->data->{power}{power_uuid}{$power_uuid}{modified_date_unix},
}});
$anvil->data->{power}{power_ups_uuid}{$power_ups_uuid}{power_uuid} = $power_uuid;
$anvil->data->{power}{power_ups_uuid}{$power_ups_uuid}{power_on_battery} = $power_on_battery;
$anvil->data->{power}{power_ups_uuid}{$power_ups_uuid}{power_seconds_left} = $power_seconds_left;
$anvil->data->{power}{power_ups_uuid}{$power_ups_uuid}{power_charge_percentage} = $power_charge_percentage;
$anvil->data->{power}{power_ups_uuid}{$power_ups_uuid}{modified_date_unix} = $modified_date_unix;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"power::power_ups_uuid::${power_ups_uuid}::power_uuid" => $anvil->data->{power}{power_ups_uuid}{$power_ups_uuid}{power_uuid},
"power::power_ups_uuid::${power_ups_uuid}::power_on_battery" => $anvil->data->{power}{power_ups_uuid}{$power_ups_uuid}{power_on_battery},
"power::power_ups_uuid::${power_ups_uuid}::power_seconds_left" => $anvil->data->{power}{power_ups_uuid}{$power_ups_uuid}{power_seconds_left},
"power::power_ups_uuid::${power_ups_uuid}::power_charge_percentage" => $anvil->data->{power}{power_ups_uuid}{$power_ups_uuid}{power_charge_percentage},
"power::power_ups_uuid::${power_ups_uuid}::modified_date_unix" => $anvil->data->{power}{power_ups_uuid}{$power_ups_uuid}{modified_date_unix},
}});
}
return(0);
}
=head2 get_upses
This loads the known UPSes (uninterruptible power supplies) into the C<< anvil::data >> hash at:
@ -3848,6 +3999,7 @@ This loads the known UPSes (uninterruptible power supplies) into the C<< anvil::
* upses::ups_uuid::<ups_uuid>::ups_agent
* upses::ups_uuid::<ups_uuid>::ups_ip_address
* upses::ups_uuid::<ups_uuid>::modified_date
* upses::ups_uuid::<ups_uuid>::power_uuid
And, to allow for lookup by name;
@ -3855,11 +4007,14 @@ And, to allow for lookup by name;
* upses::ups_name::<ups_name>::ups_agent
* upses::ups_name::<ups_name>::ups_ip_address
* upses::ups_name::<ups_name>::modified_date
* upses::ups_name::<ups_name>::power_uuid
If the hash was already populated, it is cleared before repopulating to ensure no stray data remains.
B<<Note>>: Deleted devices (ones where C<< ups_ip_address >> is set to C<< DELETED >>) are ignored. See the C<< include_deleted >> parameter to include them.
B<< Note>>: If a scan agent has scanned this UPS, it's power state information will be stored in the C<< power >> table. If a matching record is found, the C<< power_uuid >> will be stored in the C<< ...::power_uuid >> hash references. For this linking to work, this method will call C<< Database->get_power >>.
Parameters;
=head3 include_deleted (Optional, default 0)
@ -3885,6 +4040,9 @@ sub get_upses
delete $anvil->data->{upses};
}
# Load the power data.
$anvil->Database->get_power({debug => $debug});
my $query = "
SELECT
ups_uuid,
@ -3929,6 +4087,7 @@ WHERE
$anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_agent} = $ups_agent;
$anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_ip_address} = $ups_ip_address;
$anvil->data->{upses}{ups_uuid}{$ups_uuid}{modified_date} = $modified_date;
$anvil->data->{upses}{ups_uuid}{$ups_uuid}{power_uuid} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"upses::ups_uuid::${ups_uuid}::ups_name" => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_name},
"upses::ups_uuid::${ups_uuid}::ups_agent" => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_agent},
@ -3940,12 +4099,27 @@ WHERE
$anvil->data->{upses}{ups_name}{$ups_name}{ups_agent} = $ups_agent;
$anvil->data->{upses}{ups_name}{$ups_name}{ups_ip_address} = $ups_ip_address;
$anvil->data->{upses}{ups_name}{$ups_name}{modified_date} = $modified_date;
$anvil->data->{upses}{ups_name}{$ups_name}{power_uuid} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"upses::ups_name::${ups_name}::ups_uuid" => $anvil->data->{upses}{ups_name}{$ups_name}{ups_uuid},
"upses::ups_name::${ups_name}::ups_agent" => $anvil->data->{upses}{ups_name}{$ups_name}{ups_agent},
"upses::ups_name::${ups_name}::ups_ip_address" => $anvil->data->{upses}{ups_name}{$ups_name}{ups_ip_address},
"upses::ups_name::${ups_name}::modified_date" => $anvil->data->{upses}{ups_name}{$ups_name}{modified_date},
}});
# Collect power information from 'power'.
if (exists $anvil->data->{power}{power_ups_uuid}{$ups_uuid})
{
my $power_uuid = $anvil->data->{power}{power_ups_uuid}{$ups_uuid}{power_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { power_uuid => $power_uuid }});
$anvil->data->{upses}{ups_uuid}{$ups_uuid}{power_uuid} = $power_uuid;
$anvil->data->{upses}{ups_name}{$ups_name}{power_uuid} = $power_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"upses::ups_uuid::${ups_uuid}::power_ups_uuid" => $anvil->data->{upses}{ups_uuid}{$ups_uuid}{power_ups_uuid},
"upses::ups_name::${ups_name}::power_ups_uuid" => $anvil->data->{upses}{ups_name}{$ups_name}{power_ups_uuid},
}});
}
}
return(0);

@ -308,7 +308,7 @@ sub check_internet
next;
}
my $pinged = $anvil->Network->ping({
my ($pinged, $average_time) = $anvil->Network->ping({
debug => $debug,
target => $target,
port => $port,
@ -317,7 +317,10 @@ sub check_internet
ping => $domain,
count => 3,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pinged => $pinged }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
pinged => $pinged,
average_time => $average_time,
}});
if ($pinged)
{
$access = 1;
@ -2058,13 +2061,13 @@ This method will attempt to ping a target, by host name or IP, and returns C<< 1
Example;
# Test access to the internet. Allow for three attempts to account for network jitter.
my $pinged = $anvil->Network->ping({
my ($pinged, $average_time) = $anvil->Network->ping({
ping => "google.ca",
count => 3,
});
# Test 9000-byte jumbo-frame access to a target over the BCN.
my $jumbo_to_peer = $anvil->Network->ping({
my ($jumbo_to_peer, $average_time) = $anvil->Network->ping({
ping => "an-a01n02.bcn",
count => 1,
payload => 9000,
@ -2072,7 +2075,7 @@ Example;
});
# Check to see if an Anvil! node has internet access
my $pinged = $anvil->Network->ping({
my ($pinged, $average_time) = $anvil->Network->ping({
target => "an-a01n01.alteeve.com",
port => 22,
password => "super secret",
@ -2181,7 +2184,7 @@ sub ping
{
$shell_call = $anvil->data->{path}{exe}{timeout}." $timeout ";
}
$shell_call .= $anvil->data->{path}{exe}{'ping'}." -W 1 -n $ping -c 1";
$shell_call .= $anvil->data->{path}{exe}{'ping'}." -W 1 -n ".$ping." -c 1";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
if (not $fragment)
{
@ -2199,8 +2202,8 @@ sub ping
my $average_ping_time = 0;
foreach my $try (1..$count)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count, try => $try }});
last if $pinged;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count, try => $try }});
my $output = "";
my $error = "";
@ -2249,6 +2252,7 @@ sub ping
# Contact!
$pinged = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { pinged => $pinged }});
last;
}
else
{

@ -16,6 +16,13 @@ my $THIS_FILE = "ScanCore.pm";
### Methods;
# agent_startup
# call_scan_agents
# check_power
# post_scan_analysis
# post_scan_analysis_dr
# post_scan_analysis_node
# post_scan_analysis_striker
# _scan_directory
=pod
@ -78,17 +85,6 @@ sub parent
#############################################################################################################
# =head3
#
# Private Functions;
#
# =cut
#############################################################################################################
# Private functions #
#############################################################################################################
=head2 agent_startup
This method handles connecting to the databases, loading the agent's schema, resync'ing database tables if needed and reading in the words files.
@ -198,4 +194,813 @@ sub agent_startup
}
=head2 call_scan_agents
This method calls all scan agents found on this system. It looks under the C<< path::directories::scan_agents >> directory (and subdirectories) for scan agents.
This method takes no parameters.
=cut
sub call_scan_agents
{
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->call_scan_agents()" }});
# Get the current list of scan agents on this system.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"path::directories::scan_agents" => $anvil->data->{path}{directories}{scan_agents},
}});
$anvil->ScanCore->_scan_directory({directory => $anvil->data->{path}{directories}{scan_agents}});
# Now loop through the agents I found and call them.
my $timeout = 30;
if ((exists $anvil->data->{scancore}{timing}{agent_runtime}) && ($anvil->data->{scancore}{timing}{agent_runtime} =~ /^\d+$/))
{
$timeout = $anvil->data->{scancore}{timing}{agent_runtime};
}
foreach my $agent_name (sort {$a cmp $b} keys %{$anvil->data->{scancore}{agent}})
{
my $agent_path = $anvil->data->{scancore}{agent}{$agent_name};
my $agent_words = $agent_path.".xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
agent_name => $agent_name,
agent_path => $agent_path,
agent_words => $agent_words,
}});
if ((-e $agent_words) && (-r $agent_words))
{
# Read the words file so that we can generate alerts later.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0251", variables => {
agent_name => $agent_name,
file => $agent_words,
}});
$anvil->Words->read({file => $agent_words});
}
# Set the timeout.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
agent_name => $agent_name,
"scancore::${agent_name}::timeout" => $anvil->data->{scancore}{$agent_name}{timeout},
}});
# Now call the agent.
my $start_time = time;
if (($anvil->data->{scancore}{$agent_name}{timeout}) && ($anvil->data->{scancore}{$agent_name}{timeout} =~ /^\d+$/))
{
$timeout = $anvil->data->{scancore}{$agent_name}{timeout};
}
my $shell_call = $agent_path;
if ($anvil->data->{sys}{'log'}{level})
{
$shell_call .= " ".$anvil->data->{sys}{'log'}{level};
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
# Tell the user this agent is about to run...
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => $debug, key => "log_0252", variables => {
agent_name => $agent_name,
timeout => $timeout,
}});
my ($output, $return_code) = $anvil->System->call({timeout => $timeout, 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 }});
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => $debug, key => "log_0557", variables => {
agent_name => $agent_name,
runtime => (time - $start_time),
return_code => $return_code,
}});
# If the return code is '124', timeout popped.
if ($return_code eq "124")
{
### TODO: Check if this alert was set so it only goes out once.
# Register an alert...
$anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "message_0180,!!agent_name!".$agent_name."!!,!!timeout!".$timeout."!!"});
}
}
return(0);
}
=head2 check_power
This method checks the health of the UPSes powering a node.
The power health, the shortest "time on batteries", the highest charge percentage and etimated hold-up time are returned.
Power health values;
* '!!error!!' - There was a missing input variable.
* 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 the health is C<< 0 >>, all other values will also be C<< 0 >>.
If the health is C<< 1 >>, the "time on batteries" and "estimated hold up time" will be C<< 0 >> and the highest charge percentage will be set.
If the health is C<< 2 >>, the "time on batteries" will be the number of seconds since the last UPS to lose power was found to be running on batteries, The estimated hold up time of the strongest UPS is also returned in seconds.
If no UPSes were found, health of '0' is returned (unknown). If If both/all UPSes are
Parameters;
=head3 anvil_uuid (required)
This is the Anvil! UUID that the machine belongs to. This is required to find the manifest that shows which UPSes power the host.
=head3 anvil_name (required)
This is the Anvil! name that the machine is a member of. This is used for logging.
=head3 host_uuid (required)
This is the host's UUID that we're checking the UPSes powering it.
=head3 host_name (required)
This is the host's name that we're checking. This is used for logging.
=cut
sub check_power
{
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_power()" }});
my $anvil_uuid = defined $parameter->{anvil_uuid} ? $parameter->{anvil_uuid} : "";
my $anvil_name = defined $parameter->{anvil_name} ? $parameter->{anvil_name} : "";
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : "";
my $host_name = defined $parameter->{host_name} ? $parameter->{host_name} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_uuid => $anvil_uuid,
anvil_name => $anvil_name,
host_uuid => $host_uuid,
host_name => $host_name,
}});
if ((not $anvil_uuid) or (not $anvil_name) or (not $host_uuid) or (not $host_name))
{
# Woops
return("!!error!!");
}
# We'll need the UPS data
$anvil->Database->get_upses({debug => $debug});
my $power_health = 0;
my $shorted_time_on_batteries = 99999;
my $highest_charge_percentage = 0;
my $estimated_hold_up_time = 0;
my $query = "SELECT manifest_uuid FROM manifests WHERE manifest_name = ".$anvil->Database->quote($anvil_name).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
if (not $count)
{
# Nothing we can do.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0569", variables => {
anvil_name => $anvil_name,
host_name => $host_name,
}});
return($power_health, $shorted_time_on_batteries, $highest_charge_percentage, $estimated_hold_up_time)
}
my $manifest_uuid = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { manifest_uuid => $manifest_uuid }});
# Try to parse the manifest now.
if (not exists $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid})
{
my $problem = $anvil->Striker->load_manifest({
debug => $debug,
manifest_uuid => $manifest_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if ($problem)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0569", variables => {
manifest_uuid => $manifest_uuid,
anvil_name => $anvil_name,
host_name => $host_name,
}});
return($power_health, $shorted_time_on_batteries, $highest_charge_percentage, $estimated_hold_up_time)
}
}
# If we're here, we can now look for the PDUs powering this host.
my $ups_count = 0;
my $ups_with_mains_found = 0;
foreach my $machine_type (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}})
{
my $machine_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine_type}{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
machine_type => $machine_type,
machine_name => $machine_name,
}});
next if $host_name !~ /$machine_name/;
foreach my $ups_name (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine_type}{ups}})
{
my $ups_uuid = $anvil->data->{upses}{ups_name}{$ups_name}{ups_uuid};
my $ups_used = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine_type}{ups}{$ups_name}{used};
my $power_uuid = $anvil->data->{upses}{ups_name}{$ups_name}{power_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ups_name => $ups_name,
ups_uuid => $ups_uuid,
power_uuid => $power_uuid,
}});
if (($ups_used) && ($power_uuid))
{
### TODO: The power 'modified_time' is in unixtime. So we can see when the
### UPS was last scanned. Later, we should think about how valid we
### consider data over a certain age.
# What state is the UPS in?
$ups_count++;
my $power_on_battery = $anvil->data->{power}{power_uuid}{$power_uuid}{power_on_battery};
my $power_seconds_left = $anvil->data->{power}{power_uuid}{$power_uuid}{power_seconds_left};
my $power_charge_percentage = $anvil->data->{power}{power_uuid}{$power_uuid}{power_charge_percentage};
my $modified_date_unix = $anvil->data->{power}{power_uuid}{$power_uuid}{modified_date_unix};
my $time_now = time;
my $last_updated = $time_now - $modified_date_unix;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ups_count => $ups_count,
power_on_battery => $power_on_battery,
power_seconds_left => $power_seconds_left." (".$anvil->Convert->time({'time' => $power_seconds_left, long => 1, translate => 1}).")",
power_charge_percentage => $power_charge_percentage."%",
modified_date_unix => $modified_date_unix,
time_now => $time_now,
last_updated => $last_updated." (".$anvil->Convert->time({'time' => $last_updated, long => 1, translate => 1}).")",
}});
if ($power_on_battery)
{
# We're on battery, so see what the hold up time is.
if (not $power_health)
{
# Set this to '2', if another UPS is on mains, it will change it to 1.
$power_health = 2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { power_health => $power_health }});
}
if ($power_seconds_left > $estimated_hold_up_time)
{
$estimated_hold_up_time = $power_seconds_left;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { estimated_hold_up_time => $estimated_hold_up_time }});
}
# How long has it been on batteries?
my $query = "
SELECT
round(extract(epoch from modified_date))
FROM
history.power
WHERE
power_uuid = ".$anvil->Database->quote($power_uuid)."
AND
power_on_battery IS FALSE
ORDER BY
modified_date DESC
LIMIT 1
;";
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)
{
# The only way this could happen is if we've never seen the UPS on mains...
$shorted_time_on_batteries = 0;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0571", variables => {
power_uuid => $power_uuid,
host_name => $host_name,
}});
}
else
{
my $time_on_batteries = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
time_on_batteries => $time_on_batteries." (".$anvil->Convert->time({'time' => $time_on_batteries, long => 1, translate => 1}).")",
}});
if ($time_on_batteries < $shorted_time_on_batteries)
{
$shorted_time_on_batteries = $shorted_time_on_batteries;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
shorted_time_on_batteries => $shorted_time_on_batteries." (".$anvil->Convert->time({'time' => $shorted_time_on_batteries, long => 1, translate => 1}).")",
}});
}
}
}
else
{
# See how charged up this UPS is.
$power_health = 1;
$ups_with_mains_found = 1;
$shorted_time_on_batteries = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ups_with_mains_found => $ups_with_mains_found,
shorted_time_on_batteries => $shorted_time_on_batteries,
}});
if ($power_charge_percentage > $highest_charge_percentage)
{
$highest_charge_percentage = $power_charge_percentage;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { highest_charge_percentage => $highest_charge_percentage }});
}
}
}
}
}
if ($ups_count)
{
# No UPSes found.
$shorted_time_on_batteries = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shorted_time_on_batteries => $shorted_time_on_batteries }});
}
return($power_health, $shorted_time_on_batteries, $highest_charge_percentage, $estimated_hold_up_time);
}
=head2 post_scan_analysis
This method contains the logic for the ScanCore "decision engine". The logic applied depends on the host type.
This method takes no parameters.
=cut
sub post_scan_analysis
{
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->post_scan_analysis()" }});
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 eq "striker")
{
$anvil->ScanCore->post_scan_analysis_striker({debug => $debug})
}
elsif ($host_type eq "node")
{
$anvil->ScanCore->post_scan_analysis_node({debug => $debug})
}
elsif ($host_type eq "dr")
{
$anvil->ScanCore->post_scan_analysis_dr({debug => $debug})
}
return(0);
}
=head2 post_scan_analysis_dr
This runs through ScanCore post-scan analysis on DR hosts.
This method takes no parameters;
=cut
sub post_scan_analysis_dr
{
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->post_scan_analysis_dr()" }});
return(0);
}
=head2 post_scan_analysis_node
This runs through ScanCore post-scan analysis on Anvil! nodes.
This method takes no parameters;
=cut
sub post_scan_analysis_node
{
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->post_scan_analysis_node()" }});
return(0);
}
=head2 post_scan_analysis_striker
This runs through ScanCore post-scan analysis on Striker dashboards.
This method takes no parameters;
=cut
sub post_scan_analysis_striker
{
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->post_scan_analysis_striker()" }});
# We only boot nodes and DR hosts. Nodes get booted if 'variable_name = 'system::shutdown_reason' is
# set, or when a DR host is scheduled to boot.
$anvil->Database->get_hosts_info({debug => $debug});
# Get a look at all nodes and DR hosts. For each, check if they're up.
foreach my $host_uuid (keys %{$anvil->data->{machine}{host_uuid}})
{
# Compile data.
my $host_name = $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_name};
my $host_type = $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_type};
my $host_key = $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_key};
my $host_ipmi = $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi};
my $password = $anvil->data->{machine}{host_uuid}{$host_uuid}{password};
my $anvil_name = $anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{name};
my $anvil_uuid = $anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{uuid};
my $anvil_role = $anvil->data->{machine}{host_uuid}{$host_uuid}{anvil}{role};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_name => $host_name,
host_type => $host_type,
host_key => $host_key,
host_ipmi => $anvil->Log->is_secure($host_ipmi),
password => $anvil->Log->is_secure($password),
anvil_name => $anvil_name,
anvil_uuid => $anvil_uuid,
anvil_role => $anvil_role,
}});
### TODO: Add an ability to mark which PDU powers a striker. If set, try logging into the
### peer striker and if it fails, power cycle it (but only once per hour).
next if $host_type eq "striker";
### TODO: Adding support for PDU resets would allow us to recover from crashed IPMI BMCs as
### well. For now though, not 'host_ipmi' means there's nothing we can do.
if (not $anvil->data->{machine}{host_uuid}{$host_uuid}{hosts}{host_ipmi})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0560", variables => { host_name => $host_name }});
next;
}
# Check this target's power state.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0561", variables => { host_name => $host_name }});
# Do we share a network with this system?
my $check_power = 1;
my $match = $anvil->Network->find_matches({
debug => $debug,
first => $anvil->Get->host_uuid,
second => $host_uuid,
});
my $matched_ips = keys %{$match};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { matched_ips => $matched_ips }});
if (not $matched_ips)
{
# nothing we can do with this host.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0558", variables => { host_name => $host_name }});
next;
}
foreach my $interface (sort {$a cmp $b} keys %{$match->{$host_uuid}})
{
next;
my $ip_address = $match->{$host_uuid}{$interface}{ip};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:interface' => $interface,
's2:ip_address' => $ip_address,
}});
# Can we access the machine?
my ($pinged, $average_time) = $anvil->Network->ping({
debug => $debug,
count => 3,
ping => $ip_address,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
pinged => $pinged,
average_time => $average_time,
}});
if ($pinged)
{
my $access = $anvil->Remote->test_access({
debug => $debug,
target => $ip_address,
user => "root",
password => $password,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }});
if ($access)
{
# It's up.
$check_power = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { check_power => $check_power }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0562", variables => { host_name => $host_name }});
last;
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { check_power => $check_power }});
if (not $check_power)
{
next;
}
# Do we have IPMI info?
if (not $host_ipmi)
{
### TODO: Add support for power-cycling a target using PDUs. Until this, this
### will never be hit as we next on no host_ipmi, but will be useful
### when PDU support is added.
# Nothing we can do (for now)
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0559", variables => { host_name => $host_name }});
next;
}
# Check the power state.
my $shell_call = $host_ipmi;
$shell_call =~ s/--action status//;
$shell_call =~ s/-o status//;
$shell_call .= " --action status";
$shell_call =~ s/ --action/ --action/;
my ($output, $return_code) = $anvil->System->call({debug => $debug, timeout => 30, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }});
foreach my $line (split/\n/, $output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
}
if ($return_code eq "2")
{
# Node is off.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0564", variables => { host_name => $host_name }});
}
elsif ($return_code eq "0")
{
# Node is on.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0563", variables => { host_name => $host_name }});
next;
}
# Still here? See if we know why the node is off.
my $boot_target = 0;
my $stop_reason = "unknown";
my $query = "
SELECT
variable_value
FROM
variables
WHERE
variable_name = 'system::stop_reason'
AND
variable_source_table = 'hosts'
AND
variable_source_uuid = ".$anvil->Database->quote($host_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
if ($count)
{
$stop_reason = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { stop_reason => $stop_reason }});
}
if (not $stop_reason)
{
# Nothing to do.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0565", variables => { host_name => $host_name }});
next;
}
elsif ($stop_reason eq "user")
{
# Nothing to do.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0566", variables => { host_name => $host_name }});
next;
}
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 }});
my ($power_health, $shorted_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,
host_name => $host_name,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
power_health => $power_health,
shorted_time_on_batteries => $shorted_time_on_batteries,
highest_charge_percentage => $highest_charge_percentage,
estimated_hold_up_time => $estimated_hold_up_time,
}});
# * 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 ($power_health eq "1")
{
# Power is (at least partially) back. What's the charge percent?
if ((not $anvil->data->{scancore}{power}{safe_boot_percentage}) or ($anvil->data->{scancore}{power}{safe_boot_percentage} =~ /\D/))
{
$anvil->data->{scancore}{power}{safe_boot_percentage} = 35;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
"scancore::power::safe_boot_percentage" => $anvil->data->{scancore}{power}{safe_boot_percentage},
}});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
highest_charge_percentage => $highest_charge_percentage,
"scancore::power::safe_boot_percentage" => $anvil->data->{scancore}{power}{safe_boot_percentage},
}});
if ($highest_charge_percentage >= $anvil->data->{scancore}{power}{safe_boot_percentage})
{
# Safe to boot!
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0574", 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 => 2, list => { shell_call => $shell_call }});
}
}
}
elsif ($stop_reason eq "thermal")
{
# 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,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, 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,
});
# 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 => 2, 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 => 2, 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 => 2, list => { temperatures_ok => $temperatures_ok }});
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
sensor_found => $sensor_found,
temperatures_ok => $temperatures_ok,
}});
if (($sensor_found) && ($temperatures_ok))
{
### 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
### in the right situation.
# Safe to boot!
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0575", 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 => 2, list => { shell_call => $shell_call }});
}
}
}
return(0);
}
# =head3
#
# Private Functions;
#
# =cut
#############################################################################################################
# Private functions #
#############################################################################################################
# This looks in the passed-in directory for scan agents or sub-directories (which will in turn be scanned).
sub _scan_directory
{
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->_scan_directory()" }});
my $directory = defined $parameter->{directory} ? $parameter->{directory} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
directory => $directory,
}});
if (not $directory)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "ScanCore->_scan_directory()", parameter => "directory" }});
return("!!error!!");
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { directory => $directory }});
local(*DIRECTORY);
opendir(DIRECTORY, $directory);
while(my $file = readdir(DIRECTORY))
{
next if $file eq ".";
next if $file eq "..";
my $full_path = $directory."/".$file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file => $file,
full_path => $full_path,
}});
# If we're looking at a directory, scan it. Otherwise, see if it's an executable and that it
# starts with 'scan-*'.
if (-d $full_path)
{
# This is a directory, dive into it.
$anvil->ScanCore->_scan_directory({directory => $full_path});
}
elsif (-x $full_path)
{
# Now I only want to know if the file starts with 'scan-'
next if $file !~ /^scan-/;
# If I am still alive, I am looking at a scan agent!
$anvil->data->{scancore}{agent}{$file} = $full_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"scancore::agent::${file}" => $anvil->data->{scancore}{agent}{$file},
}});
}
}
closedir(DIRECTORY);
return(0);
}
1;

@ -27,6 +27,7 @@ my $THIS_FILE = "System.pm";
# check_ssh_keys
# check_memory
# check_storage
# collect_ipmi_data
# configure_ipmi
# disable_daemon
# enable_daemon
@ -1196,6 +1197,309 @@ sub check_storage
return(0);
}
=head2 collect_ipmi_data
This takes an C<< ipmitool >> command (for access, not including ending command or password!) and calls thae target IPMI BMC. The returned data is collected and parsed.
If failed to access, C<< 1 >> is returned. If there is a problem, C<< !!error!! >> is returned. If data is collected, C<< 0 >> is returned.
Recorded data is stored as:
ipmi::<host_name>::scan_ipmitool_sensor_name::$sensor_name::scan_ipmitool_value_sensor_value
ipmi::<host_name>::scan_ipmitool_sensor_name::$sensor_name::scan_ipmitool_sensor_units
ipmi::<host_name>::scan_ipmitool_sensor_name::$sensor_name::scan_ipmitool_sensor_status
ipmi::<host_name>::scan_ipmitool_sensor_name::$sensor_name::scan_ipmitool_sensor_high_critical
ipmi::<host_name>::scan_ipmitool_sensor_name::$sensor_name::scan_ipmitool_sensor_high_warning
ipmi::<host_name>::scan_ipmitool_sensor_name::$sensor_name::scan_ipmitool_sensor_low_critical
ipmi::<host_name>::scan_ipmitool_sensor_name::$sensor_name::scan_ipmitool_sensor_low_warning
parameters;
=head3 host_name (required)
This is the name used to store the target's information. Generally, this should be the C<< host_name >> value for the target machine, as stored in C<< hosts >>.
=head3 ipmitool_command (required)
This is the C<< ipmitool >> command used to authenticate against and access the target BMC. This must not contain the password, or the command to run on the BMC. Those parts are handled by this method.
=head3 ipmi_password (optional)
If the target BMC requires a password (and they usually do...), the password will be written to a temporary file, and C<< -f <temp_file > >> will be used as part of the final C<< ipmitool >> command call. As soon as the call returns, the temp file is deleted.
=cut
sub collect_ipmi_data
{
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->collect_ipmi_data()" }});
my $host_name = defined $parameter->{host_name} ? $parameter->{host_name} : "";
my $ipmitool_command = defined $parameter->{ipmitool_command} ? $parameter->{ipmitool_command} : "";
my $ipmi_password = defined $parameter->{ipmi_password} ? $parameter->{ipmi_password} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_name => $host_name,
ipmitool_command => $ipmitool_command,
ipmi_password => $anvil->Log->is_secure($ipmi_password),
}});
if (not $host_name)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Systeme->collect_ipmi_data()", parameter => "host_name" }});
return('!!error!!');
}
if (not $ipmitool_command)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Systeme->collect_ipmi_data()", parameter => "ipmitool_command" }});
return('!!error!!');
}
my $read_start_time = time;
# If there is a password, write it to a temp file.
my $problem = 1;
my $temp_file = "";
if ($ipmi_password)
{
# Write the password to a temp file.
$temp_file = "/tmp/scancore.".$anvil->Get->uuid({short => 1});
$anvil->Storage->write_file({
body => $ipmi_password,
secure => 1,
file => $temp_file,
overwrite => 1,
});
}
# Call with a timeout in case the call hangs.
my $shell_call = $ipmitool_command." sensor list all";
if ($ipmi_password)
{
$shell_call = $ipmitool_command." -f ".$temp_file." sensor list all";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({timeout => 30, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
# Delete the temp file.
unlink $temp_file;
my $temp_count = 1;
foreach my $line (split/\n/, $output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ">> line" => $line }});
# Clean up the output
$line =~ s/^\s+//;
$line =~ s/\s+$//;
$line =~ s/\s+\|/|/g;
$line =~ s/\|\s+/|/g;
### TODO: If we determine that the IPMI BMC is hung, set the health to '10'
### $anvil->data->{'scan-ipmitool'}{health}{new}{'ipmi:bmc_controller'} = 10;
# Catch errors:
if ($line =~ /Activate Session command failed/)
{
# Failed to connect.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_ipmitool_log_0002", variables => {
host_name => $host_name,
call => $ipmitool_command,
}});
}
next if $line !~ /\|/;
if ($problem)
{
$problem = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {problem => $problem }});
}
# high fail -------------------------------------.
# high critical ---------------------------------. |
# high warning -----------------------------. | |
# low warning -------------------------. | | |
# low critical ---------------------. | | | |
# low fail -----------------. | | | | |
# status -------------. | | | | | |
# units ---------. | | | | | | |
# current value -----. | | | | | | | |
# sensor name -. | | | | | | | | |
# Columns: | | | | | | | | | |
# x | x | x | x | x | x | x | x | x | x
my ($sensor_name,
$current_value,
$units,
$status,
$low_fail,
$low_critical,
$low_warning,
$high_warning,
$high_critical,
$high_fail) = split /\|/, $line;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
sensor_name => $sensor_name,
current_value => $current_value,
units => $units,
status => $status,
low_fail => $low_fail,
low_critical => $low_critical,
low_warning => $low_warning,
high_warning => $high_warning,
high_critical => $high_critical,
high_fail => $high_fail,
}});
next if not $sensor_name;
next if not $status;
next if not $units;
next if $units =~ /discrete/;
$units = "C" if $units =~ /degrees C/i;
$units = "F" if $units =~ /degrees F/i;
$units = "%" if $units =~ /percent/i;
$units = "W" if $units =~ /watt/i;
$units = "V" if $units =~ /volt/i;
# The BBU and RAID Controller, as reported by IPMI, is flaky and redundant. We
# monitor it via storcli/hpacucli (or OEM variant of), so we ignore it here.
next if $sensor_name eq "BBU";
next if $sensor_name eq "RAID Controller";
# HP seems to stick 'XX-' in front of some sensor names.
$sensor_name =~ s/^\d\d-//;
# Single PSU hosts often call their PSU just that, without a suffix integer. We'll
# add '1' in such cases.
if ($sensor_name eq "PSU")
{
$sensor_name = "PSU1";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_name => $sensor_name }});
}
# Dells have two sensors called simply "Temp".
if ($sensor_name eq "Temp")
{
$sensor_name = "Temp".$temp_count++;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_name => $sensor_name }});
}
# Thresholds that are 'na' need to be converted to numeric
$low_fail = -99 if $low_fail eq "na";
$low_critical = -99 if $low_critical eq "na";
$low_warning = -99 if $low_warning eq "na";
$high_warning = 999 if $high_warning eq "na";
$high_critical = 999 if $high_critical eq "na";
$high_fail = 999 if $high_fail eq "na";
# Values in the DB that are 'double precision' must be '' if not set.
$current_value = '' if not $current_value;
$low_fail = '' if not $low_fail;
$low_critical = '' if not $low_critical;
$low_warning = '' if not $low_warning;
$high_warning = '' if not $high_warning;
$high_critical = '' if not $high_critical;
$high_fail = '' if not $high_fail;
# Some values list 'inf' on some machines (HP...). Convert these to ''.
$current_value = '' if $current_value eq "inf";
$low_fail = '' if $low_fail eq "inf";
$low_critical = '' if $low_critical eq "inf";
$low_warning = '' if $low_warning eq "inf";
$high_warning = '' if $high_warning eq "inf";
$high_critical = '' if $high_critical eq "inf";
$high_fail = '' if $high_fail eq "inf";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
sensor_name => $sensor_name,
current_value => $current_value,
units => $units,
status => $status,
low_fail => $low_fail,
low_critical => $low_critical,
low_warning => $low_warning,
high_warning => $high_warning,
high_critical => $high_critical,
high_fail => $high_fail,
}});
if ($units eq "F")
{
# Convert to 'C'
$high_critical = $anvil->Convert->fahrenheit_to_celsius({temperature => $high_critical}) if $high_critical ne "";
$high_warning = $anvil->Convert->fahrenheit_to_celsius({temperature => $high_warning}) if $high_warning ne "";
$low_critical = $anvil->Convert->fahrenheit_to_celsius({temperature => $low_critical}) if $low_critical ne "";
$low_warning = $anvil->Convert->fahrenheit_to_celsius({temperature => $low_warning}) if $low_warning ne "";
$units = "C";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
low_critical => $low_critical,
low_warning => $low_warning,
high_warning => $high_warning,
high_critical => $high_critical,
units => $units,
}});
}
### TODO: It looks like the PSU state and the PSU temperature are called, simply,
### 'PSUx'... If so, change the temperature to 'PSUx Temperature'
if (($units eq "C") && ($sensor_name =~ /^PSU\d/i))
{
$sensor_name .= " Temperature";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_name => $sensor_name }});
}
# Similarly, 'PSUx Power' is used for power status and wattage....
if (($units eq "W") && ($sensor_name =~ /PSU\d Power/i))
{
$sensor_name =~ s/Power/Wattage/;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_name => $sensor_name }});
}
# And again, 'FAN PSUx' is used for both RPM and state...
if (($units eq "RPM") && ($sensor_name =~ /^FAN PSU\d/i))
{
$sensor_name .= " RPM";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_name => $sensor_name }});
}
# Record
$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_value_sensor_value} = $current_value;
$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_units} = $units;
$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_status} = $status;
$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_high_critical} = $high_critical;
$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_high_warning} = $high_warning;
$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_low_critical} = $low_critical;
$anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_low_warning} = $low_warning;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"ipmi::${host_name}::scan_ipmitool_sensor_name::${sensor_name}::scan_ipmitool_value_sensor_value" => $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_value_sensor_value},
"ipmi::${host_name}::scan_ipmitool_sensor_name::${sensor_name}::scan_ipmitool_sensor_units" => $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_units},
"ipmi::${host_name}::scan_ipmitool_sensor_name::${sensor_name}::scan_ipmitool_sensor_status" => $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_status},
"ipmi::${host_name}::scan_ipmitool_sensor_name::${sensor_name}::scan_ipmitool_sensor_high_critical" => $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_high_critical},
"ipmi::${host_name}::scan_ipmitool_sensor_name::${sensor_name}::scan_ipmitool_sensor_high_warning" => $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_high_warning},
"ipmi::${host_name}::scan_ipmitool_sensor_name::${sensor_name}::scan_ipmitool_sensor_low_critical" => $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_low_critical},
"ipmi::${host_name}::scan_ipmitool_sensor_name::${sensor_name}::scan_ipmitool_sensor_low_warning" => $anvil->data->{ipmi}{$host_name}{scan_ipmitool_sensor_name}{$sensor_name}{scan_ipmitool_sensor_low_warning},
}});
}
# Record how long it took.
my $sensor_read_time = $anvil->Convert->time({'time' => (time - $read_start_time)});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_ipmitool_log_0003", variables => {
host_name => $host_name,
'time' => $sensor_read_time
}});
return($problem);
}
=head2 configure_ipmi
This uses the host information along with the Anvil! the host is in to find and configure the local IPMI BMC.

@ -1889,8 +1889,11 @@ sub gather_pdu_data
}
# Can I ping it? This returns '1' if it was pingable, '0' if not.
my ($pinged) = $anvil->Network->ping({ping => $pdu_ip});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { pinged => $pinged }});
my ($pinged, $average_time) = $anvil->Network->ping({ping => $pdu_ip});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
pinged => $pinged,
average_time => $average_time,
}});
if (not $pinged)
{

@ -1496,7 +1496,7 @@ SELECT
FROM
scan_apc_ups_input
WHERE
scan_apc_ups_uuid = ".$anvil->Database->quote($scan_apc_ups_uuid)."
scan_apc_ups_input_scan_apc_ups_uuid = ".$anvil->Database->quote($scan_apc_ups_uuid)."
AND
scan_apc_ups_input_1m_minimum_input_voltage < ".$low_limit."
ORDER BY
@ -2092,8 +2092,11 @@ sub gather_ups_data
}
# Can I ping it? This returns '1' if it was pingable, '0' if not.
my ($pinged) = $anvil->Network->ping({ping => $ups_ip});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { pinged => $pinged }});
my ($pinged, $average_time) = $anvil->Network->ping({ping => $ups_ip});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
pinged => $pinged,
average_time => $average_time,
}});
if (not $pinged)
{

File diff suppressed because it is too large Load Diff

@ -15,8 +15,8 @@ NOTE: All string keys MUST be prefixed with the agent name! ie: 'scan_ipmitool_l
<!-- Messages entries -->
<key name="scan_ipmitool_message_0001">No IPMI BMC found on this host nor where any other machines with IPMI found or where accessible. Nothing to do.</key>
<key name="scan_ipmitool_message_0002">There was no IPMI sensor value units set for sensor: [#!variable!sensor!#] on the machine: [#!variable!machine!#].</key>
<key name="scan_ipmitool_message_0003">There was no IPMI sensor value set for sensor: [#!variable!sensor!#] on the machine: [#!variable!machine!#].</key>
<key name="scan_ipmitool_message_0002">There was no IPMI sensor value units set for sensor: [#!variable!sensor!#] on the machine: [#!variable!host_name!#].</key>
<key name="scan_ipmitool_message_0003">There was no IPMI sensor value set for sensor: [#!variable!sensor!#] on the machine: [#!variable!host_name!#].</key>
<key name="scan_ipmitool_message_0004">
The sensor: [#!variable!sensor_name!#] has changed.
- [#!variable!old_sensor_value!#] -> [#!variable!new_sensor_value!#]
@ -76,7 +76,7 @@ The temperature sensor: [#!variable!sensor_name!#] has risen blow critically hig
- [#!variable!old_sensor_value!#] -> [#!variable!new_sensor_value!#]
Note: If you are listening to 'critical' level alerts only, you will not get the alert telling you when the temperature is back to normal.
</key>
<key name="scan_ipmitool_message_0015">There was no IPMI sensor value units set for sensor: [#!variable!sensor!#] on the machine: [#!variable!machine!#].</key>
<key name="scan_ipmitool_message_0015">There was no IPMI sensor value units set for sensor: [#!variable!sensor!#] on the machine: [#!variable!host_name!#].</key>
<key name="scan_ipmitool_message_0016">
The sensor: [#!variable!sensor_name!#] has changed.
- [#!variable!old_sensor_value!#] -> [#!variable!new_sensor_value!#]
@ -87,10 +87,10 @@ The sensor: [#!variable!sensor_name!#] has changed.
- Low warning: [#!variable!old_low_warning!#] -> [#!variable!new_low_warning!#]
- Low critical: [#!variable!old_low_critical!#] -> [#!variable!new_low_critical!#]
</key>
<key name="scan_ipmitool_message_0017">There was no IPMI sensor value units set for sensor: [#!variable!sensor!#] on the machine: [#!variable!machine!#].</key>
<key name="scan_ipmitool_message_0018">There was no IPMI sensor value set for sensor: [#!variable!sensor!#] on the machine: [#!variable!machine!#].</key>
<key name="scan_ipmitool_message_0017">There was no IPMI sensor value units set for sensor: [#!variable!sensor!#] on the machine: [#!variable!host_name!#].</key>
<key name="scan_ipmitool_message_0018">There was no IPMI sensor value set for sensor: [#!variable!sensor!#] on the machine: [#!variable!host_name!#].</key>
<key name="scan_ipmitool_message_0019">
The new sensor: [#!variable!sensor_name!#] has been found on the machine: [#!variable!machine!#].
The new sensor: [#!variable!sensor_name!#] has been found on the machine: [#!variable!host_name!#].
- Value: [#!variable!sensor_value!#], Status: [#!variable!sensor_status!#]
- Thresholds:
- High critical: [#!variable!high_critical!#]
@ -99,7 +99,7 @@ The new sensor: [#!variable!sensor_name!#] has been found on the machine: [#!var
- Low critical: [#!variable!low_critical!#]
</key>
<key name="scan_ipmitool_message_0020">
The new sensor: [#!variable!sensor_name!#] has been found on the machine: [#!variable!machine!#].
The new sensor: [#!variable!sensor_name!#] has been found on the machine: [#!variable!host_name!#].
Warning: It is not in an OK state!
- Value: [#!variable!sensor_value!#], Status: [#!variable!sensor_status!#]
- Thresholds:
@ -110,9 +110,9 @@ The new sensor: [#!variable!sensor_name!#] has been found on the machine: [#!var
</key>
<!-- Log entries -->
<key name="scan_ipmitool_log_0001">Starting to read the IPMI sensor values for: [#!variable!machine!#]</key>
<key name="scan_ipmitool_log_0002">Failed to query node: [#!variable!machine!#]'s IPMI interface using the call: [#!variable!call!#]. Is the password correct?</key>
<key name="scan_ipmitool_log_0003">IPMI sensor values read from: [#!variable!machine!#] in: [#!variable!time!#].</key>
<key name="scan_ipmitool_log_0001">Starting to read the IPMI sensor values for: [#!variable!host_name!#]</key>
<key name="scan_ipmitool_log_0002">Failed to query node: [#!variable!host_name!#]'s IPMI interface using the call: [#!variable!call!#]. Is the password correct?</key>
<key name="scan_ipmitool_log_0003">IPMI sensor values read from: [#!variable!host_name!#] in: [#!variable!time!#].</key>
<key name="scan_ipmitool_log_0004">The sensor named: [#!variable!sensor_name!#] appears to have vanished, but this is the first scan that it vanished. This is generally harmless and just a sensor read issue.</key>
<key name="scan_ipmitool_log_0005">The sensor named: [#!variable!sensor_name!#] has returned.</key>

@ -240,6 +240,7 @@ The error was:
<key name="error_0165">The temperature: [#!variable!temperature!#] does not appear to be valid..</key>
<key name="error_0166">The resource: [#!variable!resource!#] in the config file: [#!variable!file!#] was found, but does not appear to be a valid UUID: [#!variable!uuid!#].</key>
<key name="error_0167">The resource: [#!variable!resource!#] in the config file: [#!variable!file!#] was found, and we were asked to replace the 'scan_drbd_resource_uuid' but the new UUID: [#!variable!uuid!#] is not a valud UUID.</key>
<key name="error_0168">The 'fence_ipmilan' command: [#!variable!command!#] does not appear to be valid.</key>
<!-- Table headers -->
<key name="header_0001">Current Network Interfaces and States</key>
@ -1071,6 +1072,24 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
====
</key>
<key name="log_0557">Scan agent: [#!variable!agent_name!#] exited after: [#!variable!runtime!#] seconds with the return code: [#!variable!return_code!#].</key>
<key name="log_0558">I'm not on the same network as: [#!variable!host_name!#]. Unable to check the power state.</key>
<key name="log_0559">The host: [#!variable!host_name!#] appears to be off, but there's no IPMI information, so unable to check the power state or power on the machine.</key>
<key name="log_0560">The host: [#!variable!host_name!#] has no IPMI information. Wouldn't be able to boot it, even if it's off, so skipping it.</key>
<key name="log_0561">The host: [#!variable!host_name!#] will be checked to see if it needs to be booted or not.</key>
<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 leave it off.</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>
<key name="log_0569">Unable to find an install manifest 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_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">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_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>
<!-- 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>
@ -1662,6 +1681,7 @@ If you are comfortable that the target has changed for a known reason, you can s
<key name="striker_0276">This tracks the last time a given mail server was configured for use. It allows for a round-robin switching of mail servers when one mail server stops working and two or more mail servers have been configured.</key>
<key name="striker_0277">No UPSes</key>
<key name="striker_0278">This is a condition record, used by programs like scan agents to track how long a condition has existed for.</key>
<key name="striker_0279">This indicated why a machine was powered off. This is used by ScanCore to decide if or when to power up the target host.</key>
<!-- These are generally units and appended to numbers -->
<key name="suffix_0001">#!variable!number!#/sec</key>

@ -13,6 +13,9 @@
# - Decide if it's worth having a separate ScanCore.log file or just feed into anvil.log.
# - Examine limits in: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#LimitCPU=
# - Use 'nvme-cli' to write a scan-nvme scan agent, can get thermal and wear data
# - Record how long a server's migration took in the past, and use that to determine which node to evacuate
# during load shed. Also, track how long it takes for servers to stop to determine when to initiate a total
# shutdown.
# -
use strict;
@ -50,6 +53,9 @@ $anvil->data->{scancore} = {
warning_temperature => 5,
warning_critical => 5,
},
power => {
safe_boot_percentage => 35,
},
};
$anvil->Storage->read_config();
@ -68,6 +74,9 @@ wait_for_database($anvil);
# If we're not configured, sleep.
wait_until_configured($anvil);
# Startup tasks.
startup_tasks($anvil);
# Load the strings from all the agents we know about before we process alerts so that we can include their
# messages in any emails we're going to send.
load_agent_strings($anvil);
@ -92,7 +101,10 @@ while(1)
if ($anvil->data->{sys}{database}{connections})
{
# Run the normal tasks
call_agents($anvil);
$anvil->ScanCore->call_agents({debug => 2});
# Do post-scan analysis.
$anvil->ScanCore->post_scan_analysis({debug => 2});
}
else
{
@ -141,91 +153,6 @@ $anvil->nice_exit({exit_code => 0});
# Functions #
#############################################################################################################
# This invokes all scan agents found in 'path::directories::scan_agents'
sub call_agents
{
my ($anvil) = @_;
# Get the current list of scan agents on this system.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"path::directories::scan_agents" => $anvil->data->{path}{directories}{scan_agents},
}});
scan_directory($anvil, $anvil->data->{path}{directories}{scan_agents});
# Now loop through the agents I found and call them.
my $timeout = 30;
if ((exists $anvil->data->{scancore}{timing}{agent_runtime}) && ($anvil->data->{scancore}{timing}{agent_runtime} =~ /^\d+$/))
{
$timeout = $anvil->data->{scancore}{timing}{agent_runtime};
}
foreach my $agent_name (sort {$a cmp $b} keys %{$anvil->data->{scancore}{agent}})
{
my $agent_path = $anvil->data->{scancore}{agent}{$agent_name};
my $agent_words = $agent_path.".xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
agent_name => $agent_name,
agent_path => $agent_path,
agent_words => $agent_words,
}});
if ((-e $agent_words) && (-r $agent_words))
{
# Read the words file so that we can generate alerts later.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0251", variables => {
agent_name => $agent_name,
file => $agent_words,
}});
$anvil->Words->read({file => $agent_words});
}
# Set the timeout.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
agent_name => $agent_name,
"scancore::${agent_name}::timeout" => $anvil->data->{scancore}{$agent_name}{timeout},
}});
# Now call the agent.
my $start_time = time;
if (($anvil->data->{scancore}{$agent_name}{timeout}) && ($anvil->data->{scancore}{$agent_name}{timeout} =~ /^\d+$/))
{
$timeout = $anvil->data->{scancore}{$agent_name}{timeout};
}
my $shell_call = $agent_path;
if ($anvil->data->{sys}{'log'}{level})
{
$shell_call .= " ".$anvil->data->{sys}{'log'}{level};
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
# Tell the user this agent is about to run...
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0252", variables => {
agent_name => $agent_name,
timeout => $timeout,
}});
my ($output, $return_code) = $anvil->System->call({timeout => $timeout, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }});
foreach my $line (split/\n/, $output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0557", variables => {
agent_name => $agent_name,
runtime => (time - $start_time),
return_code => $return_code,
}});
# If the return code is '124', timeout popped.
if ($return_code eq "124")
{
### TODO: Check if this alert was set so it only goes out once.
# Register an alert...
$anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "message_0180,!!agent_name!".$agent_name."!!,!!timeout!".$timeout."!!"});
}
}
return(0);
}
# This cleans things up after a scan run has completed.
sub cleanup_after_run
{
@ -309,47 +236,6 @@ sub prepare_for_run
return(0);
}
# This looks in the passed-in directory for scan agents or sub-directories (which will in turn be scanned).
sub scan_directory
{
my ($anvil, $directory) = @_;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { directory => $directory }});
local(*DIRECTORY);
opendir(DIRECTORY, $directory);
while(my $file = readdir(DIRECTORY))
{
next if $file eq ".";
next if $file eq "..";
my $full_path = $directory."/".$file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
file => $file,
full_path => $full_path,
}});
# If we're looking at a directory, scan it. Otherwise, see if it's an executable and that it
# starts with 'scan-*'.
if (-d $full_path)
{
# This is a directory, dive into it.
scan_directory($anvil, $full_path);
}
elsif (-x $full_path)
{
# Now I only want to know if the file starts with 'scan-'
next if $file !~ /^scan-/;
# If I am still alive, I am looking at a scan agent!
$anvil->data->{scancore}{agent}{$file} = $full_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"scancore::agent::${file}" => $anvil->data->{scancore}{agent}{$file},
}});
}
}
closedir(DIRECTORY);
return(0);
}
# This loops until it can connect to at least one database.
sub wait_for_database
{
@ -428,6 +314,28 @@ sub wait_until_configured
return(0);
}
# Things we need to do at startup.
sub startup_tasks
{
my ($anvil) = @_;
# Make sure our stop reason is cleared.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0572"});
my $variable_uuid = $anvil->Database->insert_or_update_variables({
debug => 2,
variable_name => 'system::stop_reason',
variable_value => '',
variable_default => '',
variable_description => 'striker_0279',
variable_section => 'system',
variable_source_uuid => '4c4c4544-0043-4210-8042-c3c04f523533',
variable_source_table => 'hosts',
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
return(0);
}
=pod
"I'm sorry, but I don't want to be an emperor. That's not my business. I don't want to rule or conquer anyone. I should like to help everyone if possible - Jew, Gentile - black man - white.

@ -1252,13 +1252,14 @@ ORDER BY
foreach my $interface (sort {$a cmp $b} keys %{$match->{$short_host_name}})
{
my $remote_ip = $match->{$short_host_name}{$interface}{ip};
my $pinged = $anvil->Network->ping({
my ($pinged, $average_time) = $anvil->Network->ping({
ping => $remote_ip,
count => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
remote_ip => $remote_ip,
pinged => $pinged,
average_time => $average_time,
}});
if ($pinged)
{
@ -1473,6 +1474,7 @@ sub load_packages
"adwaita-icon-theme.noarch",
"alsa-lib.x86_64",
"alteeve-el8-repo.noarch",
"annobin.x86_64",
"anvil-core.noarch",
"anvil-dr.noarch",
"anvil-node.noarch",
@ -1562,6 +1564,7 @@ sub load_packages
"cronie.x86_64",
"crontabs.noarch",
"crypto-policies.noarch",
"crypto-policies-scripts.noarch",
"cryptsetup-libs.x86_64",
"cups-libs.x86_64",
"cups-pk-helper.x86_64",
@ -1611,13 +1614,17 @@ sub load_packages
"dracut.x86_64",
"drbd90-utils.x86_64",
"drpm.x86_64",
"dwz.x86_64",
],
e => [
"e2fsprogs-libs.x86_64",
"e2fsprogs.x86_64",
"edk2-ovmf.noarch",
"efi-srpm-macros.noarch",
"elfutils.x86_64",
"elfutils-default-yama-scope.noarch",
"elfutils-libelf.x86_64",
"elfutils-libelf-devel.x86_64",
"elfutils-libs.x86_64",
"emacs-filesystem.noarch",
"enchant.x86_64",
@ -1689,8 +1696,10 @@ sub load_packages
g => [
"gawk.x86_64",
"GConf2.x86_64",
"gc.x86_64",
"gcc.x86_64",
"gcr.x86_64",
"gdb-headless.x86_64",
"gdbm-libs.x86_64",
"gdbm.x86_64",
"gdisk.x86_64",
@ -1705,6 +1714,7 @@ sub load_packages
"geolite2-country.noarch",
"gettext-libs.x86_64",
"gettext.x86_64",
"ghc-srpm-macros.noarch",
"gjs.x86_64",
"glib-networking.x86_64",
"glib2.x86_64",
@ -1741,6 +1751,7 @@ sub load_packages
"gnutls-dane.x86_64",
"gnutls-utils.x86_64",
"gnutls.x86_64",
"go-srpm-macros.noarch",
"gobject-introspection.x86_64",
"gpgme.x86_64",
"gpm-libs.x86_64",
@ -1766,6 +1777,7 @@ sub load_packages
"gtk-vnc2.x86_64",
"gtk2.x86_64",
"gtk3.x86_64",
"guile.x86_64",
"gvfs.x86_64",
"gvfs-client.x86_64",
"gvnc.x86_64",
@ -1862,7 +1874,6 @@ sub load_packages
"krb5-libs.x86_64",
],
l => [
"langpacks-en.noarch",
"lcms2.x86_64",
"less.x86_64",
@ -1897,7 +1908,9 @@ sub load_packages
"libassuan.x86_64",
"libasyncns.x86_64",
"libatasmart.x86_64",
"libatomic_ops.x86_64",
"libattr.x86_64",
"libbabeltrace.x86_64",
"libbasicobjects.x86_64",
"libblkid.x86_64",
"libbytesize.x86_64",
@ -1963,6 +1976,7 @@ sub load_packages
"libimobiledevice.x86_64",
"libini_config.x86_64",
"libinput.x86_64",
"libipt.x86_64",
"libiscsi.x86_64",
"libjpeg-turbo.x86_64",
"libkcapi-hmaccalc.x86_64",
@ -2129,6 +2143,7 @@ sub load_packages
'm' => [
"mailcap.noarch",
"mailx.x86_64",
"make.x86_64",
"man-db.x86_64",
"mcpp.x86_64",
"mdadm.x86_64",
@ -2173,16 +2188,18 @@ sub load_packages
"nmap.x86_64",
"npth.x86_64",
"nspr.x86_64",
"nss.x86_64",
"nss-softokn-freebl.x86_64",
"nss-softokn.x86_64",
"nss-sysinit.x86_64",
"nss-util.x86_64",
"nss.x86_64",
"numactl-libs.x86_64",
"numad.x86_64",
"nvme-cli.x86_64",
],
o => [
"ocaml-srpm-macros.noarch",
"openblas-srpm-macros.noarch",
"openldap.x86_64",
"openssh-clients.x86_64",
"openssh-server.x86_64",
@ -2207,6 +2224,7 @@ sub load_packages
"pango.x86_64",
"parted.x86_64",
"passwd.x86_64",
"patch.x86_64",
"pciutils-libs.x86_64",
"pciutils.x86_64",
"pcre.x86_64",
@ -2214,6 +2232,7 @@ sub load_packages
"perl-aliased.noarch",
"perl-Algorithm-C3.noarch",
"perl-Algorithm-Diff.noarch",
"perl-Authen-SASL.noarch",
"perl-B-Hooks-EndOfScope.noarch",
"perl-CGI.noarch",
"perl-Capture-Tiny.noarch",
@ -2223,6 +2242,7 @@ sub load_packages
"perl-Class-Method-Modifiers.noarch",
"perl-Compress-Raw-Bzip2.x86_64",
"perl-Compress-Raw-Zlib.x86_64",
"perl-Convert-ASN1.noarch",
"perl-Curses.x86_64",
"perl-Curses-UI.noarch",
"perl-DBD-Pg.x86_64",
@ -2266,6 +2286,7 @@ sub load_packages
"perl-Filter-Simple.noarch",
"perl-Future.noarch",
"perl-Getopt-Long.noarch",
"perl-GSSAPI.x86_64",
"perl-HTML-FromText.noarch",
"perl-HTML-Parser.x86_64",
"perl-HTML-Strip.x86_64",
@ -2285,6 +2306,7 @@ sub load_packages
"perl-IPC-SysV.x86_64",
"perl-JSON.noarch",
"perl-JSON-PP.noarch",
"perl-LDAP.noarch",
"perl-LWP-MediaTypes.noarch",
"perl-Log-Contextual.noarch",
"perl-Log-Dispatch-FileRotate.noarch",
@ -2337,6 +2359,7 @@ sub load_packages
"perl-Socket.x86_64",
"perl-Socket6.x86_64",
"perl-Specio.noarch",
"perl-srpm-macros.noarch",
"perl-Storable.x86_64",
"perl-strictures.noarch",
"perl-String-ShellQuote.noarch",
@ -2354,7 +2377,9 @@ sub load_packages
"perl-Test-Simple.noarch",
"perl-Text-Diff.noarch",
"perl-Text-ParseWords.noarch",
"perl-Text-Soundex.x86_64",
"perl-Text-Tabs+Wrap.noarch",
"perl-Text-Unidecode.noarch",
"perl-Time-HiRes.x86_64",
"perl-Time-Local.noarch",
"perl-TimeDate.noarch",
@ -2418,7 +2443,7 @@ sub load_packages
"pulseaudio-libs.x86_64",
"pulseaudio-module-bluetooth.x86_64",
"pulseaudio.x86_64",
#"python3-IPy.noarch",
"python-srpm-macros.noarch",
"python3-asn1crypto.noarch",
"python3-audit.x86_64",
"python3-argcomplete.noarch",
@ -2468,8 +2493,10 @@ sub load_packages
"python3-pyparsing.noarch",
"python3-pysocks.noarch",
"python3-pyudev.noarch",
"python3-pyyaml.x86_64",
"python3-requests.noarch",
"python3-rpm.x86_64",
"python3-rpm-macros.noarch",
"python3-schedutils.x86_64",
"python3-setools.x86_64",
"python3-setuptools.noarch",
@ -2498,6 +2525,7 @@ sub load_packages
"qemu-kvm-common.x86_64",
"qemu-kvm-core.x86_64",
"qemu-kvm.x86_64",
"qt5-srpm-macros.noarch",
"quota-nls.noarch",
"quota.x86_64",
],
@ -2505,10 +2533,13 @@ sub load_packages
"radvd.x86_64",
"rdma-core.x86_64",
"readline.x86_64",
"redhat-rpm-config.noarch",
"rest.x86_64",
"rootfiles.noarch",
"rpcbind.x86_64",
"rpm-build.x86_64",
"rpm-build-libs.x86_64",
"rpmdevtools.noarch",
"rpm-libs.x86_64",
"rpm-plugin-selinux.x86_64",
"rpm-plugin-systemd-inhibit.x86_64",
@ -2527,6 +2558,7 @@ sub load_packages
"rubygem-psych.x86_64",
"rubygem-rdoc.noarch",
"rubygems.noarch",
"rust-srpm-macros.noarch",
],
's' => [
"samba-client-libs.x86_64",
@ -2622,8 +2654,6 @@ sub load_packages
w => [
"webkit2gtk3.x86_64",
"webkit2gtk3-jsc.x86_64",
"webkit2gtk3-plugin-process-gtk2.x86_64",
"webkit2gtk3.x86_64",
"webrtc-audio-processing.x86_64",
"wget.x86_64",
"which.x86_64",
@ -2654,6 +2684,8 @@ sub load_packages
],
z => [
"zlib.x86_64",
"zlib-devel.x86_64",
"zstd.x86_64",
],
};
@ -2693,6 +2725,7 @@ sub load_packages
],
};
my ($os_type, $os_arch) = $anvil->Get->os_type();
if ($os_type eq "rhel8")
{
@ -2709,8 +2742,7 @@ sub load_packages
push @{$anvil->data->{packages}{c}}, "centos-indexhtml.noarch";
push @{$anvil->data->{packages}{c}}, "centos-logos-httpd.noarch";
push @{$anvil->data->{packages}{c}}, "centos-logos.x86_64";
push @{$anvil->data->{packages}{c}}, "centos-release.x86_64";
push @{$anvil->data->{packages}{c}}, "centos-repos.x86_64";
push @{$anvil->data->{packages}{c}}, "centos-linux-release.noarch";
# While we're here, we will need to rename /var/www/html/rhel8 to /var/www/html/rhel8, as
# 'centos8' and '/var/lib/tftpboot/rhel8' as 'centos8', as is used by anvil-striker-extra.

@ -23,16 +23,39 @@ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "
$anvil->Get->switches;
# Connect to the database(s).
#$anvil->Database->connect;
#$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0132"});
$anvil->Database->connect;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0132"});
my $hours = 0;
my $minutes = 3;
my $seconds = 24;
if (0)
{
foreach my $uuid ("4c4c4544-0043-4210-8043-c3c04f523533", "4c4c4544-0043-4210-8042-c3c04f523533", "30343536-3138-5355-4534-3238324b4842", "b4e46faf-0ebe-e211-a0d6-00262d0ca874", "4ba42b4e-9bf7-e311-a889-899427029de4")
{
my $variable_uuid = $anvil->Database->insert_or_update_variables({
debug => 2,
variable_name => 'system::stop_reason',
variable_value => 'thermal',
variable_default => '',
variable_description => 'striker_0279',
variable_section => 'system',
variable_source_uuid => $uuid,
variable_source_table => 'hosts',
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
}
}
print "Hours: [".$hours."], minutes: [".$minutes."], seconds: [".$seconds."]\n";
if (1)
{
$anvil->ScanCore->post_scan_analysis({debug => 3});
}
my $estimated_time_to_sync = (($hours * 3600) + ($minutes * 60) + $seconds);
print "ETA: [".$estimated_time_to_sync."] (".$anvil->Convert->time({'time' => $estimated_time_to_sync}).")\n";
if (0)
{
my $problem = $anvil->Striker->load_manifest({
debug => 2,
manifest_uuid => "006ee2cb-1fbd-4ea6-89d6-96cf3bc94940",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
}
$anvil->nice_exit({exit_code => 0});

Loading…
Cancel
Save