From 2e376911165acd2ae578ac7cbc7d3e34344a73ab Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 20 Apr 2021 22:46:51 -0400 Subject: [PATCH 1/3] * Updated DRBD->gather_data() to store data on peers so that the peer's LV path and backing disk is recorded. Also fixed a bug in ->get_status() where the return code for local calls was stored as a host name. * Added the scan-hpacucli scan agent. It's been done for a while and should have been added ages ago. * Updated anvil-rename-server to get to the point where it will take down the DRBD resources on all machines, but waits if there is a sync under way. It also verifies that the server is off on all systems from virsh's perspective. Signed-off-by: Digimer --- Anvil/Tools/DRBD.pm | 49 +- ocf/alteeve/server | 2 +- scancore-agents/Makefile.am | 7 + scancore-agents/scan-hpacucli/scan-hpacucli | 5250 +++++++++++++++++ .../scan-hpacucli/scan-hpacucli.sql | 572 ++ .../scan-hpacucli/scan-hpacucli.xml | 308 + share/words.xml | 17 + tools/anvil-rename-server | 552 +- 8 files changed, 6719 insertions(+), 38 deletions(-) create mode 100755 scancore-agents/scan-hpacucli/scan-hpacucli create mode 100644 scancore-agents/scan-hpacucli/scan-hpacucli.sql create mode 100644 scancore-agents/scan-hpacucli/scan-hpacucli.xml diff --git a/Anvil/Tools/DRBD.pm b/Anvil/Tools/DRBD.pm index cedd6647..9c3c737b 100644 --- a/Anvil/Tools/DRBD.pm +++ b/Anvil/Tools/DRBD.pm @@ -563,7 +563,7 @@ sub gather_data my $this_host_name = $host->{name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_host_name => $this_host_name }}); - next if (($this_host_name ne $anvil->Get->host_name) && ($this_host_name ne $anvil->Get->short_host_name)); + # Record the details under the hosts foreach my $volume_vnr ($host->findnodes('./volume')) { my $volume = $volume_vnr->{vnr}; @@ -573,15 +573,29 @@ sub gather_data 's2:meta_disk' => $meta_disk, }}); - $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_path} = $volume_vnr->findvalue('./device'); - $anvil->data->{new}{resource}{$resource}{volume}{$volume}{backing_disk} = $volume_vnr->findvalue('./disk'); - $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_minor} = $volume_vnr->findvalue('./device/@minor'); - $anvil->data->{new}{resource}{$resource}{volume}{$volume}{size} = 0; + $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{device_path} = $volume_vnr->findvalue('./device'); + $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{backing_disk} = $volume_vnr->findvalue('./disk'); + $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{device_minor} = $volume_vnr->findvalue('./device/@minor'); + $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{size} = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s1:new::resource::${resource}::volume::${volume}::device_path" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_path}, - "s2:new::resource::${resource}::volume::${volume}::backing_disk" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{backing_disk}, - "s3:new::resource::${resource}::volume::${volume}::device_minor" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_minor}, + "s1:new::resource::${resource}::host::${this_host_name}::volume::${volume}::device_path" => $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{device_path}, + "s2:new::resource::${resource}::host::${this_host_name}::volume::${volume}::backing_disk" => $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{backing_disk}, + "s3:new::resource::${resource}::host::${this_host_name}::volume::${volume}::device_minor" => $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{device_minor}, }}); + + # Record the local data only. + if (($this_host_name ne $anvil->Get->host_name) && ($this_host_name ne $anvil->Get->short_host_name)) + { + $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_path} = $volume_vnr->findvalue('./device'); + $anvil->data->{new}{resource}{$resource}{volume}{$volume}{backing_disk} = $volume_vnr->findvalue('./disk'); + $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_minor} = $volume_vnr->findvalue('./device/@minor'); + $anvil->data->{new}{resource}{$resource}{volume}{$volume}{size} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "s1:new::resource::${resource}::volume::${volume}::device_path" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_path}, + "s2:new::resource::${resource}::volume::${volume}::backing_disk" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{backing_disk}, + "s3:new::resource::${resource}::volume::${volume}::device_minor" => $anvil->data->{new}{resource}{$resource}{volume}{$volume}{device_minor}, + }}); + } } } @@ -1383,14 +1397,8 @@ sub get_status my $host = $anvil->Get->short_host_name(); if ($anvil->Network->is_local({host => $target})) { - # Clear the hash where we'll store the data. - if (exists $anvil->data->{drbd}{status}{$host}) - { - delete $anvil->data->{drbd}{status}{$host}; - } - # Local. - ($output, $anvil->data->{drbd}{status}{return_code}) = $anvil->System->call({shell_call => $shell_call}); + ($output, $anvil->data->{drbd}{status}{$host}{return_code}) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, "drbd::status::${host}::return_code" => $anvil->data->{drbd}{status}{return_code}, @@ -1398,14 +1406,8 @@ sub get_status } else { - # Clear the hash where we'll store the data. - $host = $target; - if (exists $anvil->data->{drbd}{status}{$host}) - { - delete $anvil->data->{drbd}{status}{$host}; - } - # Remote call. + $host = $target; ($output, my $error, $anvil->data->{drbd}{status}{$host}{return_code}) = $anvil->Remote->call({ debug => $debug, shell_call => $shell_call, @@ -1421,6 +1423,7 @@ sub get_status }}); } + # Clear the hash where we'll store the data. if (exists $anvil->data->{drbd}{status}{$host}) { delete $anvil->data->{drbd}{status}{$host}; @@ -1655,6 +1658,8 @@ sub manage_resource return(1); } + ### TODO: When taking down a resource, check to see if any machine is SyncTarget and take it/them + ### down first. See anvil-rename-server -> verify_server_is_off() for the logic. ### TODO: Sanity check the resource name and task requested. my $shell_call = $anvil->data->{path}{exe}{drbdadm}." ".$task." ".$resource; my $output = ""; diff --git a/ocf/alteeve/server b/ocf/alteeve/server index 9e3a12c8..6c669686 100755 --- a/ocf/alteeve/server +++ b/ocf/alteeve/server @@ -734,7 +734,7 @@ sub stop_drbd_resource peer => $peer, }}); - # Start DRBD locally. + # Stop the DRBD resource. foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$local_host}{$server}{resource}}) { my $peer_ip = $anvil->data->{drbd}{config}{$host}{resource}{$resource}{connection}{$peer}{ip_address}; diff --git a/scancore-agents/Makefile.am b/scancore-agents/Makefile.am index 99f00189..67573625 100644 --- a/scancore-agents/Makefile.am +++ b/scancore-agents/Makefile.am @@ -45,6 +45,13 @@ dist_hardware_DATA = \ dist_hardware_SCRIPTS = \ scan-hardware/scan-hardware +hpacuclidir = ${targetdir}/scan-hpacucli +dist_hpacucli_DATA = \ + scan-hardware/scan-hpacucli.xml \ + scan-hardware/scan-hpacucli.sql +dist_hardware_SCRIPTS = \ + scan-hardware/scan-hpacucli + ipmitooldir = ${targetdir}/scan-ipmitool dist_ipmitool_DATA = \ scan-ipmitool/scan-ipmitool.sql \ diff --git a/scancore-agents/scan-hpacucli/scan-hpacucli b/scancore-agents/scan-hpacucli/scan-hpacucli new file mode 100755 index 00000000..31cb7504 --- /dev/null +++ b/scancore-agents/scan-hpacucli/scan-hpacucli @@ -0,0 +1,5250 @@ +#!/usr/bin/perl +# +# This software was created by Alteeve's Niche! Inc. and has been released +# under the terms of the GNU GPL version 2. +# +# ScanCore Scan Agent for HPE type RAID controllers using the 'hpacucli' command line tool. +# +# https://alteeve.com +# +# Exit Codes: +# 0 - Success +# 1 - hpacucli not installed +# 2 - hpacucli is installed but it is not executable. +# 3 - No HPE type controllers found. +# 4 - Controller numeric value is invalid. +# 5 - Cache module numeric value is invalid. +# 6 - Array numeric value is invalid. +# 7 - Logical drive numeric value is invalid. +# 8 - Physical drive numeric value is invalid. +# 9 - Physical drive has no serial number. +# +# 255 - The host's UUID isn't in the hosts table yet, ScanCore itself hasn't been run. +# +# TODO: +# - +# +# NOTE: +# - Health values +# - Controller - Correctable errors = 1 +# - Controller - Uncorrectable errors = 5 +# - Controller - Status changes = 5 +# - Drive group - partially degraded = 5 +# - Drive group - degraded = 10 +# - Cachevault - Replacement needed = 5 +# - BBU - Replacement needed = 5 +# - Temperature - Critical = 2 +# - Temperature - Warning = 1 + +# Use my modules. +use strict; +use warnings; +use Anvil::Tools; +use Data::Dumper; +use Math::BigInt; +no warnings 'recursion'; + +# Disable buffering +$| = 1; + +# Prevent a discrepency between UID/GID and EUID/EGID from throwing an error. +$< = $>; +$( = $); + +my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; +my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; +if (($running_directory =~ /^\./) && ($ENV{PWD})) +{ + $running_directory =~ s/^\./$ENV{PWD}/; +} + +my $anvil = Anvil::Tools->new(); + +# Make sure we're running as 'root' +# $< == real UID, $> == effective UID +if (($< != 0) && ($> != 0)) +{ + # Not root + print $anvil->Words->string({key => "error_0005"})."\n"; + $anvil->nice_exit({exit_code => 1}); +} + +# Here we store data and variables for this agent. +$anvil->data->{'scan-hpacucli'} = { + health => { + old => {}, + new => {}, + }, + + # This will keep track of devices with serial numbers so that it is easy to look up + # the UUID from the serial numbers and vice versa. + controllers => { + by_serial => {}, + by_uuid => {}, + }, + physical_drives => { + by_serial => {}, + by_uuid => {}, + }, + # Checking the drives for errors is expensive, so it is only done every hour (or + # there abouts). Change the interval if you want to check more or less often. + diagnostics_interval => 1800, + disable => 0, + ignore_maximum_temperature => 0, + language => "en_CA", + log_level => 1, + log_language => "en_CA", + log_file => "/var/log/ScanCore.log", + log_db_transactions => 0, + thresholds => { + # This is used for unknown sensors and really shouldn't be used at all. + 'default' => { + high_warning => 50, + high_critical => 55, + low_warning => 15, + low_critical => 10, + jump => 5, + buffer => 3, + }, + drives => { + # http://storage.toshiba.com/docs/product-datasheets/mk01grrb-r.pdf + # http://toshiba.semicon-storage.com/us/product/storage-products/enterprise-ssd/px02smb-px02smfxxx.html + high_warning => 50, + high_critical => 55, + low_warning => 5, + low_critical => 0, + jump => 5, + buffer => 2, + }, + # I've not found official ranges on this yet... These are best-guess values + controller_temperature => { + high_warning => 100, + high_critical => 105, + low_warning => 15, + low_critical => 10, + jump => 10, + buffer => 5, + }, + # I've not found official ranges on this yet... These are best-guess values + capacitor => { + high_warning => 50, + high_critical => 55, + low_warning => 15, + low_critical => 10, + jump => 5, + buffer => 3, + }, + # https://support.hpe.com/hpsc/doc/public/display?docId=c04441382 + cache => { + high_warning => 50, + high_critical => 55, + low_warning => 15, + low_critical => 10, + jump => 5, + buffer => 3, + }, + }, + sys => { + alert_sort => 2, + controller => {}, + controller_count => 0, + # When a lock is requested, this is set to the time the lock was set. + # DB->do_db_write() and DB->do_db_read() will check this and if its age is >50% of + # scancore::locking::reap_age, it will renew the lock. + lock_active => 0, + process_diagnostics => 0, + }, + queries => [], +}; + +$anvil->Storage->read_config(); +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0115", variables => { program => $THIS_FILE }}); + +# Read switches +$anvil->data->{switches}{force} = 0; +$anvil->data->{switches}{purge} = 0; +$anvil->Get->switches; + +# If we're disabled and '--force' wasn't used, exit. +if (($anvil->data->{scancore}{'scan-hpacucli'}{disable}) && (not $anvil->data->{switches}{force})) +{ + # Exit. + $anvil->nice_exit({exit_code => 0}); +} + +# Handle start-up tasks +my $problem = $anvil->ScanCore->agent_startup({agent => $THIS_FILE}); +if ($problem) +{ + $anvil->nice_exit({exit_code => 1}); +} + +if ($anvil->data->{switches}{purge}) +{ + # This can be called when doing bulk-database purges. + my $schema_file = $anvil->data->{path}{directories}{scan_agents}."/".$THIS_FILE."/".$THIS_FILE.".sql"; + $anvil->Database->purge_data({ + debug => 2, + tables => $anvil->Database->get_tables_from_schema({schema_file => $schema_file}), + }); + $anvil->nice_exit({exit_code => 0}); +} + +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "scan_hpacucli_message_0001"}); + +# This does two things; It checks to see if hpacucli is installed (exits '1' if not, exits '2' if not +# executable) and then checks to see if any controllers are found in the system (exits '3' if not). +find_hp_controllers($anvil); + +# If we're still alive, start gathering data. +gather_data($anvil); + +# Figure out, other than temperatures, what should be added to or removed from health. +pre_process_health($anvil); + +# Look for changes. +find_changes($anvil); + +# Process temperatures! This also sets health values for warning and critical temperatures so make sure we +# always call this before process_health(). +process_temperatures($anvil); + +# Finally, process health weights. +process_health($anvil); + +# Update the database +$anvil->Database->insert_or_update_updated({updated_by => $THIS_FILE}); + +# Clean up and go away. +$anvil->nice_exit({exit_code => 0}); + + +############################################################################################################# +# Function below # +############################################################################################################# + +# This reads in the last scan data from one of the databases and compares it against the just-read data. If +# anything changed, register an alert. +sub find_changes +{ + my ($anvil) = @_; + + # Read in the old data. As we compare and UPDATE if needed, then we'll delete. If any are not found, + # then it must be new and will be INSERTed. Any old records left over will have vanished. + read_last_scan($anvil); + + ### NOTE: We will loop through each section of data we scanned, deleting records as we process them + ### that existed in the DB, and then marking as removed anything left in the databased data not + ### seen in this scan. + process_controllers($anvil); + + # Now that controllers have been proceesed, we can process drives (and their arrays) + process_drives($anvil); + + # If we processed diagnostics, update + if ($anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics}) + { + my $query = " +UPDATE + scan_hpacucli_controllers +SET + scan_hpacucli_controller_last_diagnostics = ".time.", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_controller_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); + } + + return(0); +} + +# This reads in all health wieghts previously set, alters ones as needed, INSERTs new ones and DELETEs old +# ones. +sub process_health +{ + my ($anvil) = @_; + + # This will hold our updates. + $anvil->data->{'scan-hpacucli'}{queries} = []; + + # Read in previous health values. + my $query = " +SELECT + health_uuid, + health_agent_name, + health_source_name, + health_source_weight +FROM + health +WHERE + health_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +AND + health_agent_name = ".$anvil->Database->quote($THIS_FILE)." +;"; + $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, + }}); + foreach my $row (@{$results}) + { + my $health_uuid = $row->[0]; + my $health_agent_name = $row->[1]; + my $health_source_name = $row->[2]; + my $health_source_weight = $row->[3]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + health_uuid => $health_uuid, + health_agent_name => $health_agent_name, + health_source_name => $health_source_name, + health_source_weight => $health_source_weight, + }}); + + $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{uuid} = $health_uuid; + $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{value} = $health_source_weight; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::health::old::${health_source_name}::uuid" => $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{uuid}, + "scan-hpacucli::health::old::${health_source_name}::value" => $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{value}, + }}); + } + + # Read in the new ones + foreach my $health_source_name (sort {$a cmp $b} keys %{$anvil->data->{'scan-hpacucli'}{health}{new}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }}); + + my $health_uuid = ""; + if (exists $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}) + { + $health_uuid = $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{uuid}; + } + $health_uuid = $anvil->Database->insert_or_update_health({ + debug => 2, + cache => $anvil->data->{'scan-hpacucli'}{queries}, + health_uuid => $health_uuid, + health_host_uuid => $anvil->Get->host_uuid, + health_agent_name => $THIS_FILE, + health_source_name => $health_source_name, + health_source_weight => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_uuid => $health_uuid }}); + + if (exists $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}) + { + # Delete the new old key, regardless of whether it has changed now. + delete $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}; + } + } + + # Delete any old entries that are left. + foreach my $health_source_name (sort {$a cmp $b} keys %{$anvil->data->{'scan-hpacucli'}{health}{old}}) + { + # Well set the source name to 'DELETED'. + my $health_uuid = $anvil->Database->insert_or_update_health({ + debug => 2, + cache => $anvil->data->{'scan-hpacucli'}{queries}, + 'delete' => 1, + health_uuid => $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{uuid}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_uuid => $health_uuid }}); + } + + # Now commit the changes. + $anvil->Database->write({query => $anvil->data->{'scan-hpacucli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-hpacucli'}{queries} = []; + + return(0); +} + +# This reads in the various temperature sensors we read from this run and will set the temperature table +# and/or set/clear warnings/critical states. +sub process_temperatures +{ + my ($anvil) = @_; + + ### NOTE: We use 'sensor_host' to hold the serial number of the device hosting the sensor. + # First, read in all existing entries. We'll compare and UPDATE or INSERT as needed and DELETE any + # stale entries. + my $query = " +SELECT + temperature_uuid, + temperature_sensor_name, + temperature_sensor_host, + temperature_value_c, + temperature_state, + temperature_is +FROM + temperature +WHERE + temperature_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +AND + temperature_agent_name = ".$anvil->Database->quote($THIS_FILE)." +;"; + $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__}); + + # One or more records were found. + foreach my $row (@{$results}) + { + my $temperature_sensor_name = $row->[1]; + my $temperature_sensor_host = $row->[2]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_sensor_name => $temperature_sensor_name, + temperature_sensor_host => $temperature_sensor_host, + }}); + + $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_uuid} = $row->[0]; + $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_value_c} = $row->[3]; + $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_state} = $row->[4]; + $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_is} = $row->[5]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "old::temperature::${temperature_sensor_name}::${temperature_sensor_host}::temperature_uuid" => $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_uuid}, + "old::temperature::${temperature_sensor_name}::${temperature_sensor_host}::temperature_value_c" => $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_value_c}, + "old::temperature::${temperature_sensor_name}::${temperature_sensor_host}::temperature_state" => $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_state}, + "old::temperature::${temperature_sensor_name}::${temperature_sensor_host}::temperature_is" => $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_is}, + }}); + } + + # Loop through the temperature from this scan. + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{new}{temperature}}) + { + foreach my $serial_number (sort {$a cmp $b} keys %{$anvil->data->{new}{temperature}{$variable}}) + { + my $new_temperature_value_c = $anvil->data->{new}{temperature}{$variable}{$serial_number}{temperature_value_c}; + my $new_temperature_state = $anvil->data->{new}{temperature}{$variable}{$serial_number}{temperature_state}; + my $new_temperature_is = $anvil->data->{new}{temperature}{$variable}{$serial_number}{temperature_is}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + serial_number => $serial_number, + new_temperature_value_c => $new_temperature_value_c, + new_temperature_state => $new_temperature_state, + new_temperature_is => $new_temperature_is, + }}); + + # If the state is 'warning', set a health weight of 1 and set critical to 2. + my $health_source_name = "temperature:".$serial_number; + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 0; + if ($new_temperature_state eq "warning") + { + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 1; + } + elsif ($new_temperature_state eq "critical") + { + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 2; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }}); + + my $temperature_uuid = ""; + if (exists $anvil->data->{old}{temperature}{$variable}{$serial_number}) + { + $temperature_uuid = $anvil->data->{old}{temperature}{$variable}{$serial_number}{temperature_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { temperature_uuid => $temperature_uuid }}); + delete $anvil->data->{old}{temperature}{$variable}{$serial_number}; + } + $temperature_uuid = $anvil->Database->insert_or_update_temperature({ + cache => $anvil->data->{'scan-hpacucli'}{queries}, + debug => 2, + temperature_uuid => $temperature_uuid, + temperature_host_uuid => $anvil->Get->host_uuid, + temperature_agent_name => $THIS_FILE, + temperature_sensor_host => $serial_number, + temperature_sensor_name => $variable, + temperature_value_c => $new_temperature_value_c, + temperature_state => $new_temperature_state, + temperature_is => $new_temperature_is, + temperature_weight => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { temperature_uuid => $temperature_uuid }}); + } + } + + # Now, if any undeleted old entries remain, delete them from the database. + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{old}{temperature}}) + { + foreach my $serial_number (sort {$a cmp $b} keys %{$anvil->data->{old}{temperature}{$variable}}) + { + my $temperature_uuid = $anvil->data->{old}{temperature}{$variable}{$serial_number}{temperature_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "variable" => $variable, + "serial_number" => $serial_number, + "temperature_uuid" => $temperature_uuid, + }}); + + # Mark the sensor as DELETEd. + $anvil->Database->insert_or_update_temperature({ + cache => $anvil->data->{'scan-hpacucli'}{queries}, + debug => 2, + 'delete' => 1, + temperature_uuid => $temperature_uuid, + }); + } + } + + # Commit the queries. + $anvil->Database->write({query => $anvil->data->{'scan-hpacucli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-hpacucli'}{queries} = []; + + return(0); +} + +# Process drives (and their arrays and logical drives). +sub process_drives +{ + my ($anvil) = @_; + + # Look for new, changed or deleted controllers. + $anvil->data->{'scan-hpacucli'}{queries} = []; + + # This is to collected data from every sweep. + foreach my $scan_hpacucli_controller_serial_number (sort {$a cmp $b} keys %{$anvil->data->{controller}}) + { + # Controller data; + next if $scan_hpacucli_controller_serial_number eq "metadata"; + my $scan_hpacucli_controller_uuid = $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number, + scan_hpacucli_controller_uuid => $scan_hpacucli_controller_uuid, + }}); + + # Array + foreach my $scan_hpacucli_array_name (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_array_name => $scan_hpacucli_array_name }}); + + # Data, there is no temperature + my $new_scan_hpacucli_array_type = "virtual"; + my $new_scan_hpacucli_array_status = "virtual"; + my $new_scan_hpacucli_array_error_message = ""; + + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{array_type}) + { + $new_scan_hpacucli_array_type = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{array_type}; + } + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{status}) + { + # Array transitions (OK -> Eject -> Plug back in) + #scan-hpacucli 3117; - Data; status: [OK] + #scan-hpacucli 3117; - Data; status: [Failed Physical Drive] + #scan-hpacucli 3148; - Data; status: [OK] + $new_scan_hpacucli_array_status = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{status}; + } + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message}) + { + $new_scan_hpacucli_array_error_message = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message}; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_array_name => $scan_hpacucli_array_name, + new_scan_hpacucli_array_type => $new_scan_hpacucli_array_type, + new_scan_hpacucli_array_status => $new_scan_hpacucli_array_status, + new_scan_hpacucli_array_error_message => $new_scan_hpacucli_array_error_message, + }}); + + # Does this array exist already? + my $scan_hpacucli_array_uuid = $anvil->data->{'scan-hpacucli'}{virtual_drives}{by_name}{$scan_hpacucli_array_name} ? $anvil->data->{'scan-hpacucli'}{virtual_drives}{by_name}{$scan_hpacucli_array_name} : ""; + if (($scan_hpacucli_array_uuid) && (exists $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid})) + { + # Look for changes. + my $old_scan_hpacucli_array_controller_uuid = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_controller_uuid}; + my $old_scan_hpacucli_controller_serial_number = $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$old_scan_hpacucli_array_controller_uuid}; + my $old_scan_hpacucli_array_type = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_type}; + my $old_scan_hpacucli_array_status = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_status}; + my $old_scan_hpacucli_array_error_message = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_error_message}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_scan_hpacucli_array_controller_uuid => $old_scan_hpacucli_array_controller_uuid, + old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number, + old_scan_hpacucli_array_type => $old_scan_hpacucli_array_type, + old_scan_hpacucli_array_status => $old_scan_hpacucli_array_status, + old_scan_hpacucli_array_error_message => $old_scan_hpacucli_array_error_message, + }}); + + # Delete the old one so we know we've seen it. + delete $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}; + + # Has anything changed? Note that we don't check the name as that is how we + # find if it exists already or not. + if (($scan_hpacucli_controller_serial_number ne $old_scan_hpacucli_controller_serial_number) or + ($new_scan_hpacucli_array_type ne $old_scan_hpacucli_array_type) or + ($new_scan_hpacucli_array_status ne $old_scan_hpacucli_array_status) or + ($new_scan_hpacucli_array_error_message ne $old_scan_hpacucli_array_error_message)) + { + ### Something changed. + # If the array is not OK, clear alerts. + if ($new_scan_hpacucli_array_status ne $old_scan_hpacucli_array_status) + { + my $cleared = 0; + my $message_key = "scan_hpacucli_note_0023"; + # Came back or went OK? + if ($old_scan_hpacucli_array_status eq "VANISHED") + { + $message_key = "scan_hpacucli_note_0032"; + } + elsif (lc($new_scan_hpacucli_array_status) eq "ok") + { + $cleared = 1; + $message_key = "scan_hpacucli_note_0024"; + } + my $variables = { + name => $scan_hpacucli_array_name, + serial_number => $scan_hpacucli_controller_serial_number, + new_status => $new_scan_hpacucli_array_status, + old_status => $old_scan_hpacucli_array_status, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => $cleared, + alert_level => "warning", + message => $message_key, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + + # Did the controller change? + if ($scan_hpacucli_controller_serial_number ne $old_scan_hpacucli_controller_serial_number) + { + # yup. This is a notice as the new controller will have + # generated a warning alert. + my $variables = { + name => $scan_hpacucli_array_name, + new_serial_number => $scan_hpacucli_controller_serial_number, + old_serial_number => $old_scan_hpacucli_controller_serial_number, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0025", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "notice", + message => "scan_hpacucli_note_0025", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + + # Has the error message changed? + if ($new_scan_hpacucli_array_error_message ne $old_scan_hpacucli_array_error_message) + { + # Default is 'changed' + my $cleared = 0; + my $message_key = "scan_hpacucli_note_0026"; + if (not $new_scan_hpacucli_array_error_message) + { + # Cleared + $cleared = 0; + $message_key = "scan_hpacucli_note_0027"; + } + elsif (not $old_scan_hpacucli_array_error_message) + { + # New error + $message_key = "scan_hpacucli_note_0028"; + } + my $variables = { + name => $scan_hpacucli_array_name, + new_error_message => $new_scan_hpacucli_array_error_message, + old_error_message => $old_scan_hpacucli_array_error_message, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => $cleared, + alert_level => "warning", + message => $message_key, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + + # Did the controller change? + if ($new_scan_hpacucli_array_type ne $old_scan_hpacucli_array_type) + { + # yup. This is a warning because it should never change. + my $variables = { + name => $scan_hpacucli_array_name, + new_type => $new_scan_hpacucli_array_type, + old_type => $old_scan_hpacucli_array_type, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0030", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0030", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + + # UPDATE + my $query = " +UPDATE + scan_hpacucli_arrays +SET + scan_hpacucli_array_controller_uuid = ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", + scan_hpacucli_array_type = ".$anvil->Database->quote($new_scan_hpacucli_array_type).", + scan_hpacucli_array_status = ".$anvil->Database->quote($new_scan_hpacucli_array_status).", + scan_hpacucli_array_error_message = ".$anvil->Database->quote($new_scan_hpacucli_array_error_message).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_array_uuid = ".$anvil->Database->quote($scan_hpacucli_array_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + else + { + # New. + $scan_hpacucli_array_uuid = $anvil->Get->uuid(); + $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number} = $scan_hpacucli_controller_uuid; + $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid} = $scan_hpacucli_controller_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::controllers::by_serial::${scan_hpacucli_controller_serial_number}" => $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}, + "scan-hpacucli::controllers::by_uuid::${scan_hpacucli_controller_uuid}" => $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid}, + }}); + + print $THIS_FILE." ".__LINE__."; - New Array: [$scan_hpacucli_array_name] (UUID: [$scan_hpacucli_array_uuid]); Type: [$new_scan_hpacucli_array_type], status: [$new_scan_hpacucli_array_status], error message: [$new_scan_hpacucli_array_error_message]\n"; + + # Alert the user if this isn't the virtual array. + if ($scan_hpacucli_array_name ne "ZZZZ") + { + # If the array is OK, it will be a notice. + my $alert_level = "notice"; + my $message_key = "scan_hpacucli_note_0021"; + if (lc($new_scan_hpacucli_array_status) ne "ok") + { + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0022"; + } + my $variables = { + name => $scan_hpacucli_array_name, + type => $new_scan_hpacucli_array_type, + status => $new_scan_hpacucli_array_status, + error => $new_scan_hpacucli_array_error_message, + }; + my $log_level = $alert_level eq "warning" ? 1 : 2; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => $alert_level, + message => $message_key, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + + my $query = " +INSERT INTO + scan_hpacucli_arrays +( + scan_hpacucli_array_uuid, + scan_hpacucli_array_host_uuid, + scan_hpacucli_array_controller_uuid, + scan_hpacucli_array_name, + scan_hpacucli_array_type, + scan_hpacucli_array_status, + scan_hpacucli_array_error_message, + modified_date +) VALUES ( + ".$anvil->Database->quote($scan_hpacucli_array_uuid).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", + ".$anvil->Database->quote($scan_hpacucli_array_name).", + ".$anvil->Database->quote($new_scan_hpacucli_array_type).", + ".$anvil->Database->quote($new_scan_hpacucli_array_status).", + ".$anvil->Database->quote($new_scan_hpacucli_array_error_message).", + ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +);"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + + # Logical Drive + foreach my $scan_hpacucli_logical_drive_name (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}}) + { + # No thermal data + my $scan_hpacucli_logical_drive_uuid = $anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name} ? $anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name} : ""; + my $new_scan_hpacucli_logical_drive_caching = ""; + my $new_scan_hpacucli_logical_drive_os_device_name = ""; + my $new_scan_hpacucli_logical_drive_type = ""; + my $new_scan_hpacucli_logical_drive_raid_level = ""; + my $new_scan_hpacucli_logical_drive_size = ""; + my $new_scan_hpacucli_logical_drive_strip_size = ""; + my $new_scan_hpacucli_logical_drive_stripe_size = ""; + my $new_scan_hpacucli_logical_drive_status = ""; + + # If this is the virtual array, set the sizes to 0. + if ($scan_hpacucli_logical_drive_name eq "9999") + { + $new_scan_hpacucli_logical_drive_size = 0; + $new_scan_hpacucli_logical_drive_strip_size = 0; + $new_scan_hpacucli_logical_drive_stripe_size = 0; + } + + ### Gather the variables. + # Caching + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{caching}) + { + $new_scan_hpacucli_logical_drive_caching = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{caching}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_logical_drive_caching => $new_scan_hpacucli_logical_drive_caching }}); + } + # Disk name (in the OS) + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{disk_name}) + { + $new_scan_hpacucli_logical_drive_os_device_name = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{disk_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_logical_drive_os_device_name => $new_scan_hpacucli_logical_drive_os_device_name }}); + } + # Drive type + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{drive_type}) + { + $new_scan_hpacucli_logical_drive_type = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{drive_type}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_logical_drive_type => $new_scan_hpacucli_logical_drive_type }}); + } + # RAID level + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{fault_tolerance}) + { + $new_scan_hpacucli_logical_drive_raid_level = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{fault_tolerance}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_logical_drive_raid_level => $new_scan_hpacucli_logical_drive_raid_level }}); + } + # Drive size - Needs to be converted to bytes at initial processing. + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{size}) + { + $new_scan_hpacucli_logical_drive_size = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{size}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_scan_hpacucli_logical_drive_size" => $new_scan_hpacucli_logical_drive_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_size}).")", + }}); + } + # Strip size + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{strip_size}) + { + $new_scan_hpacucli_logical_drive_strip_size = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{strip_size}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_scan_hpacucli_logical_drive_strip_size" => $new_scan_hpacucli_logical_drive_strip_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_strip_size}).")", + }}); + } + # Stripe size + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{full_stripe_size}) + { + $new_scan_hpacucli_logical_drive_stripe_size = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{full_stripe_size}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_scan_hpacucli_logical_drive_stripe_size" => $new_scan_hpacucli_logical_drive_stripe_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_stripe_size}).")", + }}); + } + # Status + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{status}) + { + $new_scan_hpacucli_logical_drive_status = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{status}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_logical_drive_status => $new_scan_hpacucli_logical_drive_status }}); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_scan_hpacucli_logical_drive_caching => $new_scan_hpacucli_logical_drive_caching, + new_scan_hpacucli_logical_drive_os_device_name => $new_scan_hpacucli_logical_drive_os_device_name, + new_scan_hpacucli_logical_drive_type => $new_scan_hpacucli_logical_drive_type, + new_scan_hpacucli_logical_drive_raid_level => $new_scan_hpacucli_logical_drive_raid_level, + new_scan_hpacucli_logical_drive_size => $new_scan_hpacucli_logical_drive_size, + new_scan_hpacucli_logical_drive_strip_size => $new_scan_hpacucli_logical_drive_strip_size, + new_scan_hpacucli_logical_drive_stripe_size => $new_scan_hpacucli_logical_drive_stripe_size, + new_scan_hpacucli_logical_drive_status => $new_scan_hpacucli_logical_drive_status, + }}); + + if (($scan_hpacucli_logical_drive_uuid) && (exists $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid})) + { + my $old_scan_hpacucli_logical_drive_array_uuid = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_array_uuid}; + my $old_scan_hpacucli_logical_drive_name = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_name}; + my $old_scan_hpacucli_logical_drive_caching = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_caching}; + my $old_scan_hpacucli_logical_drive_os_device_name = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_os_device_name}; + my $old_scan_hpacucli_logical_drive_type = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_type}; + my $old_scan_hpacucli_logical_drive_raid_level = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_raid_level}; + my $old_scan_hpacucli_logical_drive_size = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_size}; + my $old_scan_hpacucli_logical_drive_strip_size = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_strip_size}; + my $old_scan_hpacucli_logical_drive_stripe_size = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_stripe_size}; + my $old_scan_hpacucli_logical_drive_status = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_status}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_logical_drive_uuid => $scan_hpacucli_logical_drive_uuid, + old_scan_hpacucli_logical_drive_array_uuid => $old_scan_hpacucli_logical_drive_array_uuid, + old_scan_hpacucli_logical_drive_name => $old_scan_hpacucli_logical_drive_name, + old_scan_hpacucli_logical_drive_caching => $old_scan_hpacucli_logical_drive_caching, + old_scan_hpacucli_logical_drive_os_device_name => $old_scan_hpacucli_logical_drive_os_device_name, + old_scan_hpacucli_logical_drive_type => $old_scan_hpacucli_logical_drive_type, + old_scan_hpacucli_logical_drive_raid_level => $old_scan_hpacucli_logical_drive_raid_level, + old_scan_hpacucli_logical_drive_size => $old_scan_hpacucli_logical_drive_size, + old_scan_hpacucli_logical_drive_strip_size => $old_scan_hpacucli_logical_drive_strip_size, + old_scan_hpacucli_logical_drive_stripe_size => $old_scan_hpacucli_logical_drive_stripe_size, + old_scan_hpacucli_logical_drive_status => $old_scan_hpacucli_logical_drive_status, + }}); + + # Delete this so we know it was processed + delete $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}; + + my $update = 0; + my $recovered = ""; + if ($new_scan_hpacucli_logical_drive_caching ne $old_scan_hpacucli_logical_drive_caching) + { + # Did it go enabled or disabled? + $update = 1; + my $cleared = 0; + my $message_key = "scan_hpacucli_note_0034"; + if (lc($new_scan_hpacucli_logical_drive_caching) eq "enabled") + { + # We're back. + $cleared = 1; + $message_key = "scan_hpacucli_note_0035"; + } + if (lc($new_scan_hpacucli_logical_drive_caching) eq "disabled") + { + # Warn the user about a possible performance hit. + $message_key = "scan_hpacucli_note_0036"; + } + + # Send an alert telling the user that we've found a new controller. + my $variables = { + logical_drive => $scan_hpacucli_logical_drive_name, + array => $scan_hpacucli_array_name, + serial_number => $scan_hpacucli_controller_serial_number, + new_value => $new_scan_hpacucli_logical_drive_caching, + old_value => $old_scan_hpacucli_logical_drive_caching, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => $cleared, + alert_level => "warning", + message => $message_key, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + elsif ($new_scan_hpacucli_logical_drive_status ne $old_scan_hpacucli_logical_drive_status) + { + # NOTE: Auto-restored a drive that was re-inserted + # Example messages; "Interim Recovery Mode" + # "Recovering, 0% complete" + # LD transitions (OK -> Eject -> Plug back in) + $update = 1; + my $cleared = 0; + my $alert_level = "warning"; + my $message_key = "scan_hpacucli_note_0037"; + if ($old_scan_hpacucli_logical_drive_status eq "VANISHED") + { + # It's back + $cleared = 1; + $message_key = "scan_hpacucli_note_0045"; + } + elsif (lc($new_scan_hpacucli_logical_drive_status) eq "ok") + { + # Back to healthy. + $cleared = 1; + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0038"; + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_logical_drive_uuid.":rebuilding_logical_drive:".$scan_hpacucli_logical_drive_name, set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + } + elsif ($new_scan_hpacucli_logical_drive_status =~ /Recovering, (.*?)% complete/i) + { + # We'll set an alert so that one alert goes out when + # the rebuild starts. + $recovered = $1; + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_logical_drive_uuid.":rebuilding_logical_drive:".$scan_hpacucli_logical_drive_name, set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + recovered => $recovered, + changed => $changed, + }}); + if ($changed) + { + # Let the user know the rebuild has started. + $message_key = "scan_hpacucli_note_0039"; + } + else + { + # Still under way + $alert_level = "notice"; + $message_key = "scan_hpacucli_note_0040"; + } + } + elsif (lc($new_scan_hpacucli_logical_drive_status) eq "interim recovery mode") + { + # Drive just failed. + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0041"; + } + + # Send the alert + my $variables = { + logical_drive => $scan_hpacucli_logical_drive_name, + array => $scan_hpacucli_array_name, + serial_number => $scan_hpacucli_controller_serial_number, + new_value => $new_scan_hpacucli_logical_drive_status, + old_value => $old_scan_hpacucli_logical_drive_status, + recovered => $recovered, + }; + my $log_level = (($alert_level eq "warning") or ($alert_level eq "critical")) ? 1 : 2; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => $cleared, + alert_level => $alert_level, + message => $message_key, + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + elsif (($new_scan_hpacucli_logical_drive_os_device_name ne $old_scan_hpacucli_logical_drive_os_device_name) or + ($new_scan_hpacucli_logical_drive_type ne $old_scan_hpacucli_logical_drive_type) or + ($new_scan_hpacucli_logical_drive_raid_level ne $old_scan_hpacucli_logical_drive_raid_level) or + ($new_scan_hpacucli_logical_drive_size ne $old_scan_hpacucli_logical_drive_size) or + ($new_scan_hpacucli_logical_drive_strip_size ne $old_scan_hpacucli_logical_drive_strip_size) or + ($new_scan_hpacucli_logical_drive_stripe_size ne $old_scan_hpacucli_logical_drive_stripe_size)) + { + # Something else changed. This should normally never happen. + $update = 1; + my $variables = { + logical_drive => $scan_hpacucli_logical_drive_name, + array => $scan_hpacucli_array_name, + serial_number => $scan_hpacucli_controller_serial_number, + new_os_drive_name => $new_scan_hpacucli_logical_drive_os_device_name, + old_os_drive_name => $old_scan_hpacucli_logical_drive_os_device_name, + new_type => $new_scan_hpacucli_logical_drive_type, + old_type => $old_scan_hpacucli_logical_drive_type, + new_raid_level => $new_scan_hpacucli_logical_drive_raid_level, + old_raid_level => $old_scan_hpacucli_logical_drive_raid_level, + new_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_size}), + old_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hpacucli_logical_drive_size}), + new_strip_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_strip_size}), + old_strip_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hpacucli_logical_drive_strip_size}), + new_stripe_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_stripe_size}), + old_stripe_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hpacucli_logical_drive_stripe_size}), + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0042", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0042", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + + # If something changed, UPDATE. + if ($update) + { + # Quote the numbers. + my $quoted_scan_hpacucli_logical_drive_size = $anvil->Database->quote($new_scan_hpacucli_logical_drive_size); + my $quoted_scan_hpacucli_logical_drive_strip_size = $anvil->Database->quote($new_scan_hpacucli_logical_drive_strip_size); + my $quoted_scan_hpacucli_logical_drive_stripe_size = $anvil->Database->quote($new_scan_hpacucli_logical_drive_stripe_size); + $quoted_scan_hpacucli_logical_drive_size =~ s/^'(.*?)'$/$1/; + $quoted_scan_hpacucli_logical_drive_strip_size =~ s/^'(.*?)'$/$1/; + $quoted_scan_hpacucli_logical_drive_stripe_size =~ s/^'(.*?)'$/$1/; + + # Do the update + my $query = " +UPDATE + scan_hpacucli_logical_drives +SET + scan_hpacucli_logical_drive_array_uuid = ".$anvil->Database->quote($scan_hpacucli_array_uuid).", + scan_hpacucli_logical_drive_name = ".$anvil->Database->quote($scan_hpacucli_logical_drive_name).", + scan_hpacucli_logical_drive_caching = ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_caching).", + scan_hpacucli_logical_drive_os_device_name = ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_os_device_name).", + scan_hpacucli_logical_drive_type = ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_type).", + scan_hpacucli_logical_drive_raid_level = ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_raid_level).", + scan_hpacucli_logical_drive_size = $quoted_scan_hpacucli_logical_drive_size, + scan_hpacucli_logical_drive_strip_size = $quoted_scan_hpacucli_logical_drive_strip_size, + scan_hpacucli_logical_drive_stripe_size = $quoted_scan_hpacucli_logical_drive_stripe_size, + scan_hpacucli_logical_drive_status = ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_status).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_logical_drive_uuid = ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + else + { + # New, INSERT. + $scan_hpacucli_logical_drive_uuid = $anvil->Get->uuid(); + $anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name} = $scan_hpacucli_logical_drive_uuid; + $anvil->data->{'scan-hpacucli'}{logical_drives}{by_uuid}{$scan_hpacucli_logical_drive_uuid} = $scan_hpacucli_logical_drive_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::logical_drives::by_name::${scan_hpacucli_logical_drive_name}" => $anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name}, + "scan-hpacucli::logical_drives::by_uuid::${scan_hpacucli_logical_drive_uuid}" => $anvil->data->{'scan-hpacucli'}{logical_drives}{by_uuid}{$scan_hpacucli_logical_drive_uuid}, + }}); + + # Send an alert telling the user that we've found a new controller. + my $variables = { + name => $scan_hpacucli_array_name, + logical_drive => $scan_hpacucli_logical_drive_name, + new_caching => $new_scan_hpacucli_logical_drive_caching, + new_os_device_name => $new_scan_hpacucli_logical_drive_os_device_name, + new_type => $new_scan_hpacucli_logical_drive_type, + new_raid_level => $new_scan_hpacucli_logical_drive_raid_level, + new_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_size}), + new_strip_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_strip_size}), + new_stripe_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_stripe_size}), + new_status => $new_scan_hpacucli_logical_drive_status, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0033", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "notice", + message => "scan_hpacucli_note_0033", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + ### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0003", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "notice", + message => "scan_hpacucli_note_0003", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # Quote some stuff manually + my $quoted_scan_hpacucli_logical_drive_size = $anvil->Database->quote($new_scan_hpacucli_logical_drive_size); + my $quoted_scan_hpacucli_logical_drive_strip_size = $anvil->Database->quote($new_scan_hpacucli_logical_drive_strip_size); + my $quoted_scan_hpacucli_logical_drive_stripe_size = $anvil->Database->quote($new_scan_hpacucli_logical_drive_stripe_size); + $quoted_scan_hpacucli_logical_drive_size =~ s/^'(.*?)'$/$1/; + $quoted_scan_hpacucli_logical_drive_strip_size =~ s/^'(.*?)'$/$1/; + $quoted_scan_hpacucli_logical_drive_stripe_size =~ s/^'(.*?)'$/$1/; + + # Now INERT variables. + my $query = " +INSERT INTO + scan_hpacucli_logical_drives +( + scan_hpacucli_logical_drive_uuid, + scan_hpacucli_logical_drive_host_uuid, + scan_hpacucli_logical_drive_array_uuid, + scan_hpacucli_logical_drive_name, + scan_hpacucli_logical_drive_caching, + scan_hpacucli_logical_drive_os_device_name, + scan_hpacucli_logical_drive_type, + scan_hpacucli_logical_drive_raid_level, + scan_hpacucli_logical_drive_size, + scan_hpacucli_logical_drive_strip_size, + scan_hpacucli_logical_drive_stripe_size, + scan_hpacucli_logical_drive_status, + modified_date +) VALUES ( + ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($scan_hpacucli_array_uuid).", + ".$anvil->Database->quote($scan_hpacucli_logical_drive_name).", + ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_caching).", + ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_os_device_name).", + ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_type).", + ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_raid_level).", + $quoted_scan_hpacucli_logical_drive_size, + $quoted_scan_hpacucli_logical_drive_strip_size, + $quoted_scan_hpacucli_logical_drive_stripe_size, + ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_status).", + ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +);"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + + # Process logical drive variables now. Note that there are no temperatures. + foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}}) + { + # Insert the variables. + my $new_scan_hpacucli_variable_value = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{$scan_hpacucli_variable_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_variable_name => $scan_hpacucli_variable_name, + new_scan_hpacucli_variable_value => $new_scan_hpacucli_variable_value, + }}); + + # Have we seen this variable before? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::scan_hpacucli_logical_drives::source_uuid::${scan_hpacucli_logical_drive_uuid}::detail::${scan_hpacucli_variable_name}::scan_hpacucli_variable_uuid" => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_logical_drives}{source_uuid}{$scan_hpacucli_logical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}, + }}); + if ($anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_logical_drives}{source_uuid}{$scan_hpacucli_logical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}) + { + # Exists. Has it changed? + my $scan_hpacucli_variable_uuid = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_logical_drives}{source_uuid}{$scan_hpacucli_logical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}; + my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_logical_drives}{source_uuid}{$scan_hpacucli_logical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_variable_uuid => $scan_hpacucli_variable_uuid, + old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, + }}); + + # delete this so that we know it was processed. + delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_logical_drives}{source_uuid}{$scan_hpacucli_logical_drive_uuid}{detail}{$scan_hpacucli_variable_name}; + + if ($old_scan_hpacucli_variable_value ne $new_scan_hpacucli_variable_value) + { + # Now update. Alert the user as a warning, this + # should rarely ever change. + my $variables = { + logical_drive => $scan_hpacucli_logical_drive_name, + array => $scan_hpacucli_array_name, + serial_number => $scan_hpacucli_controller_serial_number, + variable_name => $scan_hpacucli_variable_name, + old_value => $old_scan_hpacucli_variable_value ? $old_scan_hpacucli_variable_value : "--", + new_value => $new_scan_hpacucli_variable_value ? $new_scan_hpacucli_variable_value : "--", + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0066", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0066", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # UPDATE + my $query = " +UPDATE + scan_hpacucli_variables +SET + scan_hpacucli_variable_value = ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_variable_uuid = ".$anvil->Database->quote($scan_hpacucli_variable_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + else + { + # New. Alert the user. + my $variables = { + name => $scan_hpacucli_variable_name, + value => $new_scan_hpacucli_variable_value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0004", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "notice", + message => "scan_hpacucli_note_0004", + variables => $variables, + show_header => 0, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_hpacucli_variables +( + scan_hpacucli_variable_uuid, + scan_hpacucli_variable_host_uuid, + scan_hpacucli_variable_source_table, + scan_hpacucli_variable_source_uuid, + scan_hpacucli_variable_is_temperature, + scan_hpacucli_variable_name, + scan_hpacucli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_hpacucli_logical_drives', + ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid).", + FALSE, + ".$anvil->Database->quote($scan_hpacucli_variable_name).", + ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", + ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +);"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + + # Physical Disks. + foreach my $port (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}}) + { + foreach my $box (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}}) + { + foreach my $bay (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}}) + { + # Throw this into a function to get out of + # indent-hell. + process_a_drive($anvil, $scan_hpacucli_controller_serial_number, $scan_hpacucli_logical_drive_uuid, $scan_hpacucli_array_name, $scan_hpacucli_logical_drive_name, $port, $box, $bay); + } + } + } + } + } + + # Look for deleted arrays. + foreach my $scan_hpacucli_array_uuid (keys %{$anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}}) + { + my $old_scan_hpacucli_array_name = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_name}; + my $old_scan_hpacucli_array_controller_uuid = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_controller_uuid}; + my $old_scan_hpacucli_controller_serial_number = $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$old_scan_hpacucli_array_controller_uuid}; + my $old_scan_hpacucli_array_status = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_status}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_scan_hpacucli_array_name => $old_scan_hpacucli_array_name, + old_scan_hpacucli_array_controller_uuid => $old_scan_hpacucli_array_controller_uuid, + old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number, + old_scan_hpacucli_array_status => $old_scan_hpacucli_array_status, + }}); + + next if $old_scan_hpacucli_array_name eq "ZZZZ"; + next if $old_scan_hpacucli_array_status eq "VANISHED"; + + my $variables = { + name => $old_scan_hpacucli_array_name, + serial_number => $old_scan_hpacucli_controller_serial_number, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0031", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0031", + variables => $variables, + show_header => 0, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_hpacucli_arrays +SET + scan_hpacucli_array_status = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_array_uuid = ".$anvil->Database->quote($scan_hpacucli_array_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + + # Look for deleted logical drives. + foreach my $scan_hpacucli_logical_drive_uuid (keys %{$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}}) + { + # Look for changes + my $old_scan_hpacucli_logical_drive_array_uuid = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_array_uuid}; + my $old_scan_hpacucli_logical_drive_name = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_name}; + my $old_scan_hpacucli_logical_drive_status = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_status}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_logical_drive_uuid => $scan_hpacucli_logical_drive_uuid, + old_scan_hpacucli_logical_drive_array_uuid => $old_scan_hpacucli_logical_drive_array_uuid, + old_scan_hpacucli_logical_drive_name => $old_scan_hpacucli_logical_drive_name, + old_scan_hpacucli_logical_drive_status => $old_scan_hpacucli_logical_drive_status, + }}); + + next if $old_scan_hpacucli_logical_drive_name eq "9999"; + next if $old_scan_hpacucli_logical_drive_status eq "VANISHED"; + + my $variables = { + logical_drive => $old_scan_hpacucli_logical_drive_name, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0044", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0044", + variables => $variables, + show_header => 0, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_hpacucli_logical_drives +SET + scan_hpacucli_logical_drive_status = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_logical_drive_uuid = ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + + # Now commit the changes. + $anvil->Database->write({query => $anvil->data->{'scan-hpacucli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-hpacucli'}{queries} = []; + + return(0); +} + +# Process a specific drive +sub process_a_drive +{ + my ($anvil, $scan_hpacucli_controller_serial_number, $scan_hpacucli_logical_drive_uuid, $scan_hpacucli_array_name, $scan_hpacucli_logical_drive_name, $port, $box, $bay) = @_; + + my $scan_hpacucli_physical_drive_uuid = ""; + my $scan_hpacucli_physical_drive_serial_number = ""; + my $new_scan_hpacucli_physical_drive_model = ""; + my $new_scan_hpacucli_physical_drive_interface = ""; + my $new_scan_hpacucli_physical_drive_status = ""; + my $new_scan_hpacucli_physical_drive_size = 0; + my $new_scan_hpacucli_physical_drive_type = ""; + my $new_scan_hpacucli_physical_drive_rpm = 0; + my $new_scan_hpacucli_physical_drive_temperature = ""; + my $new_scan_hpacucli_physical_drive_last_failure_reason = ""; + my $maximum_drive_temperature = 0; + + # Serial Number + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{serial_number}) + { + $scan_hpacucli_physical_drive_serial_number = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_physical_drive_serial_number => $scan_hpacucli_physical_drive_serial_number }}); + } + # Model + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{model}) + { + $new_scan_hpacucli_physical_drive_model = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{model}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_model => $new_scan_hpacucli_physical_drive_model }}); + } + # Interface + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{interface_type}) + { + $new_scan_hpacucli_physical_drive_interface = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{interface_type}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_interface => $new_scan_hpacucli_physical_drive_interface }}); + } + # Status + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{status}) + { + $new_scan_hpacucli_physical_drive_status = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{status}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_status => $new_scan_hpacucli_physical_drive_status }}); + } + # Size + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{size}) + { + $new_scan_hpacucli_physical_drive_size = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{size}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_scan_hpacucli_physical_drive_size" => $new_scan_hpacucli_physical_drive_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_physical_drive_size}).")", + }}); + } + # Type + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{drive_type}) + { + $new_scan_hpacucli_physical_drive_type = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{drive_type}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_type => $new_scan_hpacucli_physical_drive_type }}); + } + # RPM (0 if SSD) + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{rotational_speed}) + { + $new_scan_hpacucli_physical_drive_rpm = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{rotational_speed}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_rpm => $new_scan_hpacucli_physical_drive_rpm }}); + } + # Temperature + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{temperature}{current_temperature}) + { + $new_scan_hpacucli_physical_drive_temperature = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{temperature}{current_temperature}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_temperature => $new_scan_hpacucli_physical_drive_temperature }}); + } + # Last failure reason + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{last_failure_reason}) + { + $new_scan_hpacucli_physical_drive_last_failure_reason = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{last_failure_reason}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_last_failure_reason => $new_scan_hpacucli_physical_drive_last_failure_reason }}); + } + # Maximum temperature + if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{temperature}{maximum_temperature}) + { + $maximum_drive_temperature = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{temperature}{maximum_temperature}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { maximum_drive_temperature => $maximum_drive_temperature }}); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_physical_drive_serial_number => $scan_hpacucli_physical_drive_serial_number, + new_scan_hpacucli_physical_drive_model => $new_scan_hpacucli_physical_drive_model, + new_scan_hpacucli_physical_drive_interface => $new_scan_hpacucli_physical_drive_interface, + new_scan_hpacucli_physical_drive_status => $new_scan_hpacucli_physical_drive_status, + new_scan_hpacucli_physical_drive_size => $new_scan_hpacucli_physical_drive_size, + new_scan_hpacucli_physical_drive_type => $new_scan_hpacucli_physical_drive_type, + new_scan_hpacucli_physical_drive_rpm => $new_scan_hpacucli_physical_drive_rpm, + new_scan_hpacucli_physical_drive_temperature => $new_scan_hpacucli_physical_drive_temperature, + new_scan_hpacucli_physical_drive_last_failure_reason => $new_scan_hpacucli_physical_drive_last_failure_reason, + maximum_drive_temperature => $maximum_drive_temperature, + }}); + + # Delete the Port, Box and Bay values so that they don't get processed as their own variables. + delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{port}; + delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{box}; + delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{bay}; + + # Die if we don't have a serial number + if (not $scan_hpacucli_physical_drive_serial_number) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_hpacucli_error_0011", variables => { + serial_number => $scan_hpacucli_controller_serial_number, + array_name => $scan_hpacucli_array_name, + logical_drive_name => $scan_hpacucli_logical_drive_name, + port => $port, + box => $box, + bay => $bay, + }}); + $anvil->nice_exit({exit_code => 9}); + } + + # Have we seen this drive before? + if ($anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number}) + { + # Yup! Look for changes. + $scan_hpacucli_physical_drive_uuid = $anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_physical_drive_uuid => $scan_hpacucli_physical_drive_uuid }}); + + # Gather the old data. + my $old_scan_hpacucli_logical_drive_uuid = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_logical_drive_uuid}; + my $old_scan_hpacucli_physical_drive_model = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_model}; + my $old_scan_hpacucli_physical_drive_interface = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_interface}; + my $old_scan_hpacucli_physical_drive_status = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_status}; + my $old_scan_hpacucli_physical_drive_size = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_size}; + my $old_scan_hpacucli_physical_drive_type = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_type}; + my $old_scan_hpacucli_physical_drive_rpm = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_rpm}; + my $old_scan_hpacucli_physical_drive_temperature = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_temperature}; + my $old_scan_hpacucli_physical_drive_last_failure_reason = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_last_failure_reason}; + my $old_scan_hpacucli_physical_drive_port = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_port}; + my $old_scan_hpacucli_physical_drive_box = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_box}; + my $old_scan_hpacucli_physical_drive_bay = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_bay}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_scan_hpacucli_logical_drive_uuid => $old_scan_hpacucli_logical_drive_uuid, + old_scan_hpacucli_physical_drive_model => $old_scan_hpacucli_physical_drive_model, + old_scan_hpacucli_physical_drive_interface => $old_scan_hpacucli_physical_drive_interface, + old_scan_hpacucli_physical_drive_status => $old_scan_hpacucli_physical_drive_status, + old_scan_hpacucli_physical_drive_size => $old_scan_hpacucli_physical_drive_size, + old_scan_hpacucli_physical_drive_type => $old_scan_hpacucli_physical_drive_type, + old_scan_hpacucli_physical_drive_rpm => $old_scan_hpacucli_physical_drive_rpm, + old_scan_hpacucli_physical_drive_temperature => $old_scan_hpacucli_physical_drive_temperature, + old_scan_hpacucli_physical_drive_last_failure_reason => $old_scan_hpacucli_physical_drive_last_failure_reason, + old_scan_hpacucli_physical_drive_port => $old_scan_hpacucli_physical_drive_port, + old_scan_hpacucli_physical_drive_box => $old_scan_hpacucli_physical_drive_box, + old_scan_hpacucli_physical_drive_bay => $old_scan_hpacucli_physical_drive_bay, + }}); + + # delete this so that we know it was processed. + delete $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}; + + my $update = 0; + # Did the drive move between logical drives? + if ($scan_hpacucli_logical_drive_uuid ne $old_scan_hpacucli_logical_drive_uuid) + { + $update = 1; + + # We'll need to get the host, controller serial number and array name + my $query = " +SELECT + a.host_name, + b.scan_hpacucli_controller_serial_number, + c.scan_hpacucli_array_name, + d.scan_hpacucli_logical_drive_name +FROM + hosts a, + scan_hpacucli_controllers b, + scan_hpacucli_arrays c, + scan_hpacucli_logical_drives d +WHERE + a.host_uuid = b.scan_hpacucli_controller_host_uuid +AND + b.scan_hpacucli_controller_uuid = c.scan_hpacucli_array_controller_uuid +AND + c.scan_hpacucli_array_uuid = d.scan_hpacucli_logical_drive_array_uuid +AND + c.scan_hpacucli_array_uuid = ".$anvil->Database->quote($old_scan_hpacucli_logical_drive_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, + }}); + my $old_host_name = $results->[0]->[0] ? $results->[0]->[0] : "--"; + my $old_scan_hpacucli_controller_serial_number = $results->[0]->[1] ? $results->[0]->[1] : "--"; + my $old_scan_hpacucli_array_name = $results->[0]->[2] ? $results->[0]->[2] : "--"; + my $old_scan_hpacucli_logical_drive_name = $results->[0]->[3] ? $results->[0]->[3] : "--"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_host_name => $old_host_name, + old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number, + old_scan_hpacucli_array_name => $old_scan_hpacucli_array_name, + old_scan_hpacucli_logical_drive_name => $old_scan_hpacucli_logical_drive_name, + }}); + + # Send an alert telling the drive has moved. + my $variables = { + drive_serial_number => $scan_hpacucli_physical_drive_serial_number, + old_host_name => $old_host_name, + new_host_name => $anvil->Get->host_name, + new_controller_serial_number => $scan_hpacucli_controller_serial_number, + old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number, + new_array_name => $scan_hpacucli_array_name, + old_array_name => $scan_hpacucli_array_name, + new_logical_drive_name => $scan_hpacucli_logical_drive_name, + old_logical_drive_name => $old_scan_hpacucli_logical_drive_name + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0047", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0047", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + + # Has the status changed? + if ($old_scan_hpacucli_physical_drive_status ne $new_scan_hpacucli_physical_drive_status) + { + $update = 1; + + # Yup. Start with an alert about it being not OK, and change if it is now OK. + my $cleared = 0; + my $message_key = "scan_hpacucli_note_0048"; + + # Did it return? + if ($old_scan_hpacucli_physical_drive_status eq "VANISHED") + { + # The drive is back. + $message_key = "scan_hpacucli_note_0050"; + } + elsif (lc($new_scan_hpacucli_physical_drive_status) eq "ok") + { + # Drive is OK again. + $cleared = 1; + $message_key = "scan_hpacucli_note_0051"; + } + my $variables = { + serial_number => $scan_hpacucli_physical_drive_serial_number, + old_status => $old_scan_hpacucli_physical_drive_status, + new_status => $new_scan_hpacucli_physical_drive_status, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => $cleared, + alert_level => "warning", + message => $message_key, + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + + # Did the temperature change? Whether it did or not, we need to record the current + # temperature state. + ### NOTE: HP tells us the maximum temperature each of its drives can handle. This is + ### a low number, so we need to tighten up some thresholds compared to usual + ### ranges. + # Set defaults + my $high_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{high_critical}; + my $high_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{high_warning}; + my $low_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{low_warning}; + my $low_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{low_critical}; + my $jump = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{jump}; + my $buffer = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{buffer}; + my $clear_high_critical = $high_critical - $buffer; + my $clear_high_warning = $high_warning - $buffer; + my $clear_low_critical = $low_critical - $buffer; + my $clear_low_warning = $low_warning - $buffer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + high_critical => $high_critical, + high_warning => $high_warning, + low_warning => $low_warning, + low_critical => $low_critical, + jump => $jump, + buffer => $buffer, + clear_high_critical => $clear_high_critical, + clear_high_warning => $clear_high_warning, + clear_low_critical => $clear_low_critical, + clear_low_warning => $clear_low_warning, + }}); + + # Fine-tune the alert thresholds + if ($clear_high_critical < $high_warning) + { + $clear_high_critical = $high_warning + 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }}); + } + if ($clear_low_critical > $low_warning) + { + $clear_low_critical = $low_warning - 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }}); + } + + # Did we get a maximum temperature from the drive? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + maximum_drive_temperature => $maximum_drive_temperature, + "scan-hpacucli::ignore_maximum_temperature" => $anvil->data->{'scan-hpacucli'}{ignore_maximum_temperature}, + }}); + if (($maximum_drive_temperature) && (not $anvil->data->{'scan-hpacucli'}{ignore_maximum_temperature})) + { + $high_critical = $maximum_drive_temperature; + $high_warning = $maximum_drive_temperature - 2; + $clear_high_critical = $high_critical - $buffer; + $clear_high_warning = $high_warning - $buffer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + high_critical => $high_critical, + high_warning => $high_warning, + clear_high_critical => $clear_high_critical, + clear_high_warning => $clear_high_warning, + }}); + + # Fine-tune the alert thresholds + if ($clear_high_critical < $high_warning) + { + $clear_high_critical = $high_warning + 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }}); + } + if ($clear_low_critical > $low_warning) + { + $clear_low_critical = $low_warning - 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }}); + } + } + + # Clear alerts, if needed. The order is important as clearing a warning will replace + # clearing a critical when a sensor goes critical -> ok in one scan. Once done, we'll + # check if we've crossed into a warning or critical state. If so, those will replace + # any cleared messages. + my $cleared = 0; + my $alert_level = "info"; + my $message_key = "scan_hpacucli_note_0053"; + my $delta = 0; + if ($new_scan_hpacucli_physical_drive_temperature) + { + if ($new_scan_hpacucli_physical_drive_temperature < $clear_high_critical) + { + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $cleared = 1; + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0054"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + if ($new_scan_hpacucli_physical_drive_temperature < $clear_high_warning) + { + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # The temperature is no longer + # warning, and it didn't just go + # critical + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0055"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + if ($new_scan_hpacucli_physical_drive_temperature > $clear_low_critical) + { + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $cleared = 1; + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0056"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + if ($new_scan_hpacucli_physical_drive_temperature > $clear_low_warning) + { + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0057"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + + # Now see if the temperature has crossed into a warning or critical state. + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + if ($new_scan_hpacucli_physical_drive_temperature > $high_critical) + { + # Crossed the high critical threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0060"; + } + $temperature_state = "critical"; + $temperature_is = "high"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_physical_drive_temperature > $high_warning) + { + # Crossed the high warning threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0061"; + } + $temperature_state = "warning"; + $temperature_is = "high"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_physical_drive_temperature < $low_critical) + { + # Dropped below the low critical threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0062"; + } + $temperature_state = "critical"; + $temperature_is = "low"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "temperature_state" => $temperature_state, + "temperature_is" => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_physical_drive_temperature < $low_warning) + { + # Crossed the low warning threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0063"; + } + $temperature_state = "warning"; + $temperature_is = "low"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + else + { + # Did it change enough to trigger a jump alert? + if ($new_scan_hpacucli_physical_drive_temperature > $old_scan_hpacucli_physical_drive_temperature) + { + # Jumped + $delta = $new_scan_hpacucli_physical_drive_temperature - $old_scan_hpacucli_physical_drive_temperature; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { delta => $delta }}); + if ($delta >= $jump) + { + # Big jump. + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0058"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + else + { + # Dropped + $delta = $old_scan_hpacucli_physical_drive_temperature - $new_scan_hpacucli_physical_drive_temperature; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { delta => $delta }}); + if ($delta >= $jump) + { + # Big drop. + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0059"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + } + + # Record this for later processing into the 'temperature' table. + my $sensor_host_key = "physical_drive:".$scan_hpacucli_physical_drive_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_host_key => $sensor_host_key }}); + + $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_value_c} = $new_scan_hpacucli_physical_drive_temperature; + $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_state} = $temperature_state; + $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_is} = $temperature_is; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_value_c" => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_value_c}, + "new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_state" => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_state}, + "new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_is" => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_is}, + }}); + } + + # Now, if the temperature changed, update and send an alert if appropriate. + if ($new_scan_hpacucli_physical_drive_temperature ne $old_scan_hpacucli_physical_drive_temperature) + { + # Yup. Analyze + $update = 1; + + # Send an alert telling the user that we've found a variable for this drive. Note + # that we add ' C' to the temperatures so that they get translated to '°F' if desired + # by the reader. + my $variables = { + serial_number => $scan_hpacucli_physical_drive_serial_number, + old_temperature => $old_scan_hpacucli_physical_drive_temperature ? $old_scan_hpacucli_physical_drive_temperature." °C" : "--", + new_temperature => $new_scan_hpacucli_physical_drive_temperature ? $new_scan_hpacucli_physical_drive_temperature." °C" : "--", + delta => $delta." °C", + high_critical_temperature => $high_critical." °C", + high_warning_temperature => $high_warning." °C", + low_critical_temperature => $low_critical." °C", + low_warning_temperature => $low_warning." °C", + }; + my $log_level = (($alert_level eq "warning") or ($alert_level eq "critical")) ? 1 : 2; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => $cleared, + alert_level => $alert_level, + message => $message_key, + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + # Anything else? + if (($old_scan_hpacucli_physical_drive_model ne $new_scan_hpacucli_physical_drive_model) or + ($old_scan_hpacucli_physical_drive_interface ne $new_scan_hpacucli_physical_drive_interface) or + ($old_scan_hpacucli_physical_drive_size ne $new_scan_hpacucli_physical_drive_size) or + ($old_scan_hpacucli_physical_drive_rpm ne $new_scan_hpacucli_physical_drive_rpm) or + ($new_scan_hpacucli_physical_drive_last_failure_reason ne $old_scan_hpacucli_physical_drive_last_failure_reason) or + ($port ne $old_scan_hpacucli_physical_drive_port) or + ($box ne $old_scan_hpacucli_physical_drive_box) or + ($bay ne $old_scan_hpacucli_physical_drive_bay)) + { + # Something else changed. These normally shouldn't change... + $update = 1; + my $variables = { + serial_number => $scan_hpacucli_physical_drive_serial_number, + old_model => $old_scan_hpacucli_physical_drive_model, + new_model => $new_scan_hpacucli_physical_drive_model, + old_interface => $old_scan_hpacucli_physical_drive_interface, + new_interface => $new_scan_hpacucli_physical_drive_interface, + old_size => $anvil->Database->quote($old_scan_hpacucli_physical_drive_size), + new_size => $anvil->Database->quote($new_scan_hpacucli_physical_drive_size), + old_rpm => $old_scan_hpacucli_physical_drive_rpm, + new_rpm => $new_scan_hpacucli_physical_drive_rpm, + old_last_failure_reason => $old_scan_hpacucli_physical_drive_last_failure_reason ? $old_scan_hpacucli_physical_drive_last_failure_reason : "--", + new_last_failure_reason => $new_scan_hpacucli_physical_drive_last_failure_reason ? $new_scan_hpacucli_physical_drive_last_failure_reason : "--", + old_port => $old_scan_hpacucli_physical_drive_port, + new_port => $port, + old_box => $old_scan_hpacucli_physical_drive_box, + new_box => $box, + old_bay => $old_scan_hpacucli_physical_drive_bay, + new_bay => $bay, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0052", variables => $variables}); + $anvil->Alert->register({ + clear_alert => $cleared, + alert_level => "warning", + message => "scan_hpacucli_note_0052", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + + if ($update) + { + # UPDATE + my $query = " +UPDATE + scan_hpacucli_physical_drives +SET + scan_hpacucli_physical_drive_logical_drive_uuid = ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid).", + scan_hpacucli_physical_drive_serial_number = ".$anvil->Database->quote($scan_hpacucli_physical_drive_serial_number).", + scan_hpacucli_physical_drive_model = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_model).", + scan_hpacucli_physical_drive_interface = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_interface).", + scan_hpacucli_physical_drive_status = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_status).", + scan_hpacucli_physical_drive_size = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_size).", + scan_hpacucli_physical_drive_type = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_type).", + scan_hpacucli_physical_drive_rpm = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_rpm).", + scan_hpacucli_physical_drive_temperature = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_temperature).", + scan_hpacucli_physical_drive_last_failure_reason = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_last_failure_reason).", + scan_hpacucli_physical_drive_port = ".$anvil->Database->quote($port).", + scan_hpacucli_physical_drive_box = ".$anvil->Database->quote($box).", + scan_hpacucli_physical_drive_bay = ".$anvil->Database->quote($bay).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_physical_drive_uuid = ".$anvil->Database->quote($scan_hpacucli_physical_drive_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + else + { + # New, INSERT it. + $scan_hpacucli_physical_drive_uuid = $anvil->Get->uuid(); + $anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number} = $scan_hpacucli_physical_drive_uuid; + $anvil->data->{'scan-hpacucli'}{physical_drives}{by_uuid}{$scan_hpacucli_physical_drive_uuid} = $scan_hpacucli_physical_drive_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::physical_drives::by_serial::${scan_hpacucli_physical_drive_serial_number}" => $anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number}, + "scan-hpacucli::physical_drives::by_uuid::${scan_hpacucli_physical_drive_uuid}" => $anvil->data->{'scan-hpacucli'}{physical_drives}{by_uuid}{$scan_hpacucli_physical_drive_uuid}, + }}); + + # Send an alert telling the user we found a new drive. + my $variables = { + controller_serial_number => $scan_hpacucli_controller_serial_number, + array_name => $scan_hpacucli_array_name, + logical_drive_name => $scan_hpacucli_logical_drive_name, + port => $port, + box => $box, + bay => $bay, + drive_serial_number => $scan_hpacucli_physical_drive_serial_number, + model => $new_scan_hpacucli_physical_drive_model, + interface => $new_scan_hpacucli_physical_drive_interface, + status => $new_scan_hpacucli_physical_drive_status, + size => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_physical_drive_size}), + type => $new_scan_hpacucli_physical_drive_type, + rpm => $new_scan_hpacucli_physical_drive_rpm, + temperature => $new_scan_hpacucli_physical_drive_temperature ? $new_scan_hpacucli_physical_drive_temperature." °C" : "--", + last_failure_reason => $new_scan_hpacucli_physical_drive_last_failure_reason ? $new_scan_hpacucli_physical_drive_last_failure_reason : "--", + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0046", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0046", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # Check for problems with this new drive. + if (lc($new_scan_hpacucli_physical_drive_status) ne "ok") + { + # There's a problem, send an alert. + my $variables = { + controller_serial_number => $scan_hpacucli_controller_serial_number, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0064", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => "scan_hpacucli_note_0064", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + + # Check the temperature, if we read one. + if ($new_scan_hpacucli_physical_drive_temperature =~ /^\d+/) + { + ### NOTE: HP tells us the maximum temperature each of its drives can handle. This is + ### a low number, so we need to tighten up some thresholds compared to usual + ### ranges. + # Set defaults + my $high_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{high_critical}; + my $high_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{high_warning}; + my $low_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{low_warning}; + my $low_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{low_critical}; + my $jump = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{jump}; + my $buffer = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{buffer}; + my $clear_high_critical = $high_critical - $buffer; + my $clear_high_warning = $high_warning - $buffer; + my $clear_low_critical = $low_critical - $buffer; + my $clear_low_warning = $low_warning - $buffer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + high_critical => $high_critical, + high_warning => $high_warning, + low_warning => $low_warning, + low_critical => $low_critical, + jump => $jump, + buffer => $buffer, + clear_high_critical => $clear_high_critical, + clear_high_warning => $clear_high_warning, + clear_low_critical => $clear_low_critical, + clear_low_warning => $clear_low_warning, + }}); + + # Fine-tune the alert thresholds + if ($clear_high_critical < $high_warning) + { + $clear_high_critical = $high_warning + 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }}); + } + if ($clear_low_critical > $low_warning) + { + $clear_low_critical = $low_warning - 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }}); + } + + # Did we get a maximum temperature from the drive? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + maximum_drive_temperature => $maximum_drive_temperature, + "scan-hpacucli::ignore_maximum_temperature" => $anvil->data->{'scan-hpacucli'}{ignore_maximum_temperature}, + }}); + if (($maximum_drive_temperature) && (not $anvil->data->{'scan-hpacucli'}{ignore_maximum_temperature})) + { + $high_critical = $maximum_drive_temperature; + $high_warning = $maximum_drive_temperature - 2; + $clear_high_critical = $high_critical - $buffer; + $clear_high_warning = $high_warning - $buffer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + high_critical => $high_critical, + high_warning => $high_warning, + clear_high_critical => $clear_high_critical, + clear_high_warning => $clear_high_warning, + }}); + + # Fine-tune the alert thresholds + if ($clear_high_critical < $high_warning) + { + $clear_high_critical = $high_warning + 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }}); + } + if ($clear_low_critical > $low_warning) + { + $clear_low_critical = $low_warning - 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }}); + } + } + + # See if the temperature outside of the warning or critical thresholds. + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + my $alert_level = "warning"; + my $message_key = ""; + if ($new_scan_hpacucli_physical_drive_temperature > $high_critical) + { + # Crossed the high critical threshold. This should always be unset because it + # is a new variable, but check anyway. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0060"; + } + $temperature_state = "critical"; + $temperature_is = "high"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_physical_drive_temperature > $high_warning) + { + # Crossed the high warning threshold. This should always be unset because it + # is a new variable, but check anyway. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0061"; + } + $temperature_state = "warning"; + $temperature_is = "high"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_physical_drive_temperature < $low_critical) + { + # Dropped below the low critical threshold. This should always be unset + # because it is a new variable, but check anyway. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0062"; + } + $temperature_state = "critical"; + $temperature_is = "low"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_physical_drive_temperature < $low_warning) + { + # Crossed the low warning threshold. This should always be unset because it + # is a new variable, but check anyway. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0063"; + } + $temperature_state = "warning"; + $temperature_is = "low"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + + # Record this for later processing into the 'temperature' table. + my $sensor_host_key = "physical_drive:".$scan_hpacucli_physical_drive_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_host_key => $sensor_host_key }}); + + $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_value_c} = $new_scan_hpacucli_physical_drive_temperature; + $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_state} = $temperature_state; + $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_is} = $temperature_is; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_value_c" => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_value_c}, + "new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_state" => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_state}, + "new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_is" => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_is}, + }}); + + if ($message_key) + { + # Send an alert telling the user that we've found a drive outside nominal + # temperature. Note that we add ' C' to the temperatures so that they get + # translated to '°F' if desired by the reader. + my $variables = { + serial_number => $scan_hpacucli_controller_serial_number, + temperature => $new_scan_hpacucli_physical_drive_temperature ? $new_scan_hpacucli_physical_drive_temperature." °C" : "--", + high_critical_temperature => $high_critical." °C", + high_warning_temperature => $high_warning." °C", + low_critical_temperature => $low_critical." °C", + low_warning_temperature => $low_warning." °C", + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => $alert_level, + message => $message_key, + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + ### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0003", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "notice", + message => "scan_hpacucli_note_0003", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + } + + my $query = " +INSERT INTO + scan_hpacucli_physical_drives +( + scan_hpacucli_physical_drive_uuid, + scan_hpacucli_physical_drive_host_uuid, + scan_hpacucli_physical_drive_logical_drive_uuid, + scan_hpacucli_physical_drive_serial_number, + scan_hpacucli_physical_drive_model, + scan_hpacucli_physical_drive_interface, + scan_hpacucli_physical_drive_status, + scan_hpacucli_physical_drive_size, + scan_hpacucli_physical_drive_type, + scan_hpacucli_physical_drive_rpm, + scan_hpacucli_physical_drive_temperature, + scan_hpacucli_physical_drive_last_failure_reason, + scan_hpacucli_physical_drive_port, + scan_hpacucli_physical_drive_box, + scan_hpacucli_physical_drive_bay, + modified_date +) VALUES ( + ".$anvil->Database->quote($scan_hpacucli_physical_drive_uuid).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid).", + ".$anvil->Database->quote($scan_hpacucli_physical_drive_serial_number).", + ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_model).", + ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_interface).", + ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_status).", + ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_size).", + ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_type).", + ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_rpm).", + ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_temperature).", + ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_last_failure_reason).", + ".$anvil->Database->quote($port).", + ".$anvil->Database->quote($box).", + ".$anvil->Database->quote($bay).", + ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +);"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + + # Process physical drive variables now. Note that there are no temperatures. + foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}}) + { + my $new_scan_hpacucli_variable_value = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{$scan_hpacucli_variable_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan_hpacucli_variable_name" => $scan_hpacucli_variable_name, + "new_scan_hpacucli_variable_value" => $new_scan_hpacucli_variable_value, + }}); + + # Have we seen this variable before? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::scan_hpacucli_physical_drives::source_uuid::${scan_hpacucli_physical_drive_uuid}::detail::${scan_hpacucli_variable_name}::scan_hpacucli_variable_uuid" => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}, + }}); + if ($anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}) + { + # Exists. Has it changed? + my $scan_hpacucli_variable_uuid = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}; + my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_variable_uuid => $scan_hpacucli_variable_uuid, + old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, + }}); + + # delete this so that we know it was processed. + delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}; + + if ($old_scan_hpacucli_variable_value ne $new_scan_hpacucli_variable_value) + { + # Now update. Alert the user as a warning, these should rarely ever change. + my $variables = { + serial_number => $scan_hpacucli_physical_drive_serial_number, + variable_name => $scan_hpacucli_variable_name, + old_value => $old_scan_hpacucli_variable_value ? $old_scan_hpacucli_variable_value : "--", + new_value => $new_scan_hpacucli_variable_value ? $new_scan_hpacucli_variable_value : "--", + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0065", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0065", + variables => $variables, + show_header => 0, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # UPDATE + my $query = " +UPDATE + scan_hpacucli_variables +SET + scan_hpacucli_variable_value = ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_variable_uuid = ".$anvil->Database->quote($scan_hpacucli_variable_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + else + { + # Clear the hash key that was autovivified in the previous check so that it doesn't + # cause a loop when looking for vanished values. + delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}; + + # New. Alert the user. + my $variables = { + name => $scan_hpacucli_variable_name, + value => $new_scan_hpacucli_variable_value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0004", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "notice", + message => "scan_hpacucli_note_0004", + variables => $variables, + show_header => 0, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_hpacucli_variables +( + scan_hpacucli_variable_uuid, + scan_hpacucli_variable_host_uuid, + scan_hpacucli_variable_source_table, + scan_hpacucli_variable_source_uuid, + scan_hpacucli_variable_is_temperature, + scan_hpacucli_variable_name, + scan_hpacucli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_hpacucli_physical_drives', + ".$anvil->Database->quote($scan_hpacucli_physical_drive_uuid).", + FALSE, + ".$anvil->Database->quote($scan_hpacucli_variable_name).", + ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", + ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +);"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + + # Look for vanished variables for this drive. + foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}}) + { + my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value}; + my $old_scan_hpacucli_variable_uuid = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_variable_name => $scan_hpacucli_variable_name, + old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, + old_scan_hpacucli_variable_uuid => $old_scan_hpacucli_variable_uuid, + }}); + + # If the old alarm state is already 'VANISHED', ignore it. + next if $old_scan_hpacucli_variable_value eq "VANISHED"; + + # Still here? Alert and UPDATE. + ### NOTE: For now, we're going to use warning level because cache_modules + ### should never vanish unless one failed. If that is the case, the + ### admin already knows, but this will let other notification targets + ### know that the change has happened. + my $variables = { + serial_number => $scan_hpacucli_physical_drive_serial_number, + name => $scan_hpacucli_variable_name, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0067", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0067", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_hpacucli_variables +SET + scan_hpacucli_variable_value = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_variable_uuid = ".$anvil->Database->quote($old_scan_hpacucli_variable_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + + # If this was a diagnostics run, check for error counters + if ($anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics}) + { + # These are stored in the DB as standard variables, but we use the source is + # 'scan_hpacucli_physical_drive_diagnostics' to distinguish them. + if (exists $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_hard}) + { + # We got the data + foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}}) + { + # Store this in the main hash. + my $new_scan_hpacucli_variable_value = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{'diagnostics'}{$scan_hpacucli_variable_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_variable_name => $scan_hpacucli_variable_name, + new_scan_hpacucli_variable_value => $new_scan_hpacucli_variable_value, + }}); + + ### TODO + # If the variable name has 'error' in it and the value is numeric, see if it + # is > 5 and, if so, set the health. + + # Have we seen this variable before? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::scan_hpacucli_physical_drive_diagnostics::source_uuid::${scan_hpacucli_physical_drive_uuid}::diagnostics::${scan_hpacucli_variable_name}::scan_hpacucli_variable_uuid" => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}, + }}); + if ($anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}) + { + # Exists. Has it changed? + my $scan_hpacucli_variable_uuid = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}; + my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_variable_uuid => $scan_hpacucli_variable_uuid, + old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, + }}); + + # Delete this so that we know it was processed. + delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}; + + if ($old_scan_hpacucli_variable_value ne $new_scan_hpacucli_variable_value) + { + # Now update. Alert the user as a warning, these should rarely ever change. + my $variables = { + serial_number => $scan_hpacucli_physical_drive_serial_number, + variable_name => $scan_hpacucli_variable_name, + old_value => $old_scan_hpacucli_variable_value ? $old_scan_hpacucli_variable_value : "--", + new_value => $new_scan_hpacucli_variable_value ? $new_scan_hpacucli_variable_value : "--", + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0065", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0065", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # UPDATE + my $query = " +UPDATE + scan_hpacucli_variables +SET + scan_hpacucli_variable_value = ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_variable_uuid = ".$anvil->Database->quote($scan_hpacucli_variable_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + else + { + # Clear the hash key that was autovivified in the previous check so + # that it doesn't cause a loop when looking for vanished values. + delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}; + + # New. Alert the user. + my $variables = { + name => $scan_hpacucli_variable_name, + value => $new_scan_hpacucli_variable_value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0004", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "notice", + message => "scan_hpacucli_note_0004", + show_header => 0, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_hpacucli_variables +( + scan_hpacucli_variable_uuid, + scan_hpacucli_variable_host_uuid, + scan_hpacucli_variable_source_table, + scan_hpacucli_variable_source_uuid, + scan_hpacucli_variable_is_temperature, + scan_hpacucli_variable_name, + scan_hpacucli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_hpacucli_physical_drive_diagnostics', + ".$anvil->Database->quote($scan_hpacucli_physical_drive_uuid).", + FALSE, + ".$anvil->Database->quote($scan_hpacucli_variable_name).", + ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", + ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +);"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + } + + # Look for vanished diagnostics variables. + foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}}) + { + my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value}; + my $old_scan_hpacucli_variable_uuid = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_variable_name => $scan_hpacucli_variable_name, + old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, + old_scan_hpacucli_variable_uuid => $old_scan_hpacucli_variable_uuid, + }}); + + # If the old alarm state is already 'VANISHED', ignore it. + next if $old_scan_hpacucli_variable_value eq "VANISHED"; + + # Still here? Alert and UPDATE. + ### NOTE: For now, we're going to use warning level because cache_modules + ### should never vanish unless one failed. If that is the case, the + ### admin already knows, but this will let other notification targets + ### know that the change has happened. + my $variables = { + serial_number => $scan_hpacucli_physical_drive_serial_number, + name => $scan_hpacucli_variable_name, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0068", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0068", + show_header => 1, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_hpacucli_variables +SET + scan_hpacucli_variable_value = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_variable_uuid = ".$anvil->Database->quote($old_scan_hpacucli_variable_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + + return(0); +} + +# Look for added, changed or deleted controllers. +sub process_controllers +{ + my ($anvil) = @_; + + # Look for new, changed or deleted controllers. + $anvil->data->{'scan-hpacucli'}{queries} = []; + + foreach my $scan_hpacucli_controller_serial_number (sort {$a cmp $b} keys %{$anvil->data->{controller}}) + { + # Controller data; + next if $scan_hpacucli_controller_serial_number eq "metadata"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number, + "scan-hpacucli::controllers::by_serial::$scan_hpacucli_controller_serial_number" => $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}, + }}); + + # Have we seen this controller before? + my $scan_hpacucli_controller_uuid = ""; + my $controller_is_new = 0; + if ($anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}) + { + # Yup! + $scan_hpacucli_controller_uuid = $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_controller_uuid => $scan_hpacucli_controller_uuid }}); + } + else + { + # No, this is a new controller. Create a new UUID for it. + $scan_hpacucli_controller_uuid = $anvil->Get->uuid(); + $controller_is_new = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_controller_uuid => $scan_hpacucli_controller_uuid, + controller_is_new => $controller_is_new, + }}); + + # Add the keys for looking it up by UUID or serial number. + $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number} = $scan_hpacucli_controller_uuid; + $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid} = $scan_hpacucli_controller_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::controllers::by_serial::$scan_hpacucli_controller_serial_number" => $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}, + "scan-hpacucli::controllers::by_uuid::$scan_hpacucli_controller_uuid" => $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid}, + }}); + } + + # These are the values for the controller and cache tables. Anything else will go in the + # variables table which will be processed after the controller. + # Controller + my $new_scan_hpacucli_controller_model = ""; + my $new_scan_hpacucli_controller_status = ""; + my $new_scan_hpacucli_controller_last_diagnostics = $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics} ? time : ""; + my $new_scan_hpacucli_controller_cache_present = "unknown"; + my $new_scan_hpacucli_controller_drive_write_cache = ""; + my $new_scan_hpacucli_controller_firmware_version = ""; + my $new_scan_hpacucli_controller_unsafe_writeback_cache = ""; + + # Cache + my $new_scan_hpacucli_cache_module_size = ""; + my $new_scan_hpacucli_cache_module_serial_number = ""; + my $new_scan_hpacucli_cache_module_status = ""; + my $new_scan_hpacucli_cache_module_type = ""; + + foreach my $type ("detail", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}}) + { + # Pick up the variables for the controller + if (($type eq "detail") && ($variable eq "model_name")) + { + # Store and delete the value + $new_scan_hpacucli_controller_model = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_model => $new_scan_hpacucli_controller_model }}); + next; + } + elsif (($type eq "detail") && ($variable eq "controller_status")) + { + # Store and delete the value + $new_scan_hpacucli_controller_status = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + $new_scan_hpacucli_controller_status = lc($new_scan_hpacucli_controller_status); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_status => $new_scan_hpacucli_controller_status }}); + next; + } + elsif (($type eq "detail") && ($variable eq "cache_board_present")) + { + # Store and delete the value + $new_scan_hpacucli_controller_cache_present = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + $new_scan_hpacucli_controller_cache_present = lc($new_scan_hpacucli_controller_cache_present); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_cache_present => $new_scan_hpacucli_controller_cache_present }}); + next; + } + elsif (($type eq "detail") && ($variable eq "drive_write_cache")) + { + # Store and delete the value + $new_scan_hpacucli_controller_drive_write_cache = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + $new_scan_hpacucli_controller_drive_write_cache = lc($new_scan_hpacucli_controller_drive_write_cache); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_drive_write_cache => $new_scan_hpacucli_controller_drive_write_cache }}); + next; + } + elsif (($type eq "detail") && ($variable eq "firmware_version")) + { + # Store and delete the value + $new_scan_hpacucli_controller_firmware_version = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_firmware_version => $new_scan_hpacucli_controller_firmware_version }}); + next; + } + elsif (($type eq "detail") && ($variable eq "no_battery_write_cache")) + { + # Store and delete the value + $new_scan_hpacucli_controller_unsafe_writeback_cache = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + $new_scan_hpacucli_controller_unsafe_writeback_cache = lc($new_scan_hpacucli_controller_unsafe_writeback_cache); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_unsafe_writeback_cache => $new_scan_hpacucli_controller_unsafe_writeback_cache }}); + next; + } + # Pick up the data for the cache. + elsif (($type eq "detail") && ($variable eq "total_cache_size")) + { + # Store and delete the value + $new_scan_hpacucli_cache_module_size = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_cache_module_size => $new_scan_hpacucli_cache_module_size }}); + next; + } + elsif (($type eq "detail") && ($variable eq "cache_serial_number")) + { + # Store and delete the value + $new_scan_hpacucli_cache_module_serial_number = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_cache_module_serial_number => $new_scan_hpacucli_cache_module_serial_number }}); + next; + } + elsif (($type eq "detail") && ($variable eq "cache_status")) + { + # Store and delete the value + $new_scan_hpacucli_cache_module_status = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + $new_scan_hpacucli_cache_module_status = lc($new_scan_hpacucli_cache_module_status); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_cache_module_status => $new_scan_hpacucli_cache_module_status }}); + next; + } + elsif (($type eq "detail") && ($variable eq "cache_backup_power_source")) + { + # Store and delete the value + $new_scan_hpacucli_cache_module_type = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + $new_scan_hpacucli_cache_module_type = lc($new_scan_hpacucli_cache_module_type); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_cache_module_type => $new_scan_hpacucli_cache_module_type }}); + next; + } + else + { + # Just for debug + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::${scan_hpacucli_controller_serial_number}::data::${type}::${variable}" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}, + }}); + } + } + } + + # Pull out the rest of the variables now. If the controller is new, all variables will be + # INSERTed. If the controller exists, each variable will be examined and new ones will be + # INSERTed, existing ones will be checked for changes and UPDATEd as needed. If the + # controller is NOT new, then variables from the old data will be deleted as we go and any + # not found in the current data set will be left over. We'll use this to determine variables + # that have vanished. They will not be deleted, but their value will be set to 'VANISHED'. + if ($controller_is_new) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number, + new_scan_hpacucli_controller_model => $new_scan_hpacucli_controller_model, + new_scan_hpacucli_controller_cache_present => $new_scan_hpacucli_controller_cache_present, + new_scan_hpacucli_controller_drive_write_cache => $new_scan_hpacucli_controller_drive_write_cache, + new_scan_hpacucli_controller_firmware_version => $new_scan_hpacucli_controller_firmware_version, + new_scan_hpacucli_controller_unsafe_writeback_cache => $new_scan_hpacucli_controller_unsafe_writeback_cache, + }}); + + # Send an alert telling the user that we've found a new controller. + my $variables = { + model => $new_scan_hpacucli_controller_model, + serial_number => $scan_hpacucli_controller_serial_number, + status => $new_scan_hpacucli_controller_status, + drive_write_cache => $new_scan_hpacucli_controller_drive_write_cache, + firmware_version => $new_scan_hpacucli_controller_firmware_version, + unsafe_writeback_cache => $new_scan_hpacucli_controller_unsafe_writeback_cache, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0001", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "notice", + message => "scan_hpacucli_note_0001", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_hpacucli_controllers +( + scan_hpacucli_controller_uuid, + scan_hpacucli_controller_host_uuid, + scan_hpacucli_controller_serial_number, + scan_hpacucli_controller_model, + scan_hpacucli_controller_status, + scan_hpacucli_controller_last_diagnostics, + scan_hpacucli_controller_cache_present, + scan_hpacucli_controller_drive_write_cache, + scan_hpacucli_controller_firmware_version, + scan_hpacucli_controller_unsafe_writeback_cache, + modified_date +) VALUES ( + ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($scan_hpacucli_controller_serial_number).", + ".$anvil->Database->quote($new_scan_hpacucli_controller_model).", + ".$anvil->Database->quote($new_scan_hpacucli_controller_status).", + ".$anvil->Database->quote($new_scan_hpacucli_controller_last_diagnostics).", + ".$anvil->Database->quote($new_scan_hpacucli_controller_cache_present).", + ".$anvil->Database->quote($new_scan_hpacucli_controller_drive_write_cache).", + ".$anvil->Database->quote($new_scan_hpacucli_controller_firmware_version).", + ".$anvil->Database->quote($new_scan_hpacucli_controller_unsafe_writeback_cache).", + ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +);"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + else + { + ### NOTE: The serial number and model should never change (a changed SN/controller + ### should be picked up as a new controller), but we check/update just to be + ### safe. + # Controller already exists, check for changes. + my $old_scan_hpacucli_controller_serial_number = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_serial_number}; + my $old_scan_hpacucli_controller_model = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_model}; + my $old_scan_hpacucli_controller_status = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_status}; + my $old_scan_hpacucli_controller_last_diagnostics = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_last_diagnostics}; + my $old_scan_hpacucli_controller_cache_present = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_cache_present}; + my $old_scan_hpacucli_controller_drive_write_cache = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_drive_write_cache}; + my $old_scan_hpacucli_controller_firmware_version = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_firmware_version}; + my $old_scan_hpacucli_controller_unsafe_writeback_cache = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_unsafe_writeback_cache}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number, + old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number, + old_scan_hpacucli_controller_model => $old_scan_hpacucli_controller_model, + old_scan_hpacucli_controller_status => $old_scan_hpacucli_controller_status, + old_scan_hpacucli_controller_last_diagnostics => $old_scan_hpacucli_controller_last_diagnostics, + old_scan_hpacucli_controller_cache_present => $old_scan_hpacucli_controller_cache_present, + old_scan_hpacucli_controller_drive_write_cache => $old_scan_hpacucli_controller_drive_write_cache, + old_scan_hpacucli_controller_firmware_version => $old_scan_hpacucli_controller_firmware_version, + old_scan_hpacucli_controller_unsafe_writeback_cache => $old_scan_hpacucli_controller_unsafe_writeback_cache, + }}); + + # Delete this from the old cache. + delete $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}; + + # NOTE: We don't check if the last diagnostics changed because it will change every + # 10 minutes or so. + if (($scan_hpacucli_controller_serial_number ne $old_scan_hpacucli_controller_serial_number) or + ($new_scan_hpacucli_controller_model ne $old_scan_hpacucli_controller_model) or + ($new_scan_hpacucli_controller_status ne $old_scan_hpacucli_controller_status) or + ($new_scan_hpacucli_controller_cache_present ne $old_scan_hpacucli_controller_cache_present) or + ($new_scan_hpacucli_controller_drive_write_cache ne $old_scan_hpacucli_controller_drive_write_cache) or + ($new_scan_hpacucli_controller_firmware_version ne $old_scan_hpacucli_controller_firmware_version) or + ($new_scan_hpacucli_controller_unsafe_writeback_cache ne $old_scan_hpacucli_controller_unsafe_writeback_cache)) + { + # Send a warning level alert because the most likely change is 'status'. If, + # however, the status is now 'ok', then we'll clear the alert. + my $cleared = 0; + my $message_key = "scan_hpacucli_warning_0002"; + if ($new_scan_hpacucli_controller_status ne $old_scan_hpacucli_controller_status) + { + if (($new_scan_hpacucli_controller_status ne $old_scan_hpacucli_controller_status) && ($old_scan_hpacucli_controller_status eq "VANISHED")) + { + # Controller has returned. + $message_key = "scan_hpacucli_warning_0003"; + } + if (($new_scan_hpacucli_controller_status ne $old_scan_hpacucli_controller_status) && ($new_scan_hpacucli_controller_status =~ /ok/i)) + { + # Clear the alert, the controller is OK again. + $cleared = 1; + } + } + + my $variables = { + new_serial_number => $scan_hpacucli_controller_serial_number, + old_serial_number => $old_scan_hpacucli_controller_serial_number, + new_model_name => $new_scan_hpacucli_controller_model, + old_model_name => $old_scan_hpacucli_controller_model, + new_status => $new_scan_hpacucli_controller_status, + old_status => $old_scan_hpacucli_controller_status, + new_cache_present => $new_scan_hpacucli_controller_cache_present, + old_cache_present => $old_scan_hpacucli_controller_cache_present, + new_drive_write_cache => $new_scan_hpacucli_controller_drive_write_cache, + old_drive_write_cache => $old_scan_hpacucli_controller_drive_write_cache, + new_firmware_version => $new_scan_hpacucli_controller_firmware_version, + old_firmware_version => $old_scan_hpacucli_controller_firmware_version, + new_unsafe_writeback_cache => $new_scan_hpacucli_controller_unsafe_writeback_cache, + old_unsafe_writeback_cache => $old_scan_hpacucli_controller_unsafe_writeback_cache, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => $cleared, + alert_level => "warning", + message => $message_key, + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_hpacucli_controllers +SET + scan_hpacucli_controller_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid).", + scan_hpacucli_controller_serial_number = ".$anvil->Database->quote($scan_hpacucli_controller_serial_number).", + scan_hpacucli_controller_model = ".$anvil->Database->quote($new_scan_hpacucli_controller_model).", + scan_hpacucli_controller_status = ".$anvil->Database->quote($new_scan_hpacucli_controller_status).", + scan_hpacucli_controller_cache_present = ".$anvil->Database->quote($new_scan_hpacucli_controller_cache_present).", + scan_hpacucli_controller_drive_write_cache = ".$anvil->Database->quote($new_scan_hpacucli_controller_drive_write_cache).", + scan_hpacucli_controller_firmware_version = ".$anvil->Database->quote($new_scan_hpacucli_controller_firmware_version).", + scan_hpacucli_controller_unsafe_writeback_cache = ".$anvil->Database->quote($new_scan_hpacucli_controller_unsafe_writeback_cache).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_controller_uuid = ".$anvil->Database->quote($scan_hpacucli_controller_uuid)." +;"; + + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + + # Now, if we had a cache module on this controller, see if we knew about it already. + my $scan_hpacucli_cache_module_uuid = ""; + my $cache_is_new = 0; + if ($new_scan_hpacucli_cache_module_serial_number) + { + if ($anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$new_scan_hpacucli_cache_module_serial_number}) + { + # Yup! + $scan_hpacucli_cache_module_uuid = $anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$new_scan_hpacucli_cache_module_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_cache_module_uuid => $scan_hpacucli_cache_module_uuid }}); + } + else + { + # No, this is a new cache module. Create a new UUID for it. + $scan_hpacucli_cache_module_uuid = $anvil->Get->uuid(); + $cache_is_new = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_cache_module_uuid => $scan_hpacucli_cache_module_uuid, + cache_is_new => $cache_is_new, + }}); + + # Add the keys for looking it up by UUID or serial number. + $anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$new_scan_hpacucli_cache_module_serial_number} = $scan_hpacucli_cache_module_uuid; + $anvil->data->{'scan-hpacucli'}{cache_modules}{by_uuid}{$scan_hpacucli_cache_module_uuid} = $new_scan_hpacucli_cache_module_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::cache_modules::by_serial::$new_scan_hpacucli_cache_module_serial_number" => $anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$new_scan_hpacucli_cache_module_serial_number}, + "scan-hpacucli::cache_modules::by_uuid::$scan_hpacucli_cache_module_uuid" => $anvil->data->{'scan-hpacucli'}{cache_modules}{by_uuid}{$scan_hpacucli_cache_module_uuid}, + }}); + } + + if ($cache_is_new) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_cache_module_uuid => $scan_hpacucli_cache_module_uuid, + new_scan_hpacucli_cache_module_size => $new_scan_hpacucli_cache_module_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_cache_module_size}).")", + new_scan_hpacucli_cache_module_serial_number => $new_scan_hpacucli_cache_module_serial_number, + new_scan_hpacucli_cache_module_status => $new_scan_hpacucli_cache_module_status, + new_scan_hpacucli_cache_module_type => $new_scan_hpacucli_cache_module_type, + }}); + + # Send an alert telling the user that we've found a new controller. + my $variables = { + serial_number => $new_scan_hpacucli_cache_module_serial_number, + cache_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_cache_module_size}), + status => $new_scan_hpacucli_cache_module_status, + type => $new_scan_hpacucli_cache_module_type, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0002", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "notice", + message => "scan_hpacucli_note_0002", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + ### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0003"}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "notice", + message => "scan_hpacucli_note_0003", + variables => {}, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_hpacucli_cache_modules +( + scan_hpacucli_cache_module_uuid, + scan_hpacucli_cache_module_host_uuid, + scan_hpacucli_cache_module_controller_uuid, + scan_hpacucli_cache_module_serial_number, + scan_hpacucli_cache_module_status, + scan_hpacucli_cache_module_type, + scan_hpacucli_cache_module_size, + modified_date +) VALUES ( + ".$anvil->Database->quote($scan_hpacucli_cache_module_uuid).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", + ".$anvil->Database->quote($new_scan_hpacucli_cache_module_serial_number).", + ".$anvil->Database->quote($new_scan_hpacucli_cache_module_status).", + ".$anvil->Database->quote($new_scan_hpacucli_cache_module_type).", + ".$anvil->Database->quote($new_scan_hpacucli_cache_module_size).", + ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +);"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + else + { + # Exists already, look for changes. The serial number should never change, + # buuuut... + my $old_scan_hpacucli_cache_module_controller_uuid = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_controller_uuid}; + my $old_scan_hpacucli_cache_module_serial_number = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_serial_number}; + my $old_scan_hpacucli_cache_module_status = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_status}; + my $old_scan_hpacucli_cache_module_type = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_type}; + my $old_scan_hpacucli_cache_module_size = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_size}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_scan_hpacucli_cache_module_controller_uuid => $old_scan_hpacucli_cache_module_controller_uuid, + old_scan_hpacucli_cache_module_serial_number => $old_scan_hpacucli_cache_module_serial_number, + old_scan_hpacucli_cache_module_status => $old_scan_hpacucli_cache_module_status, + old_scan_hpacucli_cache_module_type => $old_scan_hpacucli_cache_module_type, + old_scan_hpacucli_cache_module_size => $old_scan_hpacucli_cache_module_size, + }}); + + # Delete this so we know we saw it. + delete $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}; + + if (($scan_hpacucli_controller_uuid ne $old_scan_hpacucli_cache_module_controller_uuid) or + ($new_scan_hpacucli_cache_module_serial_number ne $old_scan_hpacucli_cache_module_serial_number) or + ($new_scan_hpacucli_cache_module_status ne $old_scan_hpacucli_cache_module_status) or + ($new_scan_hpacucli_cache_module_type ne $old_scan_hpacucli_cache_module_type) or + ($new_scan_hpacucli_cache_module_size ne $old_scan_hpacucli_cache_module_size)) + { + # Something has changed, but what? Any change is likely bad, so we + # default to 'warning'. + my $cleared = 0; + my $message_key = "scan_hpacucli_warning_0004"; + + # Did the status return to 'ok'? + if (($old_scan_hpacucli_cache_module_status ne $new_scan_hpacucli_cache_module_status) && ($old_scan_hpacucli_cache_module_status eq "VANISHED")) + { + # The cache module is back + $message_key = "scan_hpacucli_warning_0005"; + } + elsif (($old_scan_hpacucli_cache_module_status ne $new_scan_hpacucli_cache_module_status) && ($new_scan_hpacucli_cache_module_status eq "ok")) + { + # The status is good now, clear the alert + $cleared = 1; + } + + # Convert the old controller UUID to a serial number. + my $query = "SELECT scan_hpacucli_controller_serial_number FROM scan_hpacucli_controllers WHERE scan_hpacucli_controller_uuid = ".$anvil->Database->quote($old_scan_hpacucli_cache_module_controller_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + my $old_scan_hpacucli_controller_serial_number = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $old_scan_hpacucli_controller_serial_number = "--" if not defined $old_scan_hpacucli_controller_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number }}); + + # Send the alert + my $variables = { + old_serial_number => $old_scan_hpacucli_cache_module_serial_number, + new_serial_number => $new_scan_hpacucli_cache_module_serial_number, + old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number, + new_controller_serial_number => $scan_hpacucli_controller_serial_number, + old_status => $old_scan_hpacucli_cache_module_status, + new_status => $old_scan_hpacucli_cache_module_status, + old_type => $new_scan_hpacucli_cache_module_type, + new_type => $old_scan_hpacucli_cache_module_type, + say_old_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hpacucli_cache_module_size}), + say_new_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_cache_module_size}), + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0002", variables => $variables}); + $anvil->Alert->register({ + clear_alert => $cleared, + alert_level => "warning", + message => $message_key, + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + ### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0003"}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0003", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # Update the database. + $query = " +UPDATE + scan_hpacucli_cache_modules +SET + scan_hpacucli_cache_module_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid).", + scan_hpacucli_cache_module_controller_uuid = ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", + scan_hpacucli_cache_module_serial_number = ".$anvil->Database->quote($new_scan_hpacucli_cache_module_serial_number).", + scan_hpacucli_cache_module_status = ".$anvil->Database->quote($new_scan_hpacucli_cache_module_status).", + scan_hpacucli_cache_module_type = ".$anvil->Database->quote($new_scan_hpacucli_cache_module_type).", + scan_hpacucli_cache_module_size = ".$anvil->Database->quote($new_scan_hpacucli_cache_module_size).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_cache_module_uuid = ".$anvil->Database->quote($scan_hpacucli_cache_module_uuid)." +;"; + + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + } + + # We do this after the cache so that the alerts make since when a new controller is found. + foreach my $type ("detail", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}}) + { + my $new_scan_hpacucli_variable_value = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + new_scan_hpacucli_variable_value => $new_scan_hpacucli_variable_value, + temperature => $temperature, + }}); + + # Now, if the variable doesn't exist, INSERT it. If it does exist, see if it + # changed and UPDATE it if so. + if (exists $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$variable}) + { + # Look for changes + my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$variable}{scan_hpacucli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$variable}{scan_hpacucli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_scan_hpacucli_variable_value => $new_scan_hpacucli_variable_value, + old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$variable}; + + # Set defaults + my $high_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{high_critical}; + my $high_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{high_warning}; + my $low_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{low_warning}; + my $low_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{low_critical}; + my $jump = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{jump}; + my $buffer = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{buffer}; + my $clear_high_critical = $high_critical - $buffer; + my $clear_high_warning = $high_warning - $buffer; + my $clear_low_critical = $low_critical - $buffer; + my $clear_low_warning = $low_warning - $buffer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + high_critical => $high_critical, + high_warning => $high_warning, + low_warning => $low_warning, + low_critical => $low_critical, + jump => $jump, + buffer => $buffer, + clear_high_critical => $clear_high_critical, + clear_high_warning => $clear_high_warning, + clear_low_critical => $clear_low_critical, + clear_low_warning => $clear_low_warning, + }}); + + # Fine-tune the alert thresholds + if ($clear_high_critical < $high_warning) + { + $clear_high_critical = $high_warning + 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }}); + } + if ($clear_low_critical > $low_warning) + { + $clear_low_critical = $low_warning - 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }}); + } + + # Does this variable have defined limits? + if (exists $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_critical}) + { + $high_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_critical}; + $high_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_warning}; + $low_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{low_warning}; + $low_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{low_critical}; + $jump = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{jump}; + $buffer = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{buffer}; + $clear_high_critical = $high_critical - $buffer; + $clear_high_warning = $high_warning - $buffer; + $clear_low_critical = $low_critical - $buffer; + $clear_low_warning = $low_warning - $buffer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + high_critical => $high_critical, + high_warning => $high_warning, + low_warning => $low_warning, + low_critical => $low_critical, + jump => $jump, + buffer => $buffer, + clear_high_critical => $clear_high_critical, + clear_high_warning => $clear_high_warning, + clear_low_critical => $clear_low_critical, + clear_low_warning => $clear_low_warning, + }}); + + # Fine-tune the alert thresholds + if ($clear_high_critical < $high_warning) + { + $clear_high_critical = $high_warning + 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }}); + } + if ($clear_low_critical > $low_warning) + { + $clear_low_critical = $low_warning - 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }}); + } + } + + # If it's a temperature, we need to analyze it and store it, + # regardless of if it changed this pass. + my $cleared = 0; + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + my $message_key = "scan_hpacucli_note_0009"; + my $alert_level = "notice"; + my $delta = 0; + if ($type eq "temperature") + { + # Change the log level to info as temperatures change often. + $alert_level = "info"; + + # Now see if the temperature has crossed into a + # warning or critical state. + if ($new_scan_hpacucli_variable_value > $high_critical) + { + # Crossed the high critical threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0005"; + } + $temperature_state = "critical"; + $temperature_is = "high"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_variable_value > $high_warning) + { + # Crossed the high warning threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0006"; + } + $temperature_state = "warning"; + $temperature_is = "high"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_variable_value < $low_critical) + { + # Dropped below the low critical threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0007"; + } + $temperature_state = "critical"; + $temperature_is = "low"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_variable_value < $low_warning) + { + # Crossed the low warning threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0008"; + } + $temperature_state = "warning"; + $temperature_is = "low"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + else + { + # Did it change enough to trigger a jump + # alert? + if ($new_scan_hpacucli_variable_value > $old_scan_hpacucli_variable_value) + { + # Jumped + $delta = $new_scan_hpacucli_variable_value - $old_scan_hpacucli_variable_value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { delta => $delta }}); + if ($delta >= $jump) + { + # Big jump. + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0015"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + else + { + # Dropped + $delta = $old_scan_hpacucli_variable_value - $new_scan_hpacucli_variable_value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { delta => $delta }}); + if ($delta >= $jump) + { + # Big drop. + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0016"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + } + + # Record this for later processing into the 'temperature' + # table. + my $sensor_host_key = "controller:$scan_hpacucli_controller_serial_number"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_host_key => $sensor_host_key }}); + + $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_value_c} = $new_scan_hpacucli_variable_value; + $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_state} = $temperature_state; + $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_is} = $temperature_is; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::temperature::${variable}::${sensor_host_key}::temperature_value_c" => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_value_c}, + "new::temperature::${variable}::${sensor_host_key}::temperature_state" => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_state}, + "new::temperature::${variable}::${sensor_host_key}::temperature_is" => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_is}, + }}); + } + + # Did the variable change? + if ($new_scan_hpacucli_variable_value ne $old_scan_hpacucli_variable_value) + { + # How has it changed? + if ($old_scan_hpacucli_variable_value eq "VANISHED") + { + $message_key = "scan_hpacucli_note_0010"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + elsif ($type eq "temperature") + { + + # Clear alerts, if needed. The order is important as + # clearing a warning will replace clearing a critical + # when a sensor goes critical -> ok in one scan. Once + # done, we'll check if we've crossed into a warning + # or critical state. If so, those will replace any + # cleared messages. + if ($new_scan_hpacucli_variable_value < $clear_high_critical) + { + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $cleared = 1; + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0011"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + if ($new_scan_hpacucli_variable_value < $clear_high_warning) + { + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # The temperature is no longer + # warning, and it didn't just go + # critical + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0012"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + if ($new_scan_hpacucli_variable_value > $clear_low_critical) + { + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $cleared = 1; + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0013"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + if ($new_scan_hpacucli_variable_value > $clear_low_warning) + { + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0014"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + } + + # Send an alert telling the user that we've found a variable for this + # controller. Note that we add ' C' to the temperatures so that they get + # translated to '°F' if desired by the reader. + my $variables = { + sensor_name => $variable, + serial_number => $scan_hpacucli_controller_serial_number, + name => $variable, + old_value => $type eq "temperature" ? $old_scan_hpacucli_variable_value." °C" : $old_scan_hpacucli_variable_value, + new_value => $type eq "temperature" ? $new_scan_hpacucli_variable_value." °C" : $new_scan_hpacucli_variable_value, + high_critical_temperature => $high_critical." °C", + high_warning_temperature => $high_warning." °C", + low_critical_temperature => $low_critical." °C", + low_warning_temperature => $low_warning." °C", + delta => $delta, + }; + my $log_level = (($alert_level eq "warning") or ($alert_level eq "critical")) ? 1 : 2; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => $cleared, + alert_level => $alert_level, + message => $message_key, + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # UPDATE + my $query = " +UPDATE + scan_hpacucli_variables +SET + scan_hpacucli_variable_value = ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_variable_uuid = ".$anvil->Database->quote($variable_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + else + { + # New, record. + my $message_key = "scan_hpacucli_note_0004"; + my $alert_level = "notice"; + + # Set defaults + my $high_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{high_critical}; + my $high_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{high_warning}; + my $low_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{low_warning}; + my $low_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{low_critical}; + my $jump = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{jump}; + my $buffer = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{buffer}; + my $clear_high_critical = $high_critical - $buffer; + my $clear_high_warning = $high_warning - $buffer; + my $clear_low_critical = $low_critical - $buffer; + my $clear_low_warning = $low_warning - $buffer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "high_critical" => $high_critical, + "high_warning" => $high_warning, + "low_warning" => $low_warning, + "low_critical" => $low_critical, + "jump" => $jump, + "buffer" => $buffer, + "clear_high_critical" => $clear_high_critical, + "clear_high_warning" => $clear_high_warning, + "clear_low_critical" => $clear_low_critical, + "clear_low_warning" => $clear_low_warning, + }}); + + # Fine-tune the alert thresholds + if ($clear_high_critical < $high_warning) + { + $clear_high_critical = $high_warning + 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }}); + } + if ($clear_low_critical > $low_warning) + { + $clear_low_critical = $low_warning - 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }}); + } + + if ($type eq "temperature") + { + # Does this variable have defined limits? + if (exists $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_critical}) + { + $high_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_critical}; + $high_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_warning}; + $low_warning = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{low_warning}; + $low_critical = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{low_critical}; + $jump = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{jump}; + $buffer = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{buffer}; + $clear_high_critical = $high_critical - $buffer; + $clear_high_warning = $high_warning - $buffer; + $clear_low_critical = $low_critical - $buffer; + $clear_low_warning = $low_warning - $buffer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + high_critical => $high_critical, + high_warning => $high_warning, + low_warning => $low_warning, + low_critical => $low_critical, + jump => $jump, + buffer => $buffer, + clear_high_critical => $clear_high_critical, + clear_high_warning => $clear_high_warning, + clear_low_critical => $clear_low_critical, + clear_low_warning => $clear_low_warning, + }}); + + # Fine-tune the alert thresholds + if ($clear_high_critical < $high_warning) + { + $clear_high_critical = $high_warning + 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }}); + } + if ($clear_low_critical > $low_warning) + { + $clear_low_critical = $low_warning - 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }}); + } + } + + # This is a temperature, so see if the temperature outside of + # the warning or critical thresholds. This is a new sensor, + # so nothing to compare against. + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + if ($new_scan_hpacucli_variable_value > $high_critical) + { + # Crossed the high critical threshold. This should + # always be unset because it is a new variable, but + # check anyway. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0005"; + } + $temperature_state = "critical"; + $temperature_is = "high"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_variable_value > $high_warning) + { + # Crossed the high warning threshold. This should + # always be unset because it is a new variable, but + # check anyway. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0006"; + } + $temperature_state = "warning"; + $temperature_is = "high"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_variable_value < $low_critical) + { + # Dropped below the low critical threshold. This + # should always be unset because it is a new + # variable, but check anyway. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "critical"; + $message_key = "scan_hpacucli_note_0007"; + } + $temperature_state = "critical"; + $temperature_is = "low"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "temperature_state" => $temperature_state, + "temperature_is" => $temperature_is, + }}); + } + elsif ($new_scan_hpacucli_variable_value < $low_warning) + { + # Crossed the low warning threshold. This should + # always be unset because it is a new variable, but + # check anyway. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + $alert_level = "warning"; + $message_key = "scan_hpacucli_note_0008"; + } + $temperature_state = "warning"; + $temperature_is = "low"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + } + + # Record this for later processing into the 'temperature' + # table. + my $sensor_host_key = "controller:".$scan_hpacucli_controller_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_host_key => $sensor_host_key }}); + + $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_value_c} = $new_scan_hpacucli_variable_value; + $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_state} = $temperature_state; + $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_is} = $temperature_is; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::temperature::${variable}::${sensor_host_key}::temperature_value_c" => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_value_c}, + "new::temperature::${variable}::${sensor_host_key}::temperature_state" => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_state}, + "new::temperature::${variable}::${sensor_host_key}::temperature_is" => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_is}, + }}); + } + + # Send an alert telling the user that we've found a variable for this + # controller. + my $variables = { + sensor_name => $variable, + serial_number => $scan_hpacucli_controller_serial_number, + name => $variable, + value => $type eq "temperature" ? $new_scan_hpacucli_variable_value." °C" : $new_scan_hpacucli_variable_value, + high_critical_temperature => $high_critical." °C", + high_warning_temperature => $high_warning." °C", + low_critical_temperature => $low_critical." °C", + low_warning_temperature => $low_warning." °C", + }; + my $log_level = (($alert_level eq "warning") or ($alert_level eq "critical")) ? 1 : 2; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => $alert_level, + message => $message_key, + variables => $variables, + show_header => 0, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_hpacucli_variables +( + scan_hpacucli_variable_uuid, + scan_hpacucli_variable_host_uuid, + scan_hpacucli_variable_source_table, + scan_hpacucli_variable_source_uuid, + scan_hpacucli_variable_is_temperature, + scan_hpacucli_variable_name, + scan_hpacucli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_hpacucli_controllers', + ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", + ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +);"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + } + } + + # Look for removed controllers + foreach my $scan_hpacucli_controller_uuid (keys %{$anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}}) + { + # Controller vanished! + my $old_scan_hpacucli_controller_serial_number = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_serial_number}; + my $old_scan_hpacucli_controller_model = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_model}; + my $old_scan_hpacucli_controller_status = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_status}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan_hpacucli_controller_uuid" => $scan_hpacucli_controller_uuid, + "old_scan_hpacucli_controller_serial_number" => $old_scan_hpacucli_controller_serial_number, + "old_scan_hpacucli_controller_model" => $old_scan_hpacucli_controller_model, + "old_scan_hpacucli_controller_status" => $old_scan_hpacucli_controller_status, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}; + + # If the old alarm state is already 'VANISHED', ignore it. + next if $old_scan_hpacucli_controller_status eq "VANISHED"; + + # Still here? Alert and UPDATE. + ### NOTE: For now, we're going to use warning level because controllers should never vanish + ### unless one failed. If that is the case, the admin already knows, but this will let + ### other notification targets know that the change has happened. + my $variables = { + model => $old_scan_hpacucli_controller_model, + serial_number => $old_scan_hpacucli_controller_serial_number, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0017", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0017", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_hpacucli_controllers +SET + scan_hpacucli_controller_status = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_controller_uuid = ".$anvil->Database->quote($scan_hpacucli_controller_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + + # Look for removed cache modules + foreach my $scan_hpacucli_cache_module_uuid (keys %{$anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}}) + { + # Controller vanished! + my $old_scan_hpacucli_cache_module_serial_number = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_serial_number}; + my $old_scan_hpacucli_cache_module_status = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_status}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan_hpacucli_cache_module_uuid" => $scan_hpacucli_cache_module_uuid, + "old_scan_hpacucli_cache_module_serial_number" => $old_scan_hpacucli_cache_module_serial_number, + "old_scan_hpacucli_cache_module_status" => $old_scan_hpacucli_cache_module_status, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}; + + # If the old alarm state is already 'VANISHED', ignore it. + next if $old_scan_hpacucli_cache_module_status eq "VANISHED"; + + # Still here? Alert and UPDATE. + ### NOTE: For now, we're going to use warning level because cache_modules should never vanish + ### unless one failed. If that is the case, the admin already knows, but this will let + ### other notification targets know that the change has happened. + my $variables = { + serial_number => $old_scan_hpacucli_cache_module_serial_number, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0018", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_note_0018", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_hpacucli_cache_modules +SET + scan_hpacucli_cache_module_status = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_cache_module_uuid = ".$anvil->Database->quote($scan_hpacucli_cache_module_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + + # Look for removed controller variables. + foreach my $scan_hpacucli_controller_uuid (keys %{$anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}}) + { + # Get the serial numbre for this contrller + my $scan_hpacucli_controller_serial_number = $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan_hpacucli_controller_uuid" => $scan_hpacucli_controller_uuid, + "scan_hpacucli_controller_serial_number" => $scan_hpacucli_controller_serial_number, + }}); + foreach my $type ("detail", "temperature") + { + foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}}) + { + my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value}; + my $old_scan_hpacucli_variable_uuid = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "type" => $type, + "scan_hpacucli_variable_name" => $scan_hpacucli_variable_name, + "old_scan_hpacucli_variable_value" => $old_scan_hpacucli_variable_value, + "old_scan_hpacucli_variable_uuid" => $old_scan_hpacucli_variable_uuid, + }}); + + # If the old alarm state is already 'VANISHED', ignore it. + next if $old_scan_hpacucli_variable_value eq "VANISHED"; + + # Still here? Alert and UPDATE. + ### NOTE: For now, we're going to use warning level because cache_modules + ### should never vanish unless one failed. If that is the case, the + ### admin already knows, but this will let other notification targets + ### know that the change has happened. + my $message_key = $type eq "temperature" ? "scan_hpacucli_note_0019" : "scan_hpacucli_note_0020"; + my $variables = { + serial_number => $scan_hpacucli_controller_serial_number, + name => $scan_hpacucli_variable_name, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => $message_key, + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_hpacucli_variables +SET + scan_hpacucli_variable_value = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_hpacucli_variable_uuid = ".$anvil->Database->quote($old_scan_hpacucli_variable_uuid)." +;"; + # Now record the query in the array + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query; + } + } + } + + # Now commit the changes. + $anvil->Database->write({query => $anvil->data->{'scan-hpacucli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-hpacucli'}{queries} = []; + + return(0); +} + +# This reads in the last scan's data. +sub read_last_scan +{ + my ($anvil) = @_; + + # Read in the controller(s) + my $query = " +SELECT + scan_hpacucli_controller_uuid, + scan_hpacucli_controller_serial_number, + scan_hpacucli_controller_model, + scan_hpacucli_controller_status, + scan_hpacucli_controller_last_diagnostics, + scan_hpacucli_controller_cache_present, + scan_hpacucli_controller_drive_write_cache, + scan_hpacucli_controller_firmware_version, + scan_hpacucli_controller_unsafe_writeback_cache +FROM + scan_hpacucli_controllers +WHERE + scan_hpacucli_controller_host_uuid = ".$anvil->Database->quote($anvil->Get->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, + }}); + foreach my $row (@{$results}) + { + my $scan_hpacucli_controller_uuid = $row->[0]; + my $scan_hpacucli_controller_serial_number = $row->[1]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_controller_uuid => $scan_hpacucli_controller_uuid, + scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number, + }}); + + $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_serial_number} = $scan_hpacucli_controller_serial_number; + $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_model} = $row->[2]; + $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_status} = $row->[3]; + $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_last_diagnostics} = $row->[4]; + $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_cache_present} = $row->[5]; + $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_drive_write_cache} = $row->[6]; + $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_firmware_version} = $row->[7]; + $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_unsafe_writeback_cache} = $row->[8]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_serial_number" => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_serial_number}, + "sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_model" => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_model}, + "sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_status" => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_status}, + "sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_last_diagnostics" => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_last_diagnostics}, + "sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_cache_present" => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_cache_present}, + "sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_drive_write_cache" => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_drive_write_cache}, + "sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_firmware_version" => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_firmware_version}, + "sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_unsafe_writeback_cache" => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_unsafe_writeback_cache}, + }}); + + # Store the information about this controllers + $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number} = $scan_hpacucli_controller_uuid; + $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid} = $scan_hpacucli_controller_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::controllers::by_serial::${scan_hpacucli_controller_serial_number}" => $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}, + "scan-hpacucli::controllers::by_uuid::${scan_hpacucli_controller_uuid}" => $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid}, + }}); + } + undef $results; + undef $count; + + # Now load the cache data + $query = " +SELECT + scan_hpacucli_cache_module_uuid, + scan_hpacucli_cache_module_serial_number, + scan_hpacucli_cache_module_controller_uuid, + scan_hpacucli_cache_module_status, + scan_hpacucli_cache_module_type, + scan_hpacucli_cache_module_size +FROM + scan_hpacucli_cache_modules +WHERE + scan_hpacucli_cache_module_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $scan_hpacucli_cache_module_uuid = $row->[0]; + my $scan_hpacucli_cache_module_serial_number = $row->[1]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_cache_module_uuid => $scan_hpacucli_cache_module_uuid, + scan_hpacucli_cache_module_serial_number => $scan_hpacucli_cache_module_serial_number, + }}); + + # Store the information about this cache_module + $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_controller_uuid} = $row->[2]; + $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_serial_number} = $scan_hpacucli_cache_module_serial_number; + $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_status} = $row->[3]; + $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_type} = $row->[4]; + $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_size} = $row->[5]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_cache_modules::scan_hpacucli_cache_module_uuid::${scan_hpacucli_cache_module_uuid}::scan_hpacucli_cache_module_controller_uuid" => $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_controller_uuid}, + "sql::scan_hpacucli_cache_modules::scan_hpacucli_cache_module_uuid::${scan_hpacucli_cache_module_uuid}::scan_hpacucli_cache_module_serial_number" => $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_serial_number}, + "sql::scan_hpacucli_cache_modules::scan_hpacucli_cache_module_uuid::${scan_hpacucli_cache_module_uuid}::scan_hpacucli_cache_module_status" => $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_status}, + "sql::scan_hpacucli_cache_modules::scan_hpacucli_cache_module_uuid::${scan_hpacucli_cache_module_uuid}::scan_hpacucli_cache_module_type" => $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_type}, + "sql::scan_hpacucli_cache_modules::scan_hpacucli_cache_module_uuid::${scan_hpacucli_cache_module_uuid}::scan_hpacucli_cache_module_size" => $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_size}, + }}); + + $anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$scan_hpacucli_cache_module_serial_number} = $scan_hpacucli_cache_module_uuid; + $anvil->data->{'scan-hpacucli'}{cache_modules}{by_uuid}{$scan_hpacucli_cache_module_uuid} = $scan_hpacucli_cache_module_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::cache_modules::by_serial::${scan_hpacucli_cache_module_serial_number}" => $anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$scan_hpacucli_cache_module_serial_number}, + "scan-hpacucli::cache_modules::by_uuid::${scan_hpacucli_cache_module_uuid}" => $anvil->data->{'scan-hpacucli'}{cache_modules}{by_uuid}{$scan_hpacucli_cache_module_uuid}, + }}); + } + undef $results; + undef $count; + + # The array data... + $query = " +SELECT + scan_hpacucli_array_uuid, + scan_hpacucli_array_name, + scan_hpacucli_array_controller_uuid, + scan_hpacucli_array_type, + scan_hpacucli_array_status, + scan_hpacucli_array_error_message +FROM + scan_hpacucli_arrays +WHERE + scan_hpacucli_array_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $scan_hpacucli_array_uuid = $row->[0]; + my $scan_hpacucli_array_name = $row->[1]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_array_uuid => $scan_hpacucli_array_uuid, + scan_hpacucli_array_name => $scan_hpacucli_array_name, + }}); + + # Store the drive group data. (Drive groups have no SN) + $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_controller_uuid} = $row->[2]; + $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_name} = $scan_hpacucli_array_name; + $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_type} = $row->[3]; + $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_status} = $row->[4]; + $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_error_message} = $row->[5]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_arrays::scan_hpacucli_array_uuid::${scan_hpacucli_array_uuid}::scan_hpacucli_array_controller_uuid" => $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_controller_uuid}, + "sql::scan_hpacucli_arrays::scan_hpacucli_array_uuid::${scan_hpacucli_array_uuid}::scan_hpacucli_array_name" => $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_name}, + "sql::scan_hpacucli_arrays::scan_hpacucli_array_uuid::${scan_hpacucli_array_uuid}::scan_hpacucli_array_type" => $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_type}, + "sql::scan_hpacucli_arrays::scan_hpacucli_array_uuid::${scan_hpacucli_array_uuid}::scan_hpacucli_array_status" => $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_status}, + "sql::scan_hpacucli_arrays::scan_hpacucli_array_uuid::${scan_hpacucli_array_uuid}::scan_hpacucli_array_error_message" => $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_error_message}, + }}); + + # Store the information about this virtual drive. + $anvil->data->{'scan-hpacucli'}{virtual_drives}{by_name}{$scan_hpacucli_array_name} = $scan_hpacucli_array_uuid; + $anvil->data->{'scan-hpacucli'}{virtual_drives}{by_uuid}{$scan_hpacucli_array_uuid} = $scan_hpacucli_array_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::virtual_drives::by_name::${scan_hpacucli_array_name}" => $anvil->data->{'scan-hpacucli'}{virtual_drives}{by_name}{$scan_hpacucli_array_name}, + "scan-hpacucli::virtual_drives::by_uuid::${scan_hpacucli_array_uuid}" => $anvil->data->{'scan-hpacucli'}{virtual_drives}{by_uuid}{$scan_hpacucli_array_uuid}, + }}); + } + undef $results; + undef $count; + + # The drive group data... + $query = " +SELECT + scan_hpacucli_logical_drive_uuid, + scan_hpacucli_logical_drive_name, + scan_hpacucli_logical_drive_array_uuid, + scan_hpacucli_logical_drive_caching, + scan_hpacucli_logical_drive_os_device_name, + scan_hpacucli_logical_drive_type, + scan_hpacucli_logical_drive_raid_level, + scan_hpacucli_logical_drive_size, + scan_hpacucli_logical_drive_strip_size, + scan_hpacucli_logical_drive_stripe_size, + scan_hpacucli_logical_drive_status +FROM + scan_hpacucli_logical_drives +WHERE + scan_hpacucli_logical_drive_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $scan_hpacucli_logical_drive_uuid = $row->[0]; + my $scan_hpacucli_logical_drive_name = $row->[1]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_logical_drive_uuid => $scan_hpacucli_logical_drive_uuid, + scan_hpacucli_logical_drive_name => $scan_hpacucli_logical_drive_name, + }}); + + # Store the logical drive data. (LDs have no SN) + $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_name} = $scan_hpacucli_logical_drive_name; + $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_array_uuid} = $row->[2]; + $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_caching} = $row->[3]; + $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_os_device_name} = $row->[4]; + $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_type} = $row->[5]; + $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_raid_level} = $row->[6]; + $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_size} = $row->[7]; + $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_strip_size} = $row->[8]; + $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_stripe_size} = $row->[9]; + $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_status} = $row->[10]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_array_uuid" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_array_uuid}, + "sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_name" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_name}, + "sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_caching" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_caching}, + "sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_os_device_name" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_os_device_name}, + "sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_type" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_type}, + "sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_raid_level" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_raid_level}, + "sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_size" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_size}, + "sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_strip_size" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_strip_size}, + "sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_stripe_size" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_stripe_size}, + "sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_status" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_status}, + }}); + + # Store the information about this virtual drive. + $anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name} = $scan_hpacucli_logical_drive_uuid; + $anvil->data->{'scan-hpacucli'}{logical_drives}{by_uuid}{$scan_hpacucli_logical_drive_uuid} = $scan_hpacucli_logical_drive_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::logical_drives::by_name::${scan_hpacucli_logical_drive_name}" => $anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name}, + "scan-hpacucli::logical_drives::by_uuid::${scan_hpacucli_logical_drive_uuid}" => $anvil->data->{'scan-hpacucli'}{logical_drives}{by_uuid}{$scan_hpacucli_logical_drive_uuid}, + }}); + } + undef $results; + undef $count; + + # And now, the physical drives. + $query = " +SELECT + scan_hpacucli_physical_drive_uuid, + scan_hpacucli_physical_drive_serial_number, + scan_hpacucli_physical_drive_logical_drive_uuid, + scan_hpacucli_physical_drive_model, + scan_hpacucli_physical_drive_interface, + scan_hpacucli_physical_drive_status, + scan_hpacucli_physical_drive_size, + scan_hpacucli_physical_drive_type, + scan_hpacucli_physical_drive_rpm, + scan_hpacucli_physical_drive_temperature, + scan_hpacucli_physical_drive_last_failure_reason, + scan_hpacucli_physical_drive_port, + scan_hpacucli_physical_drive_box, + scan_hpacucli_physical_drive_bay +FROM + scan_hpacucli_physical_drives +WHERE + scan_hpacucli_physical_drive_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $scan_hpacucli_physical_drive_uuid = $row->[0]; + my $scan_hpacucli_physical_drive_serial_number = $row->[1]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_physical_drive_uuid => $scan_hpacucli_physical_drive_uuid, + scan_hpacucli_physical_drive_serial_number => $scan_hpacucli_physical_drive_serial_number, + }}); + + # Store the information about this physical drive + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_logical_drive_uuid} = $row->[2]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_serial_number} = $scan_hpacucli_physical_drive_serial_number; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_model} = $row->[3]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_interface} = $row->[4]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_status} = $row->[5]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_size} = $row->[6]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_type} = $row->[7]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_rpm} = $row->[8]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_temperature} = $row->[9]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_last_failure_reason} = $row->[10]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_port} = $row->[11]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_box} = $row->[12]; + $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_bay} = $row->[13]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_logical_drive_uuid" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_logical_drive_uuid}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_serial_number" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_serial_number}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_model" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_model}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_interface" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_interface}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_status" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_status}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_size" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_size}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_type" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_type}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_rpm" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_rpm}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_temperature" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_temperature}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_last_failure_reason" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_last_failure_reason}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_port" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_port}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_box" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_box}, + "sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_bay" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_bay}, + }}); + + # Make it so that we can look up the serial number from the drive's UUID and vice versa + $anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number} = $scan_hpacucli_physical_drive_uuid; + $anvil->data->{'scan-hpacucli'}{physical_drives}{by_uuid}{$scan_hpacucli_physical_drive_uuid} = $scan_hpacucli_physical_drive_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::physical_drives::by_serial::${scan_hpacucli_physical_drive_serial_number}" => $anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number}, + "scan-hpacucli::physical_drives::by_uuid::${scan_hpacucli_physical_drive_uuid}" => $anvil->data->{'scan-hpacucli'}{physical_drives}{by_uuid}{$scan_hpacucli_physical_drive_uuid}, + }}); + } + undef $results; + undef $count; + + # Lastly, the variables. + $query = " +SELECT + scan_hpacucli_variable_uuid, + scan_hpacucli_variable_source_table, + scan_hpacucli_variable_source_uuid, + scan_hpacucli_variable_is_temperature, + scan_hpacucli_variable_name, + scan_hpacucli_variable_value +FROM + scan_hpacucli_variables +WHERE + scan_hpacucli_variable_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $scan_hpacucli_variable_uuid = $row->[0]; + my $scan_hpacucli_variable_source_table = $row->[1]; + my $scan_hpacucli_variable_source_uuid = $row->[2]; + my $scan_hpacucli_variable_is_temperature = $row->[3]; + my $scan_hpacucli_variable_name = $row->[4]; + my $scan_hpacucli_variable_value = $row->[5]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_variable_uuid => $scan_hpacucli_variable_uuid, + scan_hpacucli_variable_source_table => $scan_hpacucli_variable_source_table, + scan_hpacucli_variable_source_uuid => $scan_hpacucli_variable_source_uuid, + scan_hpacucli_variable_is_temperature => $scan_hpacucli_variable_is_temperature, + scan_hpacucli_variable_name => $scan_hpacucli_variable_name, + scan_hpacucli_variable_value => $scan_hpacucli_variable_value, + }}); + + # We store these differently for easier reference. Diagnostic data is stored in the special + # 'scan_hpacucli_physical_drive_diagnostics' source. + my $type = "detail"; + if ($scan_hpacucli_variable_source_table eq "scan_hpacucli_physical_drive_diagnostics") + { + $type = "diagnostics"; + } + if ($scan_hpacucli_variable_is_temperature eq "1") + { + $type = "temperature"; + } + $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{$scan_hpacucli_variable_source_table}{source_uuid}{$scan_hpacucli_variable_source_uuid}{$type}{$scan_hpacucli_variable_name} = { + scan_hpacucli_variable_uuid => $scan_hpacucli_variable_uuid, + scan_hpacucli_variable_is_temperature => $scan_hpacucli_variable_is_temperature, + scan_hpacucli_variable_value => $scan_hpacucli_variable_value, + }; + + # Entries are so long that we log the one per variable. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::${scan_hpacucli_variable_source_table}::source_uuid::${scan_hpacucli_variable_source_uuid}::${type}::${scan_hpacucli_variable_name}::scan_hpacucli_variable_uuid" => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{$scan_hpacucli_variable_source_table}{source_uuid}{$scan_hpacucli_variable_source_uuid}{$type}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::${scan_hpacucli_variable_source_table}::source_uuid::${scan_hpacucli_variable_source_uuid}::${type}::${scan_hpacucli_variable_name}::scan_hpacucli_variable_is_temperature" => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{$scan_hpacucli_variable_source_table}{source_uuid}{$scan_hpacucli_variable_source_uuid}{$type}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_is_temperature}, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::${scan_hpacucli_variable_source_table}::source_uuid::${scan_hpacucli_variable_source_uuid}::${type}::${scan_hpacucli_variable_name}::scan_hpacucli_variable_value" => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{$scan_hpacucli_variable_source_table}{source_uuid}{$scan_hpacucli_variable_source_uuid}{$type}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value}, + }}); + } + undef $results; + undef $count; + + # Return the number + return(0); +} + +# This looks for anything other than temperature sensors that will feed into the health of the node. +sub pre_process_health +{ + my ($anvil) = @_; + + # This is to collected data from every sweep. + foreach my $scan_hpacucli_controller_serial_number (sort {$a cmp $b} keys %{$anvil->data->{controller}}) + { + # We don't care about metadata + next if $scan_hpacucli_controller_serial_number eq "metadata"; + + # Controller data + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}}) + { + if (($variable eq "battery_or_capacitor_status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{$variable}) ne "ok")) + { + # BBU/FBU problem, score of 2 + my $health_source_name = "controller:".$scan_hpacucli_controller_serial_number.":data:".$variable; + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }}); + } + elsif (($variable eq "cache_status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{$variable}) ne "ok")) + { + # Cache isn't OK, score of 2 + my $health_source_name = "controller:".$scan_hpacucli_controller_serial_number.":data:".$variable; + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }}); + } + elsif (($variable eq "controller_status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{$variable}) ne "ok")) + { + # The controller isn't OK, this is major, score of 10 + my $health_source_name = "controller:".$scan_hpacucli_controller_serial_number.":data:".$variable; + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 10; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }}); + } + } + + # Array + foreach my $scan_hpacucli_array_name (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}}) + { + # Data + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}}) + { + if (($variable eq "status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{$variable}) ne "ok")) + { + # Something is wrong with this array + my $health_source_name = "controller:".$scan_hpacucli_controller_serial_number.":array:".$scan_hpacucli_array_name.":".$variable; + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 5; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }}); + } + } + + # Logical Drive + foreach my $logical_drive (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}}) + { + # Data + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{data}{detail}}) + { + if (($variable eq "caching") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{data}{detail}{$variable}) ne "enabled")) + { + # Not enabled is going to hurt performance. + my $health_source_name = "controller:".$scan_hpacucli_controller_serial_number.":array:".$scan_hpacucli_array_name.":logical_drive:".$logical_drive.":".$variable; + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }}); + } + elsif (($variable eq "status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{data}{detail}{$variable}) ne "ok")) + { + # If the status isn't OK, it's degraded (or rebuilding, but + # still degraded). + my $health_source_name = "controller:".$scan_hpacucli_controller_serial_number.":array:".$scan_hpacucli_array_name.":logical_drive:".$logical_drive.":".$variable; + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }}); + } + } + + # Physical Disks. + foreach my $port (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}}) + { + foreach my $box (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}}) + { + foreach my $bay (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}}) + { + my $scan_hpacucli_physical_drive_serial_number = $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{serial_number}; + # Data + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}}) + { + next if $variable eq "serial_number"; + next if $variable eq "port"; + next if $variable eq "box"; + next if $variable eq "bay"; + + if (($variable eq "status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{$variable}) ne "ok")) + { + # The drive is failed or is rebuilding. This adds 2. + my $health_source_name = "controller:".$scan_hpacucli_controller_serial_number.":physical_drive:".$scan_hpacucli_physical_drive_serial_number.":data:".$variable; + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }}); + } + } + + # If this was a diagnostics run, check for error + # counters + if ($anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics}) + { + # If the diagnostics don't exist for the + # drive and the drive is OK, it's likely a + # 3rd party drive. If the status is not OK, + # there may not be diagnostic data. + if (exists $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_hard}) + { + # We got the data + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}}) + { + # Store this in the main hash. + if ((($variable eq "hardware_errors") or + ($variable eq "predictive_failure_errors") or + ($variable eq "read_errors_hard") or + ($variable eq "write_errors_hard")) && + ($anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{$variable} =~ /^\d+$/) && + ($anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{$variable} > 0)) + { + # How high is the error count? + my $score = 1; + if ($anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{$variable} > 10) + { + # Eek + $score = 3; + } + elsif ($anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{$variable} > 5) + { + # Getting a little high + $score = 2; + } + my $health_source_name = "controller:".$scan_hpacucli_controller_serial_number.":physical_drive:".$scan_hpacucli_physical_drive_serial_number.":diagnostics:".$variable; + $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = $score; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, + }}); + } + + # Record the diagnostic data + # under the drive's hash. + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{'diagnostics'}{$variable} = $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{$variable}; + } + } + elsif (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{status}) eq "ok") + { + # No data for this drive. It might be + # a 3rd party drive. We'll warn the + # user that we can't predict failure. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":no_diagnostics", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # Warn the user that we can't + # predict this drive's death. + my $variables = { + serial_number => $scan_hpacucli_physical_drive_serial_number, + port => $port, + box => $box, + bay => $bay, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_warning_0001", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_hpacucli_warning_0001", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-hpacucli'}{alert_sort}++, + set_by => $THIS_FILE, + }); + } + } + } + } + } + } + } + } + } + + return(0); +} + +# This gets the basic information about the controller. +sub get_controller_info +{ + my ($anvil, $controller) = @_; + + my $model_name = ""; + my $scan_hpacucli_controller_serial_number = ""; + my $cache_serial_number = ""; + my $scan_hpacucli_physical_drive_serial_number = ""; + my $scan_hpacucli_array_name = ""; + my $logical_drive = ""; + my $port = ""; + my $box = ""; + my $bay = ""; + my $in_array = 0; + my $shell_call = $anvil->data->{path}{exe}{hpacucli}." controller slot=".$controller." show config detail"; + my ($output, $return_code) = $anvil->System->call({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) + { + $line = $anvil->Words->clean_spaces({string => $line}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + if ((not $scan_hpacucli_controller_serial_number) && ($line =~ /^(.*?) in Slot $controller /)) + { + $model_name = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { model_name => $model_name }}); + } + + if (($line =~ /^Serial Number: (.*?)$/) && (not $port) && (not $box) && (not $bay)) + { + $scan_hpacucli_controller_serial_number = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number }}); + + # Record the model number + if ($model_name) + { + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{model_name} = $model_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::${scan_hpacucli_controller_serial_number}::data::detail::model_name" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{model_name}, + }}); + } + + # Make a reference between the slot and SN + $anvil->data->{controller}{metadata}{sn_to_slot}{$scan_hpacucli_controller_serial_number} = $controller; + $anvil->data->{controller}{metadata}{slot_to_sn}{$controller} = $scan_hpacucli_controller_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::metadata::sn_to_slot::${scan_hpacucli_controller_serial_number}" => $anvil->data->{controller}{metadata}{sn_to_slot}{$scan_hpacucli_controller_serial_number}, + "controller::metadata::slot_to_sn::${controller}" => $anvil->data->{controller}{metadata}{slot_to_sn}{$controller}, + }}); + next; + } + next if not $scan_hpacucli_controller_serial_number; + + if ($line =~ /Cache Serial Number: (.*?)$/i) + { + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{cache_serial_number} = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::${scan_hpacucli_controller_serial_number}::data::detail::cache_serial_number" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{cache_serial_number}, + }}); + next; + } + + if ($line =~ /Array: (.*?)$/i) + { + $scan_hpacucli_array_name = $1; + $in_array = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_array_name => $scan_hpacucli_array_name, + in_array => $in_array, + }}); + next; + } + + if ($line =~ /Logical Drive: (.*?)$/i) + { + $logical_drive = $1; + $in_array = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + logical_drive => $logical_drive, + in_array => $in_array, + }}); + next; + } + + if ($line =~ /physicaldrive (.*?):(.*?):(.*)$/) + { + $port = $1; + $box = $2; + $bay = $3; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + port => $port, + box => $box, + bay => $bay, + }}); + next; + } + elsif (($port) && (($line eq "Drive Type: Data") or ($line =~ /^Mirror Group \d+:$/))) + { + $port = ""; + $box = ""; + $bay = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + port => $port, + box => $box, + bay => $bay, + }}); + } + + if (lc($line) eq "unassigned") + { + $scan_hpacucli_array_name = "ZZZZ"; + $logical_drive = "9999"; + $port = ""; + $box = ""; + $bay = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_hpacucli_array_name => $scan_hpacucli_array_name, + logical_drive => $logical_drive, + port => $port, + box => $box, + bay => $bay, + }}); + next; + } + + # Lines I don't care about + next if $line =~ /^Slot: $controller$/i; + + my $type = "detail"; + if ($line =~ /^(.*?): (.*)$/) + { + my $variable = $1; + my $value = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + + # If the variable has units, pull them out. + if ($variable =~ / \(C\)$/i) + { + $variable =~ s/ \(C\)$//i; + $variable = $anvil->Words->clean_spaces({string => $variable}); + $type = "temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + type => $type, + }}); + } + elsif ($variable =~ / \(F\)/i) + { + # Covert to °C + $variable =~ s/ \(F\)$//i; + $variable = $anvil->Words->clean_spaces({string => $variable}); + $value = $anvil->Convert->fahrenheit_to_celsius({temperature => $value}); + $type = "temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + type => $type, + }}); + } + elsif (($value =~ /^\d+ \wB$/) or ($value =~ /^\d+\.\d+ \wB$/)) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + ">> value" => $value, + }}); + if (($variable eq "Total Cache Size") or + ($variable eq "Total Cache Memory Available") or + ($variable eq "Strip Size") or + ($variable eq "Size") or + ($variable eq "Full Stripe Size")) + { + # HP reports in MB, etc, but means MiB. + $value = $anvil->Convert->human_readable_to_bytes({size => $value, base2 => 1}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + "<< value" => $value, + }}); + } + } + + # Save it. + if (exists $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{$type}{$variable}) + { + # Conflict! This is a dirty way to keep them separate + $variable .= " 2"; + } + + $variable = process_variable_name($anvil, $variable); + + # What am I saving? + if (($port) && ($box) && ($bay)) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "line" => $line, + }}); + + # Physical drive info + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{$type}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::${scan_hpacucli_controller_serial_number}::array::${scan_hpacucli_array_name}::logical_drive::${logical_drive}::physical_drive::port::${port}::box::${box}::bay::${bay}::${type}::$variable" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{$type}{$variable}, + }}); + + # Map the SN to it's current location. + if ($line =~ /Serial Number: (.*?)$/) + { + $scan_hpacucli_physical_drive_serial_number = $1; + my $location = $port.":".$box.":".$bay; + $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number} = { + array => $scan_hpacucli_array_name, + logical_drive => $logical_drive, + port => $port, + box => $box, + bay => $bay, + }; + $anvil->data->{physical_drive}{by_location}{$location} = $scan_hpacucli_physical_drive_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "physical_drive::by_serial_number::${scan_hpacucli_physical_drive_serial_number}::array" => $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number}{array}, + "physical_drive::by_serial_number::${scan_hpacucli_physical_drive_serial_number}::logical_drive" => $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number}{logical_drive}, + "physical_drive::by_serial_number::${scan_hpacucli_physical_drive_serial_number}::port" => $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number}{port}, + "physical_drive::by_serial_number::${scan_hpacucli_physical_drive_serial_number}::box" => $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number}{box}, + "physical_drive::by_serial_number::${scan_hpacucli_physical_drive_serial_number}::bay" => $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number}{bay}, + "physical_drive::by_location::$location" => $anvil->data->{physical_drive}{by_location}{$location}, + }}); + } + } + elsif ($logical_drive) + { + # Logical drive + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{data}{$type}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::${scan_hpacucli_controller_serial_number}::array::${scan_hpacucli_array_name}::logical_drive::${logical_drive}::data::${type}::$variable" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{data}{$type}{$variable}, + }}); + } + elsif ($scan_hpacucli_array_name) + { + # Array + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{$type}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::${scan_hpacucli_controller_serial_number}::array::${scan_hpacucli_array_name}::data::${type}::$variable" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{$type}{$variable}, + }}); + } + else + { + # Controller data + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::${scan_hpacucli_controller_serial_number}::data::${type}::$variable" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}, + }}); + } + } + elsif ($in_array) + { + # Messages about a degraded array can be here. + # ie: "One of the drives on this array have failed or has been removed." + if ($line =~ /this array have failed/) + { + # We'll concatonate in case there are multiple errors. + if (not exists $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message}) + { + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message} = ""; + } + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message} .= $line."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::${scan_hpacucli_controller_serial_number}::array::${scan_hpacucli_array_name}::data::detail::error_message" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message}, + }}); + } + } + + } + + # If I didn't find a serial number, something went wrong. + if (not $scan_hpacucli_controller_serial_number) + { + # Error out. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_hpacucli_error_0004", variables => { controller => $controller }}); + $anvil->nice_exit({exit_code => 6}); + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number }}); + return($scan_hpacucli_controller_serial_number); +} + +# This will do a details diagnostics check, if enough time has passed. +sub get_diagnostics +{ + my ($anvil, $controller) = @_; + + # Every 'scan-hpacucli::diagnostics_interval' seconds, run a full diagnostics to check for drives in + # pre-failure. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::process_diagnostics" => $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics} }}); + if (not $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics}) + { + # Is it time? + my $query = "SELECT scan_hpacucli_controller_last_diagnostics FROM scan_hpacucli_controllers WHERE scan_hpacucli_controller_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + # The actual query -----------------. .------- Row 0 + # Query this DB --. | | .-- Columns 0 + my $last_diagnostics = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $last_diagnostics = 0 if not defined $last_diagnostics; + my $current_time = time; + my $last_scan_was = $current_time - $last_diagnostics; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + last_diagnostics => $last_diagnostics, + current_time => $current_time, + last_scan_was => $last_scan_was, + "scan-hpacucli::diagnostics_interval" => $anvil->data->{'scan-hpacucli'}{diagnostics_interval}, + }}); + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::diagnostics_interval" => $last_diagnostics, + }}); + if ($anvil->data->{'scan-hpacucli'}{diagnostics_interval} !~ /^\d+$/) + { + # Invalid value, override. + $anvil->data->{'scan-hpacucli'}{diagnostics_interval} = 1800; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-hpacucli::diagnostics_interval" => $anvil->data->{'scan-hpacucli'}{diagnostics_interval}, + }}); + } + if ($last_scan_was > $anvil->data->{'scan-hpacucli'}{diagnostics_interval}) + { + $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sys::process_diagnostics" => $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics}, + }}); + } + } + + # Well, is it? + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sys::process_diagnostics" => $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics}, + }}); + if ($anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics}) + { + # Yup! We use hpacucli's diagnostics to gather all data. + my $shell_call = " +cd /tmp/ +".$anvil->data->{path}{exe}{hpacucli}." controller slot=".$controller." diag file=/tmp/ADUReport.zip +".$anvil->data->{path}{exe}{'unzip'}." -o /tmp/ADUReport.zip -d /tmp/ +if [ -e '/tmp/ADUReport.xml' ]; +then + ".$anvil->data->{path}{exe}{rm}." -f /tmp/ADUReport.zip + ".$anvil->data->{path}{exe}{rm}." -f /tmp/ADUReport.htm + ".$anvil->data->{path}{exe}{rm}." -f /tmp/ADUReport.xml + ".$anvil->data->{path}{exe}{rm}." -f /tmp/report.checksum +fi +"; + # Write a log message to warn the user that we're starting a long process. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_log_0003", variables => { shell_call => $shell_call }}); + my ($output, $return_code) = $anvil->System->call({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 }}); + } + undef $output; + undef $return_code; + + # Did it work? + if (not -r "/tmp/ADUReport.txt") + { + # Something went wrong. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_hpacucli_error_0005", variables => { path => "/tmp/ADUReport.txt" }}); + $anvil->nice_exit({exit_code => 4}); + } + + # Get this controller's serial number + my $scan_hpacucli_controller_serial_number = $anvil->data->{controller}{metadata}{slot_to_sn}{$controller}; + + # Parse! + my $in_cache_config_status = 0; + my $in_physical_drive = 0; + my $scan_hpacucli_physical_drive_serial_number = ""; + my $port = ""; + my $box = ""; + my $bay = ""; + my $skip_blank_line = 0; + $shell_call = "/tmp/ADUReport.txt"; + ($output, $return_code) = $anvil->System->call({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) + { + $line = $anvil->Words->clean_spaces({string => $line}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + if (not $line) + { + if ($skip_blank_line) + { + next; + } + $in_cache_config_status = 0; + $in_physical_drive = 0; + $scan_hpacucli_physical_drive_serial_number = ""; + $port = ""; + $box = ""; + $bay = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + in_cache_config_status => $in_cache_config_status, + in_physical_drive => $in_physical_drive, + scan_hpacucli_physical_drive_serial_number => $scan_hpacucli_physical_drive_serial_number, + port => $port, + box => $box, + bay => $bay, + }}); + next; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + $skip_blank_line = 0; + + if ($line =~ /: Cache Config Status$/i) + { + $in_cache_config_status = 1; + $skip_blank_line = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_cache_config_status => $in_cache_config_status }}); + next; + } + + if ($line =~ /: Physical Drive \(.*?\) (.*?):(.*?):(.*?) : Monitor and Performance Statistics \(Since Factory\)/) + { + $port = $1; + $box = $2; + $bay = $3; + $skip_blank_line = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + port => $port, + box => $box, + bay => $bay, + }}); + } + + if ($in_cache_config_status) + { + if ($line =~ /Parity Read Errors (\d+) \(/) + { + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{'diagnostics'}{cache}{parity_read_errors} = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::${scan_hpacucli_controller_serial_number}::diagnostics::cache::parity_read_errors" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{'diagnostics'}{cache}{parity_read_errors}, + }}); + } + if ($line =~ /Parity Write Errors (\d+) \(/) + { + $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{'diagnostics'}{cache}{parity_write_errors} = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::${scan_hpacucli_controller_serial_number}::diagnostics::cache::parity_write_errors" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{'diagnostics'}{cache}{parity_write_errors}, + }}); + } + } + + if (($port) && ($box) && ($bay)) + { + my $location = $port.":".$box.":".$bay; + $scan_hpacucli_physical_drive_serial_number = $anvil->data->{physical_drive}{by_location}{$location}; + + if ($line =~ /Read Errors Hard (0x.*?)$/) + { + my $hex = $1; + $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_hard} = hex($hex); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "hex" => $hex, + "physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::read_errors_hard" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_hard}, + }}); + } + if ($line =~ /Read Errors Retry Recovered (0x.*?)$/) + { + my $hex = $1; + $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_retry_recovered} = hex($hex); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "hex" => $hex, + "physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::read_errors_retry_recovered" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_retry_recovered}, + }}); + } + if ($line =~ /Read Errors ECC Corrected (0x.*?)$/) + { + my $hex = $1; + $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_ecc_corrected} = hex($hex); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "hex" => $hex, + "physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::read_errors_ecc_corrected" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_ecc_corrected}, + }}); + } + if ($line =~ /Write Errors Hard (0x.*?)$/) + { + my $hex = $1; + $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_hard} = hex($hex); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "hex" => $hex, + "physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::write_errors_hard" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_hard}, + }}); + } + if ($line =~ /Write Errors Retry Recovered (0x.*?)$/) + { + my $hex = $1; + $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_retry_recovered} = hex($hex); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "hex" => $hex, + "physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::write_errors_retry_recovered" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_retry_recovered}, + }}); + } + if ($line =~ /Format Errors (0x.*?)$/) + { + my $hex = $1; + $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{format_errors} = hex($hex); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "hex" => $hex, + "physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::format_errors" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{format_errors}, + }}); + } + if ($line =~ /Write Errors After Remap (0x.*?)$/) + { + my $hex = $1; + $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_after_remap} = hex($hex); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "hex" => $hex, + "physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::write_errors_after_remap" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_after_remap}, + }}); + } + if ($line =~ /Hardware Errors (0x.*?)$/) + { + my $hex = $1; + $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{hardware_errors} = hex($hex); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "hex" => $hex, + "physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::hardware_errors" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{hardware_errors}, + }}); + } + if ($line =~ /Predictive Failure Errors (0x.*?)$/) + { + my $hex = $1; + $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{predictive_failure_errors} = hex($hex); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "hex" => $hex, + "physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::predictive_failure_errors" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{predictive_failure_errors}, + }}); + } + } + } + } + + return(0); +} + +# This gathers the various data from the controller(s). +sub gather_data +{ + my ($anvil) = @_; + + ### TODO: This assumes the controllers go 0, 1, ... n. If this is wrong, we'll need to call + ### 'hpacucli controller all show' and parse the output as our outer loop. + # Loops through reach found controller. + foreach my $count (1..$anvil->data->{'scan-hpacucli'}{sys}{controller_count}) + { + my $controller = $count - 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { controller => $controller }}); + + # Read in controller data. + my $scan_hpacucli_controller_serial_number = get_controller_info($anvil, $controller); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number }}); + + get_diagnostics($anvil, $controller); + } + + return(0); +} + +# This processes variable names to flatten them and remove spaces and special characters. +sub process_variable_name +{ + my ($anvil, $variable) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< variable" => $variable }}); + + $variable = lc($variable); + $variable =~ s/ /_/g; + $variable =~ s/-/_/g; + $variable =~ s/&/and/g; + $variable =~ s/\//_or_/g; + $variable =~ s/_%/_percent/g; + $variable =~ s/{_}+/_/g; + $variable =~ s/^_+//g; + $variable =~ s/_+$//g; + $variable =~ s/(\w)\(/$1_\(/; + $variable =~ s/\((.*?)\)/-_$1/g; + $variable =~ s/_+/_/g; + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ">> variable" => $variable }}); + return($variable); +} + +# This does two things; It checks to see if hpacucli is installed (exits '1' if not, exits '2' if not +# executable) and then checks to see if any controllers are found in the system (exits '3' if not). +sub find_hp_controllers +{ + my ($anvil) = @_; + + + # This will keep track of how many controllers we find. + my $controller_count = 0; + + # First, do we have hpacucli installed? + if (not -e $anvil->data->{path}{exe}{hpacucli}) + { + # Nope, exit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "scan_hpacucli_error_0001", variables => { path => $anvil->data->{path}{exe}{hpacucli} }}); + $anvil->nice_exit({exit_code => 1}); + } + + # Make sure it is executable + if (not -x $anvil->data->{path}{exe}{hpacucli}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_hpacucli_error_0002", variables => { path => $anvil->data->{path}{exe}{hpacucli} }}); + $anvil->nice_exit({exit_code => 2}); + } + + # Still alive? Good! Look for controllers now. + my $shell_call = $anvil->data->{path}{exe}{hpacucli}." controller all show"; + my ($output, $return_code) = $anvil->System->call({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 ($line =~ /.*? Slot (\d+) .*?\(sn: (.*?)\)/i) + { + my $controller_number = $1; + my $controller_serial_number = $2; + $controller_count++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + controller_number => $controller_number, + controller_serial_number => $controller_serial_number, + controller_count => $controller_count, + }}); + } + } + + # Have we any controllers? + if ($controller_count > 0) + { + $anvil->data->{'scan-hpacucli'}{sys}{controller_count} = $controller_count; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "scan_hpacucli_log_0001", variables => { count => $anvil->data->{'scan-hpacucli'}{sys}{controller_count} }}); + } + else + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_hpacucli_error_0003", variables => { path => $anvil->data->{path}{exe}{hpacucli} }}); + $anvil->nice_exit({exit_code => 3}); + } + + return(0); +} diff --git a/scancore-agents/scan-hpacucli/scan-hpacucli.sql b/scancore-agents/scan-hpacucli/scan-hpacucli.sql new file mode 100644 index 00000000..1ad36f82 --- /dev/null +++ b/scancore-agents/scan-hpacucli/scan-hpacucli.sql @@ -0,0 +1,572 @@ +-- This is the database schema for the 'hpacucli Scan Agent'. +-- +-- Things that change rarely should go in the main tables (even if we won't explicitely watch for them +-- to change with specific alerts). + +-- ------------------------------------------------------------------------------------------------------- -- +-- Adapter -- +-- ------------------------------------------------------------------------------------------------------- -- + +-- Controller; +-- - Temperature; controller_temperature: [85 °C] +-- - Data; model_name: [Smart Array P420i] +-- - Data; cache_board_present: [True] +-- - Data; controller_status: [OK] +-- - Data; drive_write_cache: [Disabled] +-- - Data; firmware_version: [8.00] +-- - Data; no_battery_write_cache: [Disabled] +-- +-- Ignore; +-- - Data; battery_or_capacitor_count: [1] +-- - Data; degraded_performance_optimization: [Disabled] +-- - Data; elevator_sort: [Enabled] +-- - Data; expand_priority: [Medium] +-- - Data; hardware_revision: [B] +-- - Data; inconsistency_repair_policy: [Disabled] +-- - Data; monitor_and_performance_delay: [60 min] +-- - Data; post_prompt_timeout: [0 secs] +-- - Data; queue_depth: [Automatic] +-- - Data; raid_6_-_adg_status: [Enabled] +-- - Data; rebuild_priority: [Medium] +-- - Data; sata_ncq_supported: [True] +-- - Data; spare_activation_mode: [Activate on drive failure] +-- - Data; surface_analysis_inconsistency_notification: [Disabled] +-- - Data; surface_scan_delay: [15 secs] +-- - Data; surface_scan_mode: [Idle] +-- - Data; wait_for_cache_room: [Disabled] +-- - Data; cache_ratio: [10% Read / 90% Write] +-- - Data; total_cache_memory_available: [816 MB] + + +-- Here is the basic controller information. All connected devices will reference back to this table's +-- 'scan_hpacucli_controller_serial_number' column. +CREATE TABLE scan_hpacucli_controllers ( + scan_hpacucli_controller_uuid uuid not null primary key, + scan_hpacucli_controller_host_uuid uuid not null, + scan_hpacucli_controller_serial_number text not null, -- This is the core identifier + scan_hpacucli_controller_model text not null, -- + scan_hpacucli_controller_status text not null, -- + scan_hpacucli_controller_last_diagnostics numeric not null, -- Collecting diagnostics information is very expensive, so we do it once every hour (or whatever the user chooses). + scan_hpacucli_controller_cache_present text not null, -- "yes" or "no" + scan_hpacucli_controller_drive_write_cache text not null, -- "enabled" or "disabled" + scan_hpacucli_controller_firmware_version text not null, -- + scan_hpacucli_controller_unsafe_writeback_cache text not null, -- "enabled" or "disabled" + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_hpacucli_controller_host_uuid) REFERENCES hosts(host_uuid) +); +ALTER TABLE scan_hpacucli_controllers OWNER TO admin; + +CREATE TABLE history.scan_hpacucli_controllers ( + history_id bigserial, + scan_hpacucli_controller_uuid uuid, + scan_hpacucli_controller_host_uuid uuid, + scan_hpacucli_controller_serial_number text, + scan_hpacucli_controller_model text, + scan_hpacucli_controller_status text, + scan_hpacucli_controller_last_diagnostics numeric, + scan_hpacucli_controller_cache_present text, + scan_hpacucli_controller_drive_write_cache text, + scan_hpacucli_controller_firmware_version text, + scan_hpacucli_controller_unsafe_writeback_cache text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_hpacucli_controllers OWNER TO admin; + +CREATE FUNCTION history_scan_hpacucli_controllers() RETURNS trigger +AS $$ +DECLARE + history_scan_hpacucli_controllers RECORD; +BEGIN + SELECT INTO history_scan_hpacucli_controllers * FROM scan_hpacucli_controllers WHERE scan_hpacucli_controller_uuid=new.scan_hpacucli_controller_uuid; + INSERT INTO history.scan_hpacucli_controllers + (scan_hpacucli_controller_uuid, + scan_hpacucli_controller_host_uuid, + scan_hpacucli_controller_serial_number, + scan_hpacucli_controller_model, + scan_hpacucli_controller_status, + scan_hpacucli_controller_last_diagnostics, + scan_hpacucli_controller_cache_present, + scan_hpacucli_controller_drive_write_cache, + scan_hpacucli_controller_firmware_version, + scan_hpacucli_controller_unsafe_writeback_cache, + modified_date) + VALUES + (history_scan_hpacucli_controllers.scan_hpacucli_controller_uuid, + history_scan_hpacucli_controllers.scan_hpacucli_controller_host_uuid, + history_scan_hpacucli_controllers.scan_hpacucli_controller_serial_number, + history_scan_hpacucli_controllers.scan_hpacucli_controller_model, + history_scan_hpacucli_controllers.scan_hpacucli_controller_status, + history_scan_hpacucli_controllers.scan_hpacucli_controller_last_diagnostics, + history_scan_hpacucli_controllers.scan_hpacucli_controller_cache_present, + history_scan_hpacucli_controllers.scan_hpacucli_controller_drive_write_cache, + history_scan_hpacucli_controllers.scan_hpacucli_controller_firmware_version, + history_scan_hpacucli_controllers.scan_hpacucli_controller_unsafe_writeback_cache, + history_scan_hpacucli_controllers.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_hpacucli_controllers() OWNER TO admin; + +CREATE TRIGGER trigger_scan_hpacucli_controllers + AFTER INSERT OR UPDATE ON scan_hpacucli_controllers + FOR EACH ROW EXECUTE PROCEDURE history_scan_hpacucli_controllers(); + + +-- Cache; +-- - Temperature; cache_module_temperature: [37 °C] +-- - Temperature; capacitor_temperature: [25 °C] +-- - Data; cache_serial_number +-- - Data; cache_status: [OK] +-- - Data; battery_or_capacitor_status: [OK] +-- - Data; cache_backup_power_source: [Capacitors] +-- - Data; total_cache_size: [1024 MB] + +-- This table is used for BBU and FBU caching. +CREATE TABLE scan_hpacucli_cache_modules ( + scan_hpacucli_cache_module_uuid uuid not null primary key, + scan_hpacucli_cache_module_host_uuid uuid not null, + scan_hpacucli_cache_module_controller_uuid uuid not null, -- The controller this module is connected to + scan_hpacucli_cache_module_serial_number text not null, + scan_hpacucli_cache_module_status text not null, + scan_hpacucli_cache_module_type text not null, + scan_hpacucli_cache_module_size numeric not null, -- In bytes + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_hpacucli_cache_module_host_uuid) REFERENCES hosts(host_uuid), + FOREIGN KEY(scan_hpacucli_cache_module_controller_uuid) REFERENCES scan_hpacucli_controllers(scan_hpacucli_controller_uuid) +); +ALTER TABLE scan_hpacucli_cache_modules OWNER TO admin; + +CREATE TABLE history.scan_hpacucli_cache_modules ( + history_id bigserial, + scan_hpacucli_cache_module_uuid uuid, + scan_hpacucli_cache_module_host_uuid uuid, + scan_hpacucli_cache_module_controller_uuid uuid, + scan_hpacucli_cache_module_serial_number text, + scan_hpacucli_cache_module_status text, + scan_hpacucli_cache_module_type text, + scan_hpacucli_cache_module_size numeric, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_hpacucli_cache_modules OWNER TO admin; + +CREATE FUNCTION history_scan_hpacucli_cache_modules() RETURNS trigger +AS $$ +DECLARE + history_scan_hpacucli_cache_modules RECORD; +BEGIN + SELECT INTO history_scan_hpacucli_cache_modules * FROM scan_hpacucli_cache_modules WHERE scan_hpacucli_cache_module_uuid=new.scan_hpacucli_cache_module_uuid; + INSERT INTO history.scan_hpacucli_cache_modules + (scan_hpacucli_cache_module_uuid, + scan_hpacucli_cache_module_host_uuid, + scan_hpacucli_cache_module_controller_uuid, + scan_hpacucli_cache_module_serial_number, + scan_hpacucli_cache_module_status, + scan_hpacucli_cache_module_type, + scan_hpacucli_cache_module_size, + modified_date) + VALUES + (history_scan_hpacucli_cache_modules.scan_hpacucli_cache_module_uuid, + history_scan_hpacucli_cache_modules.scan_hpacucli_cache_module_host_uuid, + history_scan_hpacucli_cache_modules.scan_hpacucli_cache_module_controller_uuid, + history_scan_hpacucli_cache_modules.scan_hpacucli_cache_module_serial_number, + history_scan_hpacucli_cache_modules.scan_hpacucli_cache_module_status, + history_scan_hpacucli_cache_modules.scan_hpacucli_cache_module_type, + history_scan_hpacucli_cache_modules.scan_hpacucli_cache_module_size, + history_scan_hpacucli_cache_modules.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_hpacucli_cache_modules() OWNER TO admin; + +CREATE TRIGGER trigger_scan_hpacucli_cache_modules + AFTER INSERT OR UPDATE ON scan_hpacucli_cache_modules + FOR EACH ROW EXECUTE PROCEDURE history_scan_hpacucli_cache_modules(); + + +-- - Array: [A] +-- - Data; array_type: [Data] +-- - Data; interface_type: [SAS] +-- - Data; status: [OK] +-- - Data; unused_space: [0 MB] + +-- NOTE: 'ZZZZ' is a fake array used for unallocated disks +-- This stores information about arrays. +CREATE TABLE scan_hpacucli_arrays ( + scan_hpacucli_array_uuid uuid not null primary key, + scan_hpacucli_array_host_uuid uuid not null, + scan_hpacucli_array_controller_uuid uuid not null, -- The controller this array is connected to + scan_hpacucli_array_name text not null, + scan_hpacucli_array_type text not null, + scan_hpacucli_array_status text not null, + scan_hpacucli_array_error_message text not null, + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_hpacucli_array_host_uuid) REFERENCES hosts(host_uuid), + FOREIGN KEY(scan_hpacucli_array_controller_uuid) REFERENCES scan_hpacucli_controllers(scan_hpacucli_controller_uuid) +); +ALTER TABLE scan_hpacucli_arrays OWNER TO admin; + +CREATE TABLE history.scan_hpacucli_arrays ( + history_id bigserial, + scan_hpacucli_array_uuid uuid, + scan_hpacucli_array_host_uuid uuid, + scan_hpacucli_array_controller_uuid uuid, + scan_hpacucli_array_name text, + scan_hpacucli_array_type text, + scan_hpacucli_array_status text, + scan_hpacucli_array_error_message text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_hpacucli_arrays OWNER TO admin; + +CREATE FUNCTION history_scan_hpacucli_arrays() RETURNS trigger +AS $$ +DECLARE + history_scan_hpacucli_arrays RECORD; +BEGIN + SELECT INTO history_scan_hpacucli_arrays * FROM scan_hpacucli_arrays WHERE scan_hpacucli_array_uuid=new.scan_hpacucli_array_uuid; + INSERT INTO history.scan_hpacucli_arrays + (scan_hpacucli_array_uuid, + scan_hpacucli_array_host_uuid, + scan_hpacucli_array_controller_uuid, + scan_hpacucli_array_name, + scan_hpacucli_array_type, + scan_hpacucli_array_status, + scan_hpacucli_array_error_message, + modified_date) + VALUES + (history_scan_hpacucli_arrays.scan_hpacucli_array_uuid, + history_scan_hpacucli_arrays.scan_hpacucli_array_host_uuid, + history_scan_hpacucli_arrays.scan_hpacucli_array_controller_uuid, + history_scan_hpacucli_arrays.scan_hpacucli_array_name, + history_scan_hpacucli_arrays.scan_hpacucli_array_type, + history_scan_hpacucli_arrays.scan_hpacucli_array_status, + history_scan_hpacucli_arrays.scan_hpacucli_array_error_message, + history_scan_hpacucli_arrays.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_hpacucli_arrays() OWNER TO admin; + +CREATE TRIGGER trigger_scan_hpacucli_arrays + AFTER INSERT OR UPDATE ON scan_hpacucli_arrays + FOR EACH ROW EXECUTE PROCEDURE history_scan_hpacucli_arrays(); + + +-- - Logical Drive: [1] +-- - Data; caching: [Enabled] +-- - Data; cylinders: [65535] +-- - Data; disk_name: [/dev/sda] +-- - Data; drive_type: [Data] +-- - Data; fault_tolerance: [RAID 5] +-- - Data; full_stripe_size: [1280 KB] +-- - Data; heads: [255] +-- - Data; logical_drive_label: [A595BA15001438030E9B24025C4] +-- - Data; mount_points: [/boot 512 MB, / 679.0 GB] +-- - Data; os_status: [LOCKED] +-- - Data; parity_initialization_status: [Initialization Completed] +-- - Data; sectors_per_track: [32] +-- - Data; size: [683.5 GB] +-- - Data; status: [OK] +-- - Data; strip_size: [256 KB] +-- - Data; unique_identifier: [600508B1001C1300C1A2BCEE4BF97677] + +-- NOTE: The logical drive '9999' is a fake LD for unallocated disks +-- This stores information about arrays. +CREATE TABLE scan_hpacucli_logical_drives ( + scan_hpacucli_logical_drive_uuid uuid not null primary key, + scan_hpacucli_logical_drive_host_uuid uuid not null, + scan_hpacucli_logical_drive_array_uuid uuid not null, -- The array this logical_drive is connected to + scan_hpacucli_logical_drive_name text not null, + scan_hpacucli_logical_drive_caching text not null, + scan_hpacucli_logical_drive_os_device_name text not null, + scan_hpacucli_logical_drive_type text not null, + scan_hpacucli_logical_drive_raid_level text not null, + scan_hpacucli_logical_drive_size numeric not null, -- in bytes + scan_hpacucli_logical_drive_strip_size numeric not null, -- in bytes + scan_hpacucli_logical_drive_stripe_size numeric not null, -- in bytes + scan_hpacucli_logical_drive_status text not null, + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_hpacucli_logical_drive_host_uuid) REFERENCES hosts(host_uuid), + FOREIGN KEY(scan_hpacucli_logical_drive_array_uuid) REFERENCES scan_hpacucli_arrays(scan_hpacucli_array_uuid) +); +ALTER TABLE scan_hpacucli_logical_drives OWNER TO admin; + +CREATE TABLE history.scan_hpacucli_logical_drives ( + history_id bigserial, + scan_hpacucli_logical_drive_uuid uuid, + scan_hpacucli_logical_drive_host_uuid uuid, + scan_hpacucli_logical_drive_array_uuid uuid, + scan_hpacucli_logical_drive_name text, + scan_hpacucli_logical_drive_caching text, + scan_hpacucli_logical_drive_os_device_name text, + scan_hpacucli_logical_drive_type text, + scan_hpacucli_logical_drive_raid_level text, + scan_hpacucli_logical_drive_size numeric, + scan_hpacucli_logical_drive_strip_size numeric, + scan_hpacucli_logical_drive_stripe_size numeric, + scan_hpacucli_logical_drive_status text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_hpacucli_logical_drives OWNER TO admin; + +CREATE FUNCTION history_scan_hpacucli_logical_drives() RETURNS trigger +AS $$ +DECLARE + history_scan_hpacucli_logical_drives RECORD; +BEGIN + SELECT INTO history_scan_hpacucli_logical_drives * FROM scan_hpacucli_logical_drives WHERE scan_hpacucli_logical_drive_uuid=new.scan_hpacucli_logical_drive_uuid; + INSERT INTO history.scan_hpacucli_logical_drives + (scan_hpacucli_logical_drive_uuid, + scan_hpacucli_logical_drive_host_uuid, + scan_hpacucli_logical_drive_array_uuid, + scan_hpacucli_logical_drive_name, + scan_hpacucli_logical_drive_caching, + scan_hpacucli_logical_drive_os_device_name, + scan_hpacucli_logical_drive_type, + scan_hpacucli_logical_drive_raid_level, + scan_hpacucli_logical_drive_size, + scan_hpacucli_logical_drive_strip_size, + scan_hpacucli_logical_drive_stripe_size, + scan_hpacucli_logical_drive_status, + modified_date) + VALUES + (history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_uuid, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_host_uuid, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_array_uuid, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_name, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_caching, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_os_device_name, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_type, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_raid_level, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_size, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_strip_size, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_stripe_size, + history_scan_hpacucli_logical_drives.scan_hpacucli_logical_drive_status, + history_scan_hpacucli_logical_drives.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_hpacucli_logical_drives() OWNER TO admin; + +CREATE TRIGGER trigger_scan_hpacucli_logical_drives + AFTER INSERT OR UPDATE ON scan_hpacucli_logical_drives + FOR EACH ROW EXECUTE PROCEDURE history_scan_hpacucli_logical_drives(); + + + +-- - Physical Drive: [1I:1:1], sn: [6XM4E1R60000M528BGFK] +-- - Temperature; current_temperature: [31 °C] +-- - Temperature; maximum_temperature: [40 °C] +-- - Data; drive_type: [Data Drive] +-- - Data; size: [146 GB] +-- - Data; status: [OK] +-- - Data; interface_type: [SAS] +-- - Data; model: [HP EH0146FBQDC] +-- - Data; rotational_speed: [15000] + +-- - Data; phy_count: [2] +-- - Data; phy_transfer_rate: [6.0Gbps, Unknown] +-- - Data; firmware_revision: [HPD5] +-- - Data; drive_authentication_status: [OK] +-- - Data; carrier_application_version: [11] +-- - Data; carrier_bootloader_version: [6] + +-- This stores information about physical disks. +CREATE TABLE scan_hpacucli_physical_drives ( + scan_hpacucli_physical_drive_uuid uuid not null primary key, + scan_hpacucli_physical_drive_host_uuid uuid not null, + scan_hpacucli_physical_drive_logical_drive_uuid uuid not null, + scan_hpacucli_physical_drive_serial_number text not null, + scan_hpacucli_physical_drive_model text not null, + scan_hpacucli_physical_drive_interface text not null, + scan_hpacucli_physical_drive_status text not null, + scan_hpacucli_physical_drive_size numeric not null, -- In bytes + scan_hpacucli_physical_drive_type text not null, + scan_hpacucli_physical_drive_rpm numeric not null, -- '0' for SSDs. + scan_hpacucli_physical_drive_temperature numeric not null, -- In celslius + scan_hpacucli_physical_drive_last_failure_reason text not null, -- This is usually an empty string + scan_hpacucli_physical_drive_port text not null, -- These three form the ID for the drive; :: + scan_hpacucli_physical_drive_box text not null, + scan_hpacucli_physical_drive_bay text not null, + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_hpacucli_physical_drive_host_uuid) REFERENCES hosts(host_uuid), + FOREIGN KEY(scan_hpacucli_physical_drive_logical_drive_uuid) REFERENCES scan_hpacucli_logical_drives(scan_hpacucli_logical_drive_uuid) +); +ALTER TABLE scan_hpacucli_physical_drives OWNER TO admin; + +CREATE TABLE history.scan_hpacucli_physical_drives ( + history_id bigserial, + scan_hpacucli_physical_drive_uuid uuid, + scan_hpacucli_physical_drive_host_uuid uuid, + scan_hpacucli_physical_drive_logical_drive_uuid uuid, + scan_hpacucli_physical_drive_serial_number text, + scan_hpacucli_physical_drive_model text, + scan_hpacucli_physical_drive_interface text, + scan_hpacucli_physical_drive_status text, + scan_hpacucli_physical_drive_size numeric, + scan_hpacucli_physical_drive_type text, + scan_hpacucli_physical_drive_rpm numeric, + scan_hpacucli_physical_drive_temperature numeric, + scan_hpacucli_physical_drive_last_failure_reason text, + scan_hpacucli_physical_drive_port text, + scan_hpacucli_physical_drive_box text, + scan_hpacucli_physical_drive_bay text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_hpacucli_physical_drives OWNER TO admin; + +CREATE FUNCTION history_scan_hpacucli_physical_drives() RETURNS trigger +AS $$ +DECLARE + history_scan_hpacucli_physical_drives RECORD; +BEGIN + SELECT INTO history_scan_hpacucli_physical_drives * FROM scan_hpacucli_physical_drives WHERE scan_hpacucli_physical_drive_uuid=new.scan_hpacucli_physical_drive_uuid; + INSERT INTO history.scan_hpacucli_physical_drives + (scan_hpacucli_physical_drive_uuid, + scan_hpacucli_physical_drive_host_uuid, + scan_hpacucli_physical_drive_logical_drive_uuid, + scan_hpacucli_physical_drive_serial_number, + scan_hpacucli_physical_drive_model, + scan_hpacucli_physical_drive_interface, + scan_hpacucli_physical_drive_status, + scan_hpacucli_physical_drive_size, + scan_hpacucli_physical_drive_type, + scan_hpacucli_physical_drive_rpm, + scan_hpacucli_physical_drive_temperature, + scan_hpacucli_physical_drive_last_failure_reason, + scan_hpacucli_physical_drive_port, + scan_hpacucli_physical_drive_box, + scan_hpacucli_physical_drive_bay, + modified_date) + VALUES + (history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_uuid, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_host_uuid, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_logical_drive_uuid, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_serial_number, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_model, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_interface, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_status, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_size, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_type, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_rpm, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_temperature, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_last_failure_reason, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_port, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_box, + history_scan_hpacucli_physical_drives.scan_hpacucli_physical_drive_bay, + history_scan_hpacucli_physical_drives.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_hpacucli_physical_drives() OWNER TO admin; + +CREATE TRIGGER trigger_scan_hpacucli_physical_drives + AFTER INSERT OR UPDATE ON scan_hpacucli_physical_drives + FOR EACH ROW EXECUTE PROCEDURE history_scan_hpacucli_physical_drives(); + + + +-- ------------------------------------------------------------------------------------------------------- -- +-- Each data type has several variables that we're not storing in the component-specific tables. To do so -- +-- would be to create massive tables that would miss variables not shown for all controllers or when new -- +-- variables are added or renamed. So this table is used to store all those myriade of variables. Each -- +-- entry will reference the table it is attached to and the UUID of the record in that table. The column -- + +-- 'scan_hpacucli_variable_is_temperature' will be used to know what data is a temperature and will be then -- +-- used to inform on the host's thermal health. -- +-- ------------------------------------------------------------------------------------------------------- -- + +-- This stores various variables found for a given controller but not explicitely checked for (or that +-- change frequently). +CREATE TABLE scan_hpacucli_variables ( + scan_hpacucli_variable_uuid uuid not null primary key, + scan_hpacucli_variable_host_uuid uuid not null, + scan_hpacucli_variable_source_table text not null, + scan_hpacucli_variable_source_uuid uuid not null, + scan_hpacucli_variable_is_temperature boolean not null default FALSE, + scan_hpacucli_variable_name text not null, + scan_hpacucli_variable_value text not null, + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_hpacucli_variable_host_uuid) REFERENCES hosts(host_uuid) +); +ALTER TABLE scan_hpacucli_variables OWNER TO admin; + +CREATE TABLE history.scan_hpacucli_variables ( + history_id bigserial, + scan_hpacucli_variable_uuid uuid, + scan_hpacucli_variable_host_uuid uuid, + scan_hpacucli_variable_source_table text, + scan_hpacucli_variable_source_uuid uuid, + scan_hpacucli_variable_is_temperature boolean, + scan_hpacucli_variable_name text, + scan_hpacucli_variable_value text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_hpacucli_variables OWNER TO admin; + +CREATE FUNCTION history_scan_hpacucli_variables() RETURNS trigger +AS $$ +DECLARE + history_scan_hpacucli_variables RECORD; +BEGIN + SELECT INTO history_scan_hpacucli_variables * FROM scan_hpacucli_variables WHERE scan_hpacucli_variable_uuid=new.scan_hpacucli_variable_uuid; + INSERT INTO history.scan_hpacucli_variables + (scan_hpacucli_variable_uuid, + scan_hpacucli_variable_host_uuid, + scan_hpacucli_variable_source_table, + scan_hpacucli_variable_source_uuid, + scan_hpacucli_variable_is_temperature, + scan_hpacucli_variable_name, + scan_hpacucli_variable_value, + modified_date) + VALUES + (history_scan_hpacucli_variables.scan_hpacucli_variable_uuid, + history_scan_hpacucli_variables.scan_hpacucli_variable_host_uuid, + history_scan_hpacucli_variables.scan_hpacucli_variable_source_table, + history_scan_hpacucli_variables.scan_hpacucli_variable_source_uuid, + history_scan_hpacucli_variables.scan_hpacucli_variable_is_temperature, + history_scan_hpacucli_variables.scan_hpacucli_variable_name, + history_scan_hpacucli_variables.scan_hpacucli_variable_value, + history_scan_hpacucli_variables.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_hpacucli_variables() OWNER TO admin; + +CREATE TRIGGER trigger_scan_hpacucli_variables + AFTER INSERT OR UPDATE ON scan_hpacucli_variables + FOR EACH ROW EXECUTE PROCEDURE history_scan_hpacucli_variables(); + +-- - Array: [ZZZZ] +-- - Logical Drive: [9999] +-- - Physical Drive: [2I:1:8], sn: [11428100010010790594] +-- - Data; carrier_application_version: [11] +-- - Data; carrier_bootloader_version: [6] +-- - Data; device_number: [380] +-- - Data; drive_authentication_status: [OK] +-- - Data; drive_type: [Unassigned Drive] +-- - Data; firmware_revision: [1.0] +-- - Data; firmware_version: [RevB] +-- - Data; interface_type: [Solid State SATA] +-- - Data; model: [SRCv8x6G] +-- - Data; phy_count: [1] +-- - Data; phy_transfer_rate: [6.0Gbps] +-- - Data; sata_ncq_capable: [True] +-- - Data; sata_ncq_enabled: [True] +-- - Data; size: [128.0 GB] +-- - Data; ssd_smart_trip_wearout: [Not Supported] +-- - Data; status: [OK] +-- - Data; vendor_id: [PMCSIERA] +-- - Data; wwid: [5001438030E9B24F] diff --git a/scancore-agents/scan-hpacucli/scan-hpacucli.xml b/scancore-agents/scan-hpacucli/scan-hpacucli.xml new file mode 100644 index 00000000..8a57b042 --- /dev/null +++ b/scancore-agents/scan-hpacucli/scan-hpacucli.xml @@ -0,0 +1,308 @@ + + + + + + + + + + + HP Enterprise RAID controller scan agent using the 'hpacucli' tool + + + Starting #!string!scan_hpacucli_brand_0001!#: + #!free!# + + + Diagnostics not available for the drive: [#!variable!serial_number!#] in port: [#!variable!port!#], box: [#!variable!box!#], bay: [#!variable!bay!#]. Unable to predict failures! Is this a third-party drive? + The RAID controller's properties have changed: +- Model: ................. [#!variable!old_model!#] -> [#!variable!new_model!#] +- Serial Number: ......... [#!variable!old_serial_number!#] -> [#!variable!new_serial_number!#] +- Status: ................ [#!variable!old_status!#] -> [#!variable!new_status!#] +- Status: ................ [#!variable!old_alarm_state!#] -> [#!variable!new_alarm_state!#] +- Cache Present: ......... [#!variable!old_cache_present!#] -> [#!variable!new_cache_present!#] +- Drive Write Cache: ..... [#!variable!old_drive_write_cache!#] -> [#!variable!new_drive_write_cache!#] +- Firmware Version: ...... [#!variable!old_firmware_version!#] -> [#!variable!new_firmware_version!#] +- Unsafe Write-Back Cache: [#!variable!old_unsafe_writeback_cache!#] -> [#!variable!new_unsafe_writeback_cache!#] + + The RAID controller has returned: +- Model: ................. [#!variable!new_model!#] +- Serial Number: ......... [#!variable!new_serial_number!#] +- Status: ................ [#!variable!new_status!#] +- Status: ................ [#!variable!new_alarm_state!#] +- Cache Present: ......... [#!variable!new_cache_present!#] +- Drive Write Cache: ..... [#!variable!new_drive_write_cache!#] +- Firmware Version: ...... [#!variable!new_firmware_version!#] +- Unsafe Write-Back Cache: [#!variable!new_unsafe_writeback_cache!#] + + The RAID controller's cache module has changed: +- Serial Number: ......... [#!variable!old_serial_number!#] -> [#!variable!new_serial_number!#] +- Controller: ............ [#!variable!old_controller_serial_number!#] -> [#!variable!new_controller_serial_number!#] +- Status: ................ [#!variable!old_status!#] -> [#!variable!new_status!#] +- Type: .................. [#!variable!old_type!#] -> [#!variable!new_type!#] +- Size: .................. [#!variable!say_old_size!#] -> [#!variable!say_new_size!#] + + The RAID controller's cache module has returned: +- Serial Number: ......... [#!variable!new_serial_number!#] +- Controller: ............ [#!variable!new_controller_serial_number!#] +- Status: ................ [#!variable!new_status!#] +- Type: .................. [#!variable!new_type!#] +- Size: .................. [#!variable!say_new_size!#] + + + + The 'hpacucli' program was not found at: [#!variable!path!#], exiting. + The 'hpacucli' program was found at: [#!variable!path!#], but it is not executable. exiting. + No HPE-type RAID controllers were found, exiting. + Failed to find the serial number for the adapter: [#!variable!adapter!#]. Please check the output of '#!data!path::hpacucli!# #!data!sys::arguments::controller_info!#' and look for the 'Serial Number = X' string. Exiting. + The attempt to generate the XML diagnostics file: [#!variable!file!#] appears to have failed. + Non-numeric value in a numeric variable; controller last diagnostics (unix time): [#!variable!last_diagnostics!#]. This is likely a program error. + Non-numeric value in a numeric variable; cache module size: [#!variable!size!#]. This is likely a program error. + Non-numeric value in a numeric variable; array unused space: [#!variable!unused_space!#]. This is likely a program error. + Non-numeric value in a numeric variable; logical drive size: [#!variable!logical_drive_size!#], strip size: [#!variable!strip_size!#], or stripe size: [#!variable!stripe_size!#]. This is likely a program error. + Non-numeric value in a numeric variable; drive size: [#!variable!size!#], RPM: [#!variable!rpm!#] or temperature: [#!variable!temperature!#]. This is likely a program error. + Failed to find the serial number of the physical drive at the following location: +- RAID Controller Serial Number: [#!variable!serial_number!#] +- Array Name: .................. [#!variable!array_name!#] +- Logical Drive Name: .......... [#!variable!logical_drive_name!#] +- Port: ........................ [#!variable!port!#] +- Box: ......................... [#!variable!box!#] +- Bay: ......................... [#!variable!bay!#] + + + + A new HP RAID controller has been found. +- Model Name: .............. [#!variable!model!#] +- Serial Number: ........... [#!variable!serial_number!#] +- Status: .................. [#!variable!status!#] +- Drive Write Cache: ....... [#!variable!drive_write_cache!#] +- Firmware: ................ [#!variable!firmware_version!#] +- Write-Back on bad FBU/BBU: [#!variable!unsafe_writeback_cache!#] + + A new cache module has been found. +- Serial Number: [#!variable!serial_number!#] +- Cache Size: .. [#!variable!cache_size!#] +- Status: ...... [#!variable!status!#] +- Type: ........ [#!variable!type!#] + + Other detected variables (if any): + - #!variable!name!#: [#!variable!value!#] + +The temperature sensor: [#!variable!sensor_name!#] on the controller: [#!variable!serial_number!#] is above the high critical temperature of: [#!variable!high_critical_temperature!#]!: +- #!variable!name!#: [#!variable!value!#] +NOTE: If the other node is cooler, automatic live migration of hosted servers (if any) will occur soon. +NOTE: If enough sensors go into warning or critical on both nodes, load shedding will occur to slow room heating. +WARNING: If enough sensors go critical, emergency power off will occure to protect the node from damage. + + +The temperature sensor: [#!variable!sensor_name!#] on the controller: [#!variable!serial_number!#] is above the high warning temperature of: [#!variable!high_warning_temperature!#]. It will go critical at: [#!variable!high_critical_temperature!#]!: +- #!variable!name!#: [#!variable!value!#] +NOTE: If the other node is cooler, automatic live migration of hosted servers (if any) will occur soon. +NOTE: If enough sensors go into warning or critical on both nodes, load shedding will occur to slow room heating. +WARNING: If enough sensors go critical, emergency power off will occure to protect the node from damage. + + +The temperature sensor: [#!variable!sensor_name!#] on the controller: [#!variable!serial_number!#] is below the low critical temperature of: [#!variable!low_critical_temperature!#]!: +- #!variable!name!#: [#!variable!value!#] +NOTE: If the other node is cooler, automatic live migration of hosted servers (if any) will occur soon. +NOTE: If enough sensors go into warning or critical on both nodes, load shedding will occur to slow room heating. +WARNING: If enough sensors go critical, emergency power off will occure to protect the node from damage. + + +The temperature sensor: [#!variable!sensor_name!#] on the controller: [#!variable!serial_number!#] is below the low warning temperature of: [#!variable!low_warning_temperature!#]. It will go critical at: [#!variable!low_critical_temperature!#]!: +- #!variable!name!#: [#!variable!value!#] +NOTE: If the other node is cooler, automatic live migration of hosted servers (if any) will occur soon. +NOTE: If enough sensors go into warning or critical on both nodes, load shedding will occur to slow room heating. +WARNING: If enough sensors go critical, emergency power off will occure to protect the node from damage. + + - The variable: [#!variable!name!#] has changed: +- [#!variable!old_value!#] -> [#!variable!new_value!#] + + - Controller: [#!variable!serial_number!#]: '#!variable!name!#' has returned: [#!variable!new_value!#] + - Controller: [#!variable!serial_number!#]: Temperature sensor: '#!variable!name!#' is no longer critically hot. +- [#!variable!old_value!#] -> [#!variable!new_value!#] + + - Controller: [#!variable!serial_number!#]: Temperature sensor: '#!variable!name!#' is no longer hot enough to be in a warning state. +- [#!variable!old_value!#] -> [#!variable!new_value!#] + + - Controller: [#!variable!serial_number!#]: Temperature sensor: '#!variable!name!#' is no longer critically cold. +- [#!variable!old_value!#] -> [#!variable!new_value!#] + + - Controller: [#!variable!serial_number!#]: Temperature sensor: '#!variable!name!#' is no longer cold enough to be in a warning state. +- [#!variable!old_value!#] -> [#!variable!new_value!#] + + - Controller: [#!variable!serial_number!#]: Temperature sensor: '#!variable!name!#' has jumped: [#!variable!delta!#] since the last scan. +- [#!variable!old_value!#] -> [#!variable!new_value!#] + + - Controller: [#!variable!serial_number!#]: Temperature sensor: '#!variable!name!#' has dropped: [#!variable!delta!#] since the last scan. +- [#!variable!old_value!#] -> [#!variable!new_value!#] + + The HP RAID controller: [#!variable!model!#] with the serial number: [#!variable!serial_number!#] has vanished! + The HP RAID cache module with the serial number: [#!variable!serial_number!#] has vanished! + The temperature sensor: [#!variable!name!#] on the HP RAID controller with the serial number: [#!variable!serial_number!#] has vanished! + The sensor: [#!variable!name!#] on the HP RAID controller with the serial number: [#!variable!serial_number!#] has vanished! + A new array has been found: [#!variable!name!#]. It is a: [#!variable!type!#] array and it's status is: [#!variable!status!#]! + A new array has been found: [#!variable!name!#] and it appears to have a problem. It is a: [#!variable!type!#] array and it's status is: [#!variable!status!#]. The error message is: [#!variable!error!#]! + The status of the HP RAID array: [#!variable!name!#] has changed: +- [#!variable!old_status!#] -> [#!variable!new_status!#] + + The HP RAID array: [#!variable!name!#] has changed is back to a healthy state. + The HP RAID array: [#!variable!name!#] has moved to a new controller. +- [#!variable!old_serial_number!#] -> [#!variable!new_serial_number!#] + + The error message for the HP RAID array: [#!variable!name!#] has changed: +- [#!variable!old_error_message!#] -> [#!variable!new_error_message!#] + + The HP RAID array: [#!variable!name!#] has cleared the old error message: [#!variable!old_error_message!#] + The HP RAID array: [#!variable!name!#] has an error message: [#!variable!new_error_message!#] + The error message for the HP RAID array: [#!variable!name!#] has changed: +- [#!variable!old_error_message!#] -> [#!variable!new_error_message!#] + + The HP RAID array: [#!variable!name!#] type has changed: +- [#!variable!old_type!#] -> [#!variable!new_type!#] + + The HP RAID array: [#!variable!name!#] on the controller: [#!variable!serial_number!#] has vanished! + The HP RAID array: [#!variable!name!#] on the controller: [#!variable!serial_number!#] has returned. + The HP RAID array: [#!variable!name!#] has a new logical drive: [#!variable!logical_drive!#]: +- Status: .............. [#!variable!new_status!#] +- Write-Back Caching: .. [#!variable!new_caching!#] +- Device Name in the OS: [#!variable!new_os_device_name!#] +- Drive Type: .......... [#!variable!new_type!#] +- RAID Level: .......... [#!variable!new_raid_level!#] +- Logical Drive Size: .. [#!variable!new_size!#] +- Strip Size: .......... [#!variable!new_strip_size!#] +- Stripe Size: ......... [#!variable!new_stripe_size!#] + + The write-back caching on the HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#] has changed! +- [#!variable!old_value!#] -> [#!variable!new_value!#] + + The write-back caching has been re-enabled on the HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#]. + The write-back caching has been disabled on the HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#]. +WARNING: Storage performance can be significantly impacted when write-back caching has been disabled! This can be caused by a failed battery or capacitor on the RAID controller. + + The status on the HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#] has changed! +- [#!variable!old_value!#] -> [#!variable!new_value!#] + + The HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#] is back to normal. + The HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#] is has begun recovering. +NOTE: The array is still degraded, and will remain so until the rebuild process is complete. How long this rebuild will take is a factor of the replacement drive's speed and size. + + The rebuild of the HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#] is now at: [#!variable!recovered!# %]. + The HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#] is degraded! +WARNING: This is generally caused by a drive failing or having been removed. Please replace the drive as soon as possible. + + The HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#] has changed! +- Drive Name in OS: [#!variable!old_os_drive_name!#] -> [#!variable!new_os_drive_name!#] +- Drive Type: ..... [#!variable!old_type!#] -> [#!variable!new_type!#] +- RAID Level: ..... [#!variable!old_raid_level!#] -> [#!variable!new_raid_level!#] +- Drive Size: ..... [#!variable!old_size!#] -> [#!variable!new_size!#] +- Strip Size: ..... [#!variable!old_strip_size!#] -> [#!variable!new_strip_size!#] +- Stripe Size: .... [#!variable!old_stripe_size!#] -> [#!variable!new_stripe_size!#] + + A variable on the HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#] has changed! +- #!variable!variable_name!#: [#!variable!old_value!#] -> [#!variable!new_value!#] + + The HP RAID logical drive: [#!variable!logical_drive!#] has vanished! + The HP RAID logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#] has returned! + A new physical disk was found on the HP RAID controller: [#!variable!controller_serial_number!#]: +- Serial Number: ..... [#!variable!drive_serial_number!#] +- Model: ............. [#!variable!model!#] +- Size: .............. [#!variable!size!#] +- Status: ............ [#!variable!status!#] +- Temperature: ....... [#!variable!temperature!#] +- Interface: ......... [#!variable!interface!#] +- Location: .......... [#!variable!port!#:#!variable!box!#:#!variable!bay!#] (Port:Box:Bay) +- Type: .............. [#!variable!rpm!#] +- Array: ............. [#!variable!array_name!#] +- Logical Drive: ..... [#!variable!logical_drive_name!#] +- Last Failure Reason: [#!variable!last_failure_reason!#] + + The physical disk: [#!variable!drive_serial_number!#] has moved to a new logical disk. +- Host: ........................ [#!variable!old_host_name!#] -> [#!variable!new_host_name!#] +- RAID Controller Serial Number: [#!variable!old_controller_serial_number!#] -> [#!variable!new_controller_serial_number!#] +- Array Name: .................. [#!variable!old_array_name!#] -> [#!variable!new_array_name!#] +- Logical Drive Name: .......... [#!variable!old_logical_drive_name!#] -> [#!variable!new_logical_drive_name!#] + + The status of the physical disk [#!variable!serial_number!#] has changed! [#!variable!old_status!#] -> [#!variable!new_status!#] + The physical disk: [#!variable!serial_number!#] has vanished! + The physical disk: [#!variable!serial_number!#] has returned. + The physical disk: [#!variable!serial_number!#] is back to normal. + The physical disk: [#!variable!serial_number!#] has changed in an unusual way: +- Model: ............. [#!variable!old_model!#] -> [#!variable!new_model!#] +- Interface: ......... [#!variable!old_interface!#] -> [#!variable!new_interface!#] +- Size: .............. [#!variable!old_size!#] -> [#!variable!new_size!#] +- RPM: ............... [#!variable!old_rpm!#] -> [#!variable!new_rpm!#] +- Last Failure Reason: [#!variable!old_last_failure_reason!#] -> [#!variable!new_last_failure_reason!#] +- Location: .......... [#!variable!old_port!#:#!variable!old_box!#:#!variable!old_bay!#] -> [#!variable!new_port!#:#!variable!new_box!#:#!variable!new_bay!#] (Port:Box:Bay) + + The temperature of the physical disk [#!variable!serial_number!#] has changed: [#!variable!old_temperature!#] -> [#!variable!new_temperature!#] + The temperature of the physical disk: [#!variable!serial_number!#] is no longer critically hot. +- [#!variable!old_temperature!#] -> [#!variable!new_temperature!#] + + The temperature of the physical disk: [#!variable!serial_number!#] is no longer hot enough to be in a warning state. +- [#!variable!old_temperature!#] -> [#!variable!new_temperature!#] + + The temperature of the physical disk: [#!variable!serial_number!#] is no longer critically cold. +- [#!variable!old_temperature!#] -> [#!variable!new_temperature!#] + + The temperature of the physical disk: [#!variable!serial_number!#] is no longer cold enough to be in a warning state. +- [#!variable!old_temperature!#] -> [#!variable!new_temperature!#] + + The temperature of the physical disk: [#!variable!serial_number!#] has jumped: [#!variable!delta!#] since the last scan. +- [#!variable!old_temperature!#] -> [#!variable!new_temperature!#] + + The temperature of the physical disk: [#!variable!serial_number!#] has dropped: [#!variable!delta!#] since the last scan. +- [#!variable!old_temperature!#] -> [#!variable!new_temperature!#] + + +The temperature of the physical drive: [#!variable!serial_number!#] is above the high critical temperature of: [#!variable!high_critical_temperature!#]!: +- Current temperature: [#!variable!new_temperature!#] +NOTE: If the other node is cooler, automatic live migration of hosted servers (if any) will occur soon. +NOTE: If enough temperature sensors go into warning or critical on both nodes, load shedding will occur to slow room heating. +WARNING: If enough sensors go critical, emergency power off will occure to protect the node from damage. + + +The temperature of the physical drive: [#!variable!serial_number!#] is above the high warning temperature of: [#!variable!high_warning_temperature!#]. It will go critical at: [#!variable!high_critical_temperature!#]!: +- Current temperature: [#!variable!new_temperature!#] +NOTE: If the other node is cooler, automatic live migration of hosted servers (if any) will occur soon. +NOTE: If enough temperature sensors go into warning or critical on both nodes, load shedding will occur to slow room heating. +WARNING: If enough sensors go critical, emergency power off will occure to protect the node from damage. + + +The temperature of the physical drive: [#!variable!serial_number!#] is below the low critical temperature of: [#!variable!low_critical_temperature!#]!: +- Current temperature: [#!variable!new_temperature!#] +NOTE: If the other node is cooler, automatic live migration of hosted servers (if any) will occur soon. +NOTE: If enough sensors go into warning or critical on both nodes, load shedding will occur to slow room heating. +WARNING: If enough sensors go critical, emergency power off will occure to protect the node from damage. + + +The temperature of the physical drive: [#!variable!serial_number!#] is below the low warning temperature of: [#!variable!low_warning_temperature!#]. It will go critical at: [#!variable!low_critical_temperature!#]!: +- Current temperature: [#!variable!new_temperature!#] +NOTE: If the other node is cooler, automatic live migration of hosted servers (if any) will occur soon. +NOTE: If enough sensors go into warning or critical on both nodes, load shedding will occur to slow room heating. +WARNING: If enough sensors go critical, emergency power off will occure to protect the node from damage. + + The new physical disk with the serial number: [#!variable!drive_serial_number!#] is not healthy! + A variable on the physical drive: [#!variable!serial_number!#] has changed: +- #!variable!variable_name!#: [#!variable!old_value!#] -> [#!variable!new_value!#] + + A variable on the logical drive: [#!variable!logical_drive!#] under the array: [#!variable!array!#] on the controller: [#!variable!serial_number!#] has changed: +- #!variable!variable_name!#: [#!variable!old_value!#] -> [#!variable!new_value!#] + + The variable: [#!variable!name!#] on the physical drive with the serial number: [#!variable!serial_number!#] has vanished! + The diagnostics variable: [#!variable!name!#] on the physical drive with the serial number: [#!variable!serial_number!#] has vanished! + + + Found: [#!variable!count!#] controller(s). + The thermal sensor named: [#!variable!sensor_name!#], on: [#!variable!sensor_host!#] has not changed. + Running: [#!variable!shell_call!#] to gather drive diagnostics. This will take up to fifteen seconds to run. + + + diff --git a/share/words.xml b/share/words.xml index 4f1a1028..6b3094b6 100644 --- a/share/words.xml +++ b/share/words.xml @@ -387,6 +387,12 @@ The attempt to start the servers appears to have failed. The return code '0' was #!variable!output!# ==== + ' or '--server-uuid .]]> + Could not find the server: [#!variable!server!#] on this Anvil! in the database. + This host is not a node, unable to rename the server from here. + '. The new name can not contain spaces.]]> + + The server wasn't found in the cluster configuration... Did a previous attempt to rename fail? Aborting. @@ -799,6 +805,16 @@ It should be provisioned in the next minute or two. The server: [#!variable!server!#] has been migrated to: [#!variable!target!#]. The server: [#!variable!server!#] will now be migrated to: [#!variable!target!#]. This could take some time! How much RAM is allocated to this server, the speed of the back-channel network and how busy the server is all contribute to migration time. Please be patient! The server: [#!variable!server!#] has been asked to migrate. We are not waiting for it to complete. + The cluster is up and both nodes are ready. + The cluster is up and both one or both nodes are not yet ready. Will wait until both are up. Current states; [#!variable!local_name!#] is: [#!variable!local_ready!#], and [#!variable!peer_name!#] is: [#!variable!peer_ready!#]. + The peer: [#!variable!host_name!#] can't be reached yet. Will wait for it to be available before proceeding with the rename. + The peer(s) of this server are accessible. Ready to proceed with the rename. + The server: [#!variable!server!#] status is: [#!variable!status!#]. Waiting for it to be off. + The server: [#!variable!server!#] is verified to be off everywhere. + The DRBD connection from: [#!variable!source_host!#] to: [#!variable!peer_host!#] for the resource/volume: [#!variable!resource!#/#!variable!volume!#] is: [#!variable!replication_state!#]. Will wait for the sync to finish before taking down the resource. + The DRBD resource behind the server is ready to be taken down. + Taking down the DRBD resource: [#!variable!resource!#] on the peer: [#!variable!peer!#] via the IP: [#!variable!ip!#]. + The DRBD resource is down. Starting: [#!variable!program!#]. @@ -1836,6 +1852,7 @@ Are you sure that you want to delete the server: [#!variable!server_name!#]? [Ty The 'anvil-safe-start' tool is disabled, exiting. Use '--force' to run anyway. The 'anvil-safe-start' tool is disabled, but '--force' was used, so proceeding. It appears that another instance of 'anvil-safe-start' is already runing. Please wait for it to complete (or kill it manually if needed). + Preparing to rename a server. Saved the mail server information successfully! diff --git a/tools/anvil-rename-server b/tools/anvil-rename-server index ba163b32..cecd15a1 100755 --- a/tools/anvil-rename-server +++ b/tools/anvil-rename-server @@ -14,7 +14,7 @@ use strict; use warnings; use Anvil::Tools; -require POSIX; +use Data::Dumper; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; @@ -30,15 +30,17 @@ my $anvil = Anvil::Tools->new(); # Read switches (target ([user@]host[:port]) and the file with the target's password. If the password is # passed directly, it will be used. Otherwise, the password will be read from the database. -$anvil->data->{switches}{'job-uuid'} = ""; -$anvil->data->{switches}{'new-name'} = ""; -$anvil->data->{switches}{'old-name'} = ""; +$anvil->data->{switches}{'job-uuid'} = ""; +$anvil->data->{switches}{'new-name'} = ""; +$anvil->data->{switches}{'server'} = ""; +$anvil->data->{switches}{'server-uuid'} = ""; $anvil->Get->switches; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 'switches::new-name' => $anvil->data->{switches}{'new-name'}, - 'switches::old-name' => $anvil->data->{switches}{'old-name'}, - 'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'}, + 'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'}, + 'switches::new-name' => $anvil->data->{switches}{'new-name'}, + 'switches::server' => $anvil->data->{switches}{'server'}, + 'switches::server-uuid' => $anvil->data->{switches}{'server-uuid'}, }}); $anvil->Database->connect(); @@ -70,18 +72,142 @@ if ($anvil->data->{switches}{'job-uuid'}) progress => 1, job_picked_up_by => $$, job_picked_up_at => time, - message => "message_0190", + message => "message_0234", }); - # Job data will be in $anvil->data->{jobs}{job_data} - run_jobs($anvil); + # Pull out the job data. + foreach my $line (split/\n/, $anvil->data->{jobs}{job_data}) + { + if ($line =~ /server=(.*?)$/) + { + $anvil->data->{switches}{'server'} = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 'switches::server' => $anvil->data->{switches}{'server'}, + }}); + } + if ($line =~ /server-uuid=(.*?)$/) + { + $anvil->data->{switches}{'server-uuid'} = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 'switches::server-uuid' => $anvil->data->{switches}{'server-uuid'}, + }}); + } + if ($line =~ /new-name=(.*?)$/) + { + $anvil->data->{switches}{'new-name'} = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 'switches::new-name' => $anvil->data->{switches}{'new-name'}, + }}); + } + } } -else + +# Make sure we're in an Anvil! +$anvil->data->{sys}{anvil_uuid} = $anvil->Cluster->get_anvil_uuid(); +if (not $anvil->data->{sys}{anvil_uuid}) +{ + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0260"}); + $anvil->Job->update_progress({progress => 100, message => "error_0260"}); + $anvil->nice_exit({exit_code => 1}); +} + +# Now check that we have a server. If it's a server_uuid, read the server name. +$anvil->Database->get_servers(); +if ($anvil->data->{switches}{'server-uuid'}) { - # Interactive! - interactive_question($anvil); + # Convert the server_uuid to a server_name. + my $server_uuid = $anvil->data->{switches}{'server-uuid'}; + if (not exists $anvil->data->{servers}{server_uuid}{$server_uuid}) + { + # Invalid server UUID. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0269", variables => { + server_uuid => $anvil->data->{switches}{'server-uuid'}, + }}); + $anvil->Job->update_progress({progress => 100, message => "error_0269,!!server_uuid!".$anvil->data->{switches}{'server-uuid'}."!!"}); + $anvil->nice_exit({exit_code => 1}); + } + + $anvil->data->{switches}{'server'} = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 'switches::server' => $anvil->data->{switches}{'server'}, + }}); } +# Do we have a server name? +if (not $anvil->data->{switches}{'server'}) +{ + # Unable to proceed. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0276"}); + $anvil->Job->update_progress({progress => 100, message => "error_0276"}); + $anvil->nice_exit({exit_code => 1}); +} + +# Do we have a new server name? +if (not $anvil->data->{switches}{'new-name'}) +{ + # Unable to proceed. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0279"}); + $anvil->Job->update_progress({progress => 100, message => "error_0279"}); + $anvil->nice_exit({exit_code => 1}); +} + +# Make sure there are no spaces in the name +$anvil->data->{switches}{'new-name'} =~ s/^\s+//; +$anvil->data->{switches}{'new-name'} =~ s/\s$//; +if ($anvil->data->{switches}{'new-name'} =~ /\s/) +{ + # Bad new server name + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0280", variables => { + new_name => $anvil->data->{switches}{'new-name'}, + }}); + $anvil->Job->update_progress({progress => 100, message => "error_0280,!!new_name!".$anvil->data->{switches}{'new-name'}."!!"}); + $anvil->nice_exit({exit_code => 1}); +} + +# We're going to need a server UUID. If we don't have it, find it from the current name. +if (not $anvil->data->{switches}{'server-uuid'}) +{ + # Convert the server name to a server_uuid. + my $anvil_uuid = $anvil->data->{sys}{anvil_uuid}; + my $server_name = $anvil->data->{switches}{'server'}; + if (not exists $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name}) + { + # Invalid server UUID. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0277", variables => { server => $server_name }}); + $anvil->Job->update_progress({progress => 100, message => "error_0277,!!server!".$server_name."!!"}); + $anvil->nice_exit({exit_code => 1}); + } + + $anvil->data->{switches}{'server-uuid'} = $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name}{server_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 'switches::server-uuid' => $anvil->data->{switches}{'server-uuid'}, + }}); +} + +# Are we a node? +$anvil->data->{sys}{host_type} = $anvil->Get->host_type(); +if ($anvil->data->{sys}{host_type} ne "node") +{ + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0264"}); + $anvil->Job->update_progress({progress => 100, message => "error_0264"}); + $anvil->nice_exit({exit_code => 1}); +} + +# This is copied from anvil-boot-server, but it works here as well. We can't use 'pcs' without pacemaker +# being up. +wait_for_pacemaker($anvil); + +# Now we're ready. +gather_server_data($anvil); + +# Verify that the server is off everywhere. +verify_server_is_off($anvil); + +# Now start renaming things. +#rename_server($anvil); + +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0281"}); +$anvil->Job->update_progress({progress => 100, message => "job_0281"}); $anvil->nice_exit({exit_code => 0}); @@ -90,12 +216,408 @@ $anvil->nice_exit({exit_code => 0}); # Functions # ############################################################################################################# -# This actually provisions a VM. -sub run_jobs +# This does the actual rename. It removes the resource from the cluster, makes sure the DRBD resource is down +# on all machines, renames the XML definition file + +# Calls virsh locally and on peer(s) to ensure that the server is not running. +sub verify_server_is_off { my ($anvil) = @_; + # Is the server running from pacemaker's perspective? + my $waiting = 1; + my $old_server_name = $anvil->data->{switches}{'server'}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_server_name => $old_server_name }}); + while ($waiting) + { + $waiting = 0; + $anvil->Cluster->parse_cib({debug => 2}); + if (not exists $anvil->data->{cib}{parsed}{data}{server}{$old_server_name}) + { + # Server wasn't found in the cluster config. Wat?! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0281"}); + $anvil->Job->update_progress({progress => 100, message => "error_0281"}); + $anvil->nice_exit({exit_code => 1}); + } + + my $status = $anvil->data->{cib}{parsed}{data}{server}{$old_server_name}{status}; + my $host_name = $anvil->data->{cib}{parsed}{data}{server}{$old_server_name}{host_name}; + my $role = $anvil->data->{cib}{parsed}{data}{server}{$old_server_name}{role}; + my $active = $anvil->data->{cib}{parsed}{data}{server}{$old_server_name}{active}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:old_server_name' => $old_server_name, + 's2:status' => $status, + 's2:host_name' => $host_name, + 's4:role' => $role, + 's5:active' => $active, + }}); + + if ($status ne "off") + { + $waiting = 1; + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0299", variables => { + server => $old_server_name, + status => $status, + }}); + $anvil->Job->update_progress({progress => 22, message => "job_0299,!!server!".$old_server_name."!!,!!status!".$status."!!"}); + sleep 10; + } + } + + # Now check virsh. + $waiting = 1; + while ($waiting) + { + $waiting = 0; + $anvil->Server->find({refresh => 1}); + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{rename_server}{host}}) + { + next if $anvil->data->{rename_server}{host}{$host_name}{is_peer}; + my $peers_ip = $anvil->data->{rename_server}{host}{$host_name}{use_ip}; + my $password = $anvil->data->{rename_server}{host}{$host_name}{password}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + peers_ip => $peers_ip, + password => $anvil->Log->is_secure($password), + }}); + $anvil->Server->find({ + refresh => 0, + target => $peers_ip, + password => $password, + }); + } + if ((exists $anvil->data->{server}{location}{$old_server_name}) && ($anvil->data->{server}{location}{$old_server_name}{status} ne "shut off")) + { + my $status = $anvil->data->{server}{location}{$old_server_name}{status}; + my $host = $anvil->data->{server}{location}{$old_server_name}{host_name}; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0299", variables => { + server => $old_server_name, + status => $status, + host => $host, + }}); + $anvil->Job->update_progress({progress => 26, message => "job_0299,!!server!".$old_server_name."!!,!!status!".$status."!!,!!host!".$host."!!"}); + sleep 10; + } + } + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0300", variables => { server => $old_server_name }}); + $anvil->Job->update_progress({progress => 28, message => "job_0300,!!server!".$old_server_name."!!"}); + # Now make sure the DRBD resource is down on all machines. + my $short_host_name = $anvil->Get->short_host_name(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { short_host_name => $short_host_name }}); + + # Wait until the resource is not sync'ing (if it is at all). + $waiting = 1; + while ($waiting) + { + # (Re)fresh my view of the storage. + $waiting = 0; + $anvil->DRBD->get_status({debug => 2}); + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{rename_server}{host}}) + { + next if not $anvil->data->{rename_server}{host}{$host_name}{is_peer}; + my $peers_ip = $anvil->data->{rename_server}{host}{$host_name}{use_ip}; + my $password = $anvil->data->{rename_server}{host}{$host_name}{password}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + peers_ip => $peers_ip, + password => $anvil->Log->is_secure($password), + }}); + $anvil->DRBD->get_status({ + debug => 2, + target => $peers_ip, + password => $password, + }); + } + + # Now check to see if anything is sync'ing. + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd}{status}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:old_server_name' => $old_server_name, + 's2:host_name' => $host_name, + }}); + next if not exists $anvil->data->{drbd}{status}{$host_name}{resource}{$old_server_name}; + + foreach my $peer_name (sort {$a cmp $b} keys %{$anvil->data->{drbd}{status}{$host_name}{resource}{$old_server_name}{connection}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_name => $peer_name }}); + foreach my $volume (sort {$a cmp $b} %{$anvil->data->{drbd}{status}{$host_name}{resource}{$old_server_name}{connection}{$peer_name}{volume}}) + { + next if not exists $anvil->data->{drbd}{status}{$host_name}{resource}{$old_server_name}{connection}{$peer_name}{volume}{$volume}{'replication-state'}; + my $replication_state = $anvil->data->{drbd}{status}{$host_name}{resource}{$old_server_name}{connection}{$peer_name}{volume}{$volume}{'replication-state'}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + volume => $volume, + replication_state => $replication_state, + }}); + + if ($replication_state =~ /Sync/i) + { + $waiting = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0301", variables => { + source_host => $host_name, + peer_host => $peer_name, + resource => $old_server_name, + volume => $volume, + replication_state => $replication_state, + }}); + $anvil->Job->update_progress({progress => 30, message => "job_0301,!!source_host!".$host_name."!!,!!peer_host!".$peer_name."!!,!!resource!".$old_server_name."!!,!!volume!".$volume."!!,!!replication_state!".$replication_state."!!"}); + } + } + } + } + if ($waiting) + { + sleep 10; + } + } + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0302"}); + $anvil->Job->update_progress({progress => 33, message => "job_0302"}); + + # Shut down the peers first + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{rename_server}{host}}) + { + next if not $anvil->data->{rename_server}{host}{$host_name}{is_peer}; + my $peers_ip = $anvil->data->{rename_server}{host}{$host_name}{use_ip}; + my $password = $anvil->data->{rename_server}{host}{$host_name}{password}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + peers_ip => $peers_ip, + password => $anvil->Log->is_secure($password), + }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0303", variables => { + peer => $host_name, + resource => $old_server_name, + ip => $peers_ip, + }}); + $anvil->Job->update_progress({progress => 35, message => "job_0303,!!peer!".$host_name."!!,!!resource!".$old_server_name."!!,!!ip!".$peers_ip."!!"}); + $anvil->DRBD->manage_resource({ + debug => 2, + resource => $old_server_name, + task => "down", + target => $peers_ip, + password => $password, + }); + } + $anvil->DRBD->manage_resource({ + debug => 2, + resource => $old_server_name, + task => "down", + }); + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0304"}); + $anvil->Job->update_progress({progress => 38, message => "job_0304"}); + + return(0); +} + +# This figures out the names of the definition and DRBD resource files, LV names and other details that will +# be needed to rename the server. This will abort if anything seems wrong. +sub gather_server_data +{ + my ($anvil) = @_; + + my $old_server_name = $anvil->data->{switches}{'server'}; + my $new_server_name = $anvil->data->{switches}{'new-name'}; + + $anvil->data->{rename_server}{old_definition_file} = $anvil->data->{path}{directories}{shared}{definitions}."/".$old_server_name.".xml"; + $anvil->data->{rename_server}{new_definition_file} = $anvil->data->{path}{directories}{shared}{definitions}."/".$new_server_name.".xml"; + $anvil->data->{rename_server}{old_drbd_resource_file} = $anvil->data->{path}{directories}{drbd_resources}."/".$old_server_name.".res"; + $anvil->data->{rename_server}{new_drbd_resource_file} = $anvil->data->{path}{directories}{drbd_resources}."/".$new_server_name.".res"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "rename_server::old_definition_file" => $anvil->data->{rename_server}{old_definition_file}, + "rename_server::new_definition_file" => $anvil->data->{rename_server}{new_definition_file}, + "rename_server::old_drbd_resource_file" => $anvil->data->{rename_server}{old_drbd_resource_file}, + "rename_server::new_drbd_resource_file" => $anvil->data->{rename_server}{new_drbd_resource_file}, + }}); + + # Parse the DRBD resource file to see if we have a DR target for this server. + $anvil->DRBD->gather_data({debug => 2}); + $anvil->Database->get_hosts(); + + # We'll store our name for finding matches later. + my $local_drbd_node_name = ""; + + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$old_server_name}{host}}) + { + my $host_uuid = $anvil->Get->host_uuid_from_name({host_name => $host_name}); + my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type}; + my $peer = $host_uuid eq $anvil->Get->host_uuid ? 0 : 1; + $anvil->data->{rename_server}{host}{$host_name}{host_uuid} = $host_uuid; + $anvil->data->{rename_server}{host}{$host_name}{host_type} = $host_type; + $anvil->data->{rename_server}{host}{$host_name}{is_peer} = $peer; + $anvil->data->{rename_server}{host}{$host_name}{use_ip} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "rename_server::host::${host_name}::host_uuid" => $anvil->data->{rename_server}{host}{$host_name}{host_uuid}, + "rename_server::host::${host_name}::host_type" => $anvil->data->{rename_server}{host}{$host_name}{host_type}, + "rename_server::host::${host_name}::is_peer" => $anvil->data->{rename_server}{host}{$host_name}{is_peer}, + }}); + + if (not $peer) + { + $local_drbd_node_name = $host_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_drbd_node_name => $local_drbd_node_name }}); + $anvil->Network->load_ips({ + host => $local_drbd_node_name, + host_uuid => $host_uuid, + }); + } + + foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$old_server_name}{host}{$host_name}{volume}}) + { + my $old_device_path = $anvil->data->{new}{resource}{$old_server_name}{host}{$host_name}{volume}{$volume}{device_path}; + my $new_device_path = $old_device_path; + $new_device_path =~ s/$old_server_name/$new_server_name/g; + my $old_backing_disk = $anvil->data->{new}{resource}{$old_server_name}{host}{$host_name}{volume}{$volume}{backing_disk}; + my $new_backing_disk = $old_backing_disk; + $new_backing_disk =~ s/$old_server_name/$new_server_name/g; + $anvil->data->{rename_server}{host}{$host_name}{volume}{$volume}{old_device_path} = $old_device_path; + $anvil->data->{rename_server}{host}{$host_name}{volume}{$volume}{new_device_path} = $new_device_path; + $anvil->data->{rename_server}{host}{$host_name}{volume}{$volume}{old_backing_disk} = $old_backing_disk; + $anvil->data->{rename_server}{host}{$host_name}{volume}{$volume}{new_backing_disk} = $new_backing_disk; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "rename_server::host::${host_name}::volume::${volume}::old_device_path" => $anvil->data->{rename_server}{host}{$host_name}{volume}{$volume}{old_device_path}, + "rename_server::host::${host_name}::volume::${volume}::new_device_path" => $anvil->data->{rename_server}{host}{$host_name}{volume}{$volume}{new_device_path}, + "rename_server::host::${host_name}::volume::${volume}::old_backing_disk" => $anvil->data->{rename_server}{host}{$host_name}{volume}{$volume}{old_backing_disk}, + "rename_server::host::${host_name}::volume::${volume}::new_backing_disk" => $anvil->data->{rename_server}{host}{$host_name}{volume}{$volume}{new_backing_disk}, + }}); + } + } + + # Make sure we can talk to peers. + my $waiting = 1; + while($waiting) + { + $waiting = 0; + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{rename_server}{host}}) + { + next if not $anvil->data->{rename_server}{host}{$host_name}{is_peer}; + my $host_uuid = $anvil->data->{rename_server}{host}{$host_name}{host_uuid}; + my $anvil_uuid = $anvil->data->{sys}{anvil_uuid}; + my $password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + host_name => $host_name, + host_uuid => $host_uuid, + anvil_uuid => $anvil_uuid, + password => $anvil->Log->is_secure($password), + }}); + + $anvil->Network->load_ips({ + host => $host_name, + host_uuid => $host_uuid, + }); + + my $peers_ip = ""; + my ($match) = $anvil->Network->find_matches({ + debug => 2, + first => $local_drbd_node_name, + second => $host_name, + }); + + my $access = 0; + if ($match) + { + # Yup! + foreach my $interface (sort {$a cmp $b} keys %{$match->{$host_name}}) + { + my $peers_ip = $match->{$host_name}{$interface}{ip}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peers_ip => $peers_ip }}); + + $access = $anvil->Remote->test_access({ + target => $peers_ip, + password => $password, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }}); + if ($access) + { + $anvil->data->{rename_server}{host}{$host_name}{use_ip} = $peers_ip; + $anvil->data->{rename_server}{host}{$host_name}{password} = $password; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "rename_server::host::${host_name}::use_ip" => $anvil->data->{rename_server}{host}{$host_name}{use_ip}, + }}); + last; + } + } + } + if (not $access) + { + # Unable to reach this peer, so we need to keep waiting. + $waiting = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0297", variables => { host_name => $host_name }}); + $anvil->Job->update_progress({progress => 18, message => "job_0297,!!host_name!".$host_name."!!"}); + } + } + + if ($waiting) + { + sleep 10; + } + } + + # All peer(s) are ready! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0298"}); + $anvil->Job->update_progress({progress => 20, message => "job_0298"}); + + return(0); +} + +sub wait_for_pacemaker +{ + my ($anvil) = @_; + + # We need to rename the server in the cluster, and we need both nodes up to do it. + my $waiting = 1; + while($waiting) + { + my $problem = $anvil->Cluster->parse_cib({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); + if (not $problem) + { + my $local_name = $anvil->data->{cib}{parsed}{'local'}{name}; + my $peer_name = $anvil->data->{cib}{parsed}{peer}{name}; + my $local_ready = $anvil->data->{cib}{parsed}{data}{node}{$local_name}{node_state}{ready}; + my $peer_ready = $anvil->data->{cib}{parsed}{data}{node}{$local_name}{node_state}{ready}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + local_name => $local_name, + peer_name => $peer_name, + local_ready => $local_ready, + peer_ready => $peer_ready, + }}); + if (($local_ready) && ($peer_ready)) + { + # We're good. + $waiting = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0295"}); + $anvil->Job->update_progress({progress => 15, message => "job_0295"}); + } + else + { + # One or both nods are not online yet. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0296", variables => { + local_name => $local_name, + peer_name => $peer_name, + local_ready => $local_ready, + peer_ready => $peer_ready, + }}); + $anvil->Job->update_progress({progress => 10, message => "job_0296,!!local_name!".$local_name."!!,!!peer_name!".$peer_name."!!,!!local_ready!".$local_ready."!!,!!peer_ready!".$peer_ready."!!"}); + } + } + else + { + # Cluster hasn't started. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0277"}); + $anvil->Job->update_progress({progress => 5, message => "job_0277"}); + } + if ($waiting) + { + sleep 10; + } + } return(0); } From e3ba64cb83eaa9a4b81e099828a70266c07b9794 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 20 Apr 2021 23:00:03 -0400 Subject: [PATCH 2/3] * Fixed a type in the Makefile.am. Signed-off-by: Digimer --- scancore-agents/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scancore-agents/Makefile.am b/scancore-agents/Makefile.am index 67573625..3b343ff0 100644 --- a/scancore-agents/Makefile.am +++ b/scancore-agents/Makefile.am @@ -49,7 +49,7 @@ hpacuclidir = ${targetdir}/scan-hpacucli dist_hpacucli_DATA = \ scan-hardware/scan-hpacucli.xml \ scan-hardware/scan-hpacucli.sql -dist_hardware_SCRIPTS = \ +dist_hpacucli_SCRIPTS = \ scan-hardware/scan-hpacucli ipmitooldir = ${targetdir}/scan-ipmitool From 53cd0bdf3ac6be8e1e59295a4bc32dce51f2ada7 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 20 Apr 2021 23:22:45 -0400 Subject: [PATCH 3/3] * Now with 100% less typos. Signed-off-by: Digimer --- scancore-agents/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scancore-agents/Makefile.am b/scancore-agents/Makefile.am index 3b343ff0..42243270 100644 --- a/scancore-agents/Makefile.am +++ b/scancore-agents/Makefile.am @@ -47,10 +47,10 @@ dist_hardware_SCRIPTS = \ hpacuclidir = ${targetdir}/scan-hpacucli dist_hpacucli_DATA = \ - scan-hardware/scan-hpacucli.xml \ - scan-hardware/scan-hpacucli.sql + scan-hpacucli/scan-hpacucli.xml \ + scan-hpacucli/scan-hpacucli.sql dist_hpacucli_SCRIPTS = \ - scan-hardware/scan-hpacucli + scan-hpacucli/scan-hpacucli ipmitooldir = ${targetdir}/scan-ipmitool dist_ipmitool_DATA = \