From 1c00060d6e7a8a34fcef2b0684b7573318472f0e Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 23 Nov 2020 11:18:00 -0500 Subject: [PATCH] * Finished porting scan-storcli! This was the largest scan agent to migrate to M3. * Updated Alert->register() to take message variables using the 'variables' parameter. * Added a 'cache' parameter to Database->insert_or_update_health() and ->insert_or_update_temperature(). When set, the SQL UPDATE/INSERT calls and pushed into the array reference set in 'cache'. This is to allow performance improvements when processing a large amount of sensor/device data. * Updated Log->variables() to take a 'prefix' parameter that, when set, will prefix the string to each variable line. * Updated scan-ipmitool to use Database->insert_or_update_health() and ->insert_or_update_temperature(). Signed-off-by: Digimer --- Anvil/Tools.pm | 2 + Anvil/Tools/Alert.pm | 48 +- Anvil/Tools/Database.pm | 116 +- Anvil/Tools/Log.pm | 19 +- rpm/SPECS/anvil.spec | 7 +- scancore-agents/scan-apc-pdu/scan-apc-pdu | 316 +- scancore-agents/scan-apc-ups/scan-apc-ups | 142 +- scancore-agents/scan-cluster/scan-cluster | 22 +- scancore-agents/scan-hardware/scan-hardware | 116 +- scancore-agents/scan-ipmitool/scan-ipmitool | 335 +- .../scan-ipmitool/scan-ipmitool.xml | 2 +- scancore-agents/scan-lvm/scan-lvm | 62 +- scancore-agents/scan-server/scan-server | 26 +- scancore-agents/scan-storcli/scan-storcli | 10076 ++++++++++++++++ scancore-agents/scan-storcli/scan-storcli.sql | 640 + scancore-agents/scan-storcli/scan-storcli.xml | 1011 ++ tools/test.pl | 70 +- 17 files changed, 12346 insertions(+), 664 deletions(-) create mode 100755 scancore-agents/scan-storcli/scan-storcli create mode 100644 scancore-agents/scan-storcli/scan-storcli.sql create mode 100644 scancore-agents/scan-storcli/scan-storcli.xml diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 7afbe95b..408057c0 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1181,6 +1181,7 @@ sub _set_paths openssl => "/usr/bin/openssl", passwd => "/usr/bin/passwd", pcs => "/usr/sbin/pcs", + perccli64 => "/opt/MegaRAID/perccli/perccli64", ping => "/usr/bin/ping", pgrep => "/usr/bin/pgrep", ps => "/usr/bin/ps", @@ -1201,6 +1202,7 @@ sub _set_paths 'ssh-keyscan' => "/usr/bin/ssh-keyscan", 'stat' => "/usr/bin/stat", stonith_admin => "/usr/sbin/stonith_admin", + storcli64 => "/opt/MegaRAID/storcli/storcli64", strings => "/usr/bin/strings", 'striker-get-peer-data' => "/usr/sbin/striker-get-peer-data", 'striker-initialize-host' => "/usr/sbin/striker-initialize-host", diff --git a/Anvil/Tools/Alert.pm b/Anvil/Tools/Alert.pm index df5c961a..08caf0da 100644 --- a/Anvil/Tools/Alert.pm +++ b/Anvil/Tools/Alert.pm @@ -405,11 +405,7 @@ This is the message body of the alert. It is expected to be in the format C<< >. Example with two variables; C<< foo_0002,!!bar!abc!!,!!baz!123!! >>. -B<< Note >>: See C<< message_variables >> for an alternate method of passing variables - -=head3 message_variables (optional) - -This can be set as a hash reference containing key / variable pairs to inject into the message key. the C<< variable => value >> pairs will be appended to the C<< message >> key automatically. This is meant to simplify when an alert is also being longed, or when a large number of variables are being injected into the string. +B<< Note >>: See C<< variables >> for an alternate method of passing variables =head3 set_by (required) @@ -442,6 +438,10 @@ This is the title of the alert. It is expected to be in the format C<< >. Example with two variables; C<< foo_0002,!!bar!abc!!,!!baz!123!! >>. +=head3 variables (optional) + +This can be set as a hash reference containing key / variable pairs to inject into the message key. the C<< variable => value >> pairs will be appended to the C<< message >> key automatically. This is meant to simplify when an alert is also being longed, or when a large number of variables are being injected into the string. + =cut sub register { @@ -451,23 +451,23 @@ sub register my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Alert->register()" }}); - my $alert_level = defined $parameter->{alert_level} ? $parameter->{alert_level} : 0; - my $clear_alert = defined $parameter->{clear_alert} ? $parameter->{clear_alert} : 0; - my $message = defined $parameter->{message} ? $parameter->{message} : ""; - my $message_variables = defined $parameter->{message_variables} ? $parameter->{message_variables} : "", - my $set_by = defined $parameter->{set_by} ? $parameter->{set_by} : ""; - my $show_header = defined $parameter->{show_header} ? $parameter->{show_header} : 1; - my $sort_position = defined $parameter->{sort_position} ? $parameter->{sort_position} : 9999; - my $title = defined $parameter->{title} ? $parameter->{title} : ""; + my $alert_level = defined $parameter->{alert_level} ? $parameter->{alert_level} : 0; + my $clear_alert = defined $parameter->{clear_alert} ? $parameter->{clear_alert} : 0; + my $message = defined $parameter->{message} ? $parameter->{message} : ""; + my $set_by = defined $parameter->{set_by} ? $parameter->{set_by} : ""; + my $show_header = defined $parameter->{show_header} ? $parameter->{show_header} : 1; + my $sort_position = defined $parameter->{sort_position} ? $parameter->{sort_position} : 9999; + my $title = defined $parameter->{title} ? $parameter->{title} : ""; + my $variables = defined $parameter->{variables} ? $parameter->{variables} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - show_header => $show_header, - clear_alert => $clear_alert, - alert_level => $alert_level, - message => $message, - message_variables => ref($message_variables), - set_by => $set_by, - sort_position => $sort_position, - title => $title, + show_header => $show_header, + clear_alert => $clear_alert, + alert_level => $alert_level, + message => $message, + set_by => $set_by, + sort_position => $sort_position, + title => $title, + variables => ref($variables), }}); # Missing parameters? @@ -487,11 +487,11 @@ sub register return("!!error!!"); } - if (ref($message_variables) eq "HASH") + if (ref($variables) eq "HASH") { - foreach my $variable (sort {$a cmp $b} keys %{$message_variables}) + foreach my $variable (sort {$a cmp $b} keys %{$variables}) { - my $value = defined $message_variables->{$variable} ? $message_variables->{$variable} : "undefined:".$variable; + my $value = defined $variables->{$variable} ? $variables->{$variable} : "undefined:".$variable; $message .= ",!!".$variable."!".$value."!!"; } } diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index f8b7f1f0..d7497c66 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -1601,12 +1601,12 @@ sub connect # if ($cleared) # { # $anvil->Alert->register({ -# debug => $debug, -# level => "warning", -# agent_name => "Anvil!", -# title_key => "an_title_0006", -# message_key => "cleared_log_0055", -# message_variables => { +# debug => $debug, +# level => "warning", +# agent_name => "Anvil!", +# title_key => "an_title_0006", +# message => "cleared_log_0055", +# variables => { # name => $database_name, # host => $anvil->data->{database}{$uuid}{host}, # port => defined $anvil->data->{database}{$uuid}{port} ? $anvil->data->{database}{$uuid}{port} : 5432, @@ -5785,6 +5785,16 @@ If there is a problem, an empty string is returned. Otherwise, the C<< health_uu parameters; +=head3 cache (optional) + +If this is passed an array reference, SQL queries will be pushed into the array instead of actually committed to databases. It will be up to the caller to commit the queries. + +=head3 delete (optional, default '0') + +If set, the associated C<< health_uuid >> will be deleted. + +B<< Note >>: If set, C<< health_uuid >> becomes required and no other parameter is required. + =head3 health_uuid (optional) Is passed, the specific entry will be updated. @@ -5819,6 +5829,8 @@ sub insert_or_update_health my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $line = defined $parameter->{line} ? $parameter->{line} : ""; + my $cache = defined $parameter->{cache} ? $parameter->{cache} : ""; + my $delete = defined $parameter->{'delete'} ? $parameter->{'delete'} : ""; my $health_uuid = defined $parameter->{health_uuid} ? $parameter->{health_uuid} : ""; my $health_host_uuid = defined $parameter->{health_host_uuid} ? $parameter->{health_host_uuid} : $anvil->Get->host_uuid; my $health_agent_name = defined $parameter->{health_agent_name} ? $parameter->{health_agent_name} : ""; @@ -5828,6 +5840,7 @@ sub insert_or_update_health uuid => $uuid, file => $file, line => $line, + 'delete' => $delete, health_uuid => $health_uuid, health_host_uuid => $health_host_uuid, health_agent_name => $health_agent_name, @@ -5835,17 +5848,49 @@ sub insert_or_update_health health_source_weight => $health_source_weight, }}); - if (not $health_agent_name) + if ($delete) { - # Throw an error and exit. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_health()", parameter => "health_agent_name" }}); - return(""); + if (not $health_uuid) + { + # Throw an error and exit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_health()", parameter => "health_uuid" }}); + return(""); + } + my $query = " +UPDATE + health +SET + health_source_name = 'DELETED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + health_uuid = ".$anvil->Database->quote($health_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + + $query = " +DELETE FROM + health +WHERE + health_uuid = ".$anvil->Database->quote($health_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); } - if (not $health_source_name) + else { - # Throw an error and exit. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_health()", parameter => "health_source_name" }}); - return(""); + if (not $health_agent_name) + { + # Throw an error and exit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_health()", parameter => "health_agent_name" }}); + return(""); + } + if (not $health_source_name) + { + # Throw an error and exit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_health()", parameter => "health_source_name" }}); + return(""); + } } # If we don't have a health UUID, see if we can find one. @@ -5936,7 +5981,14 @@ WHERE health_uuid = ".$anvil->Database->quote($health_uuid)." ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + if (ref($cache) eq "ARRAY") + { + push @{$cache}, $query; + } + else + { + $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + } } } else @@ -5963,7 +6015,14 @@ INSERT INTO ); "; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + if (ref($cache) eq "ARRAY") + { + push @{$cache}, $query; + } + else + { + $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + } } return($health_uuid); @@ -10430,6 +10489,10 @@ If there is a problem, an empty string is returned. Otherwise, the C<< temperatu parameters; +=head3 cache (optional) + +If this is passed an array reference, SQL queries will be pushed into the array instead of actually committed to databases. It will be up to the caller to commit the queries. + =head3 temperature_uuid (optional) Is passed, the specific entry will be updated. @@ -10484,6 +10547,7 @@ sub insert_or_update_temperature my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $line = defined $parameter->{line} ? $parameter->{line} : ""; + my $cache = defined $parameter->{cache} ? $parameter->{cache} : ""; my $temperature_uuid = defined $parameter->{temperature_uuid} ? $parameter->{temperature_uuid} : ""; my $temperature_host_uuid = defined $parameter->{temperature_host_uuid} ? $parameter->{temperature_host_uuid} : $anvil->Get->host_uuid; my $temperature_agent_name = defined $parameter->{temperature_agent_name} ? $parameter->{temperature_agent_name} : ""; @@ -10671,14 +10735,21 @@ WHERE temperature_uuid = ".$anvil->Database->quote($temperature_uuid)." ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + if (ref($cache) eq "ARRAY") + { + push @{$cache}, $query; + } + else + { + $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + } } } else { # INSERT $temperature_uuid = $anvil->Get->uuid(); - my $query = " + my $query = " INSERT INTO temperature ( @@ -10706,7 +10777,14 @@ INSERT INTO ); "; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + if (ref($cache) eq "ARRAY") + { + push @{$cache}, $query; + } + else + { + $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + } } return($temperature_uuid); diff --git a/Anvil/Tools/Log.pm b/Anvil/Tools/Log.pm index 1547783e..609dbc71 100644 --- a/Anvil/Tools/Log.pm +++ b/Anvil/Tools/Log.pm @@ -763,6 +763,14 @@ Would generate a sorted log entry that looks like: All other key names are left alone and output is sorted alphabetically. +=head3 prefix (optional) + +If set, this string will be prefixed to all variable names. The string passed will be separated from variable names by a space-padded hyphen. + +For example, if C<< prefix >> is set to C<< foo >>, and the variables in the list are C<< bar >> and C<< baz >>, the logged variables will be C<< foo - bar >> and C<< foo - baz >>. + +B<< Note >>: If the list is short enough to be displayed on one line (three or less keys), the prefix is prepended to the list, not each variable name. + =cut sub variables { @@ -777,6 +785,7 @@ sub variables my $line = defined $parameter->{line} ? $parameter->{line} : ""; my $list = defined $parameter->{list} ? $parameter->{list} : {}; my $facility = defined $parameter->{facility} ? $parameter->{facility} : $anvil->data->{defaults}{'log'}{facility}; + my $prefix = defined $parameter->{prefix} ? $parameter->{prefix} : ""; my $priority = defined $parameter->{priority} ? $parameter->{priority} : ""; my $secure = defined $parameter->{secure} ? $parameter->{secure} : 0; my $server = defined $parameter->{server} ? $parameter->{server} : $anvil->data->{defaults}{'log'}{server}; @@ -827,6 +836,10 @@ sub variables if ($entries <= 3) { # Put all the entries on one line. + if ($prefix) + { + $raw = $prefix." - "; + } foreach my $key (sort {$a cmp $b} keys %{$list}) { print $THIS_FILE." ".__LINE__."; key: [".$key."]\n" if $test; @@ -866,7 +879,11 @@ sub variables # Strip a leading 'sX:' in case the user is sorting the output. my $say_key = $key; $say_key =~ s/^s(\d+)://; - $say_key .= ":"; + if ($prefix) + { + $say_key = $prefix." - ".$say_key; + } + $say_key .= ":"; my $difference = $length - length($say_key); print $THIS_FILE." ".__LINE__."; say_key: [".$say_key."], difference: [".$difference."]\n" if $test; if ($difference) diff --git a/rpm/SPECS/anvil.spec b/rpm/SPECS/anvil.spec index 295099e3..aecac22d 100644 --- a/rpm/SPECS/anvil.spec +++ b/rpm/SPECS/anvil.spec @@ -3,7 +3,7 @@ %define anvilgroup admin Name: anvil Version: 3.0 -Release: 36%{?dist} +Release: 37%{?dist} Summary: Alteeve Anvil! complete package. License: GPLv2+ @@ -381,7 +381,10 @@ fi %changelog -* tbd Madison Kelly 3.0-36 +* tbd Madison Kelly 3.0-37 +- Updated source. + +* Tue Nov 17 2020 Madison Kelly 3.0-36 - Updated source. * Thu Sep 03 2020 Madison Kelly 3.0-35 diff --git a/scancore-agents/scan-apc-pdu/scan-apc-pdu b/scancore-agents/scan-apc-pdu/scan-apc-pdu index 60f5f6d5..b0842974 100755 --- a/scancore-agents/scan-apc-pdu/scan-apc-pdu +++ b/scancore-agents/scan-apc-pdu/scan-apc-pdu @@ -589,11 +589,11 @@ sub find_changes }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0006", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0006", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0006", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } else @@ -605,11 +605,11 @@ sub find_changes }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0007", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0007", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0007", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } } @@ -620,17 +620,17 @@ sub find_changes $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { - name => $pdu_host_name, + name => $pdu_host_name, old_serial_number => $old_scan_apc_pdu_serial_number, new_serial_number => $new_scan_apc_pdu_serial_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0008", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0008", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0008", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_manufacture_date ne $old_scan_apc_pdu_manufacture_date) @@ -646,11 +646,11 @@ sub find_changes }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0009", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0009", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0009", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_firmware_version ne $old_scan_apc_pdu_firmware_version) @@ -666,11 +666,11 @@ sub find_changes }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0010", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0010", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0010", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_hardware_version ne $old_scan_apc_pdu_hardware_version) @@ -686,11 +686,11 @@ sub find_changes }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0011", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0011", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0011", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_ipv4_address ne $old_scan_apc_pdu_ipv4_address) @@ -706,11 +706,11 @@ sub find_changes }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0012", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0012", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0012", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_mac_address ne $old_scan_apc_pdu_mac_address) @@ -726,11 +726,11 @@ sub find_changes }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0013", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0013", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0013", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_mtu_size ne $old_scan_apc_pdu_mtu_size) @@ -740,17 +740,17 @@ sub find_changes $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { - name => $pdu_host_name, - old_mtu_size => $old_scan_apc_pdu_mtu_size, - new_mtu_size => $new_scan_apc_pdu_mtu_size, + name => $pdu_host_name, + old_mtu_size => $old_scan_apc_pdu_mtu_size, + new_mtu_size => $new_scan_apc_pdu_mtu_size, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0014", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0014", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0014", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_link_speed ne $old_scan_apc_pdu_link_speed) @@ -777,11 +777,11 @@ sub find_changes }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0015", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0015", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0015", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_phase_count ne $old_scan_apc_pdu_phase_count) @@ -797,11 +797,11 @@ sub find_changes }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0016", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0016", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0016", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_outlet_count ne $old_scan_apc_pdu_outlet_count) @@ -817,11 +817,11 @@ sub find_changes }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0017", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0017", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0017", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } @@ -885,11 +885,11 @@ WHERE # Normal, info-level $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0018", variables => $variables}); $anvil->Alert->register({ - alert_level => "info", - message => "scan_apc_pdu_message_0018", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "info", + message => "scan_apc_pdu_message_0018", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } elsif (($new_uptime < $old_uptime) && ($new_uptime < 300)) @@ -898,11 +898,11 @@ WHERE # the NIC rebooting and doesn't interfere with power. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0019", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0019", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0019", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } } @@ -935,11 +935,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0009", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0009", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0009", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); update_variables($anvil, $scan_apc_pdu_variable_uuid, "total_wattage_draw", $new_total_wattage_draw); @@ -991,11 +991,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0021", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0021", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0021", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } @@ -1014,11 +1014,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0022", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0022", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0022", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($old_scan_apc_pdu_phase_current_amperage ne $new_scan_apc_pdu_phase_current_amperage) @@ -1037,11 +1037,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0023", variables => $variables}); $anvil->Alert->register({ - alert_level => "info", - message => "scan_apc_pdu_message_0023", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "info", + message => "scan_apc_pdu_message_0023", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); # Cheack for low alerts to set or high alerts to clear @@ -1065,11 +1065,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0024", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0024", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0024", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } @@ -1163,11 +1163,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0030", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0030", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0030", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } } @@ -1213,11 +1213,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0031", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0031", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0031", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_outlet_name ne $old_scan_apc_pdu_outlet_name) @@ -1234,11 +1234,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0032", variables => $variables}); $anvil->Alert->register({ - alert_level => "notice", - message => "scan_apc_pdu_message_0032", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "notice", + message => "scan_apc_pdu_message_0032", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_outlet_on_phase ne $old_scan_apc_pdu_outlet_on_phase) @@ -1255,11 +1255,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0033", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0033", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0033", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } if ($new_scan_apc_pdu_outlet_state ne $old_scan_apc_pdu_outlet_state) @@ -1276,11 +1276,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0034", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0034", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0034", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } @@ -1331,11 +1331,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0035", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0035", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0035", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } @@ -1377,11 +1377,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0036", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0036", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0036", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } } @@ -1485,11 +1485,11 @@ INSERT INTO }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0037", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0037", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0037", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); # Insert the phase data @@ -1529,11 +1529,11 @@ INSERT INTO }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0038", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0038", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0038", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } @@ -1573,11 +1573,11 @@ INSERT INTO }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0039", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0039", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0039", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } } @@ -1620,11 +1620,11 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0040", variables => $variables}); $anvil->Alert->register({ - alert_level => "warning", - message => "scan_apc_pdu_message_0040", - message_variables => $variables, - set_by => $THIS_FILE, - sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, + alert_level => "warning", + message => "scan_apc_pdu_message_0040", + variables => $variables, + set_by => $THIS_FILE, + sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); } } @@ -2385,7 +2385,7 @@ sub gather_pdu_data if ($changed) { # Register an alert. - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_pdu_message_0002", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_pdu_message_0002", variables => $variables, set_by => $THIS_FILE}); } $anvil->nice_exit({exit_code => 1}); } @@ -2403,7 +2403,7 @@ sub gather_pdu_data { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_pdu_message_0003", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_pdu_message_0003", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_pdu_message_0003", variables => $variables, set_by => $THIS_FILE}); } } # Now read the phase data @@ -2453,7 +2453,7 @@ sub gather_pdu_data if ($changed) { # Register an alert. - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_pdu_message_0004", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_pdu_message_0004", variables => $variables, set_by => $THIS_FILE}); } $anvil->nice_exit({exit_code => 1}); } @@ -2471,7 +2471,7 @@ sub gather_pdu_data { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_pdu_message_0005", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_pdu_message_0005", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_pdu_message_0005", variables => $variables, set_by => $THIS_FILE}); } } # Now read the outlet data diff --git a/scancore-agents/scan-apc-ups/scan-apc-ups b/scancore-agents/scan-apc-ups/scan-apc-ups index 2451734a..d6e02efd 100755 --- a/scancore-agents/scan-apc-ups/scan-apc-ups +++ b/scancore-agents/scan-apc-ups/scan-apc-ups @@ -386,7 +386,7 @@ INSERT INTO last_transfer_reason => "#!string!scan_apc_ups_last_xfer_".sprintf("%04d", $scan_apc_ups_last_transfer_reason)."!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_pdu_message_0002", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_pdu_message_0002", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_pdu_message_0002", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); # Add any batteries. foreach my $battery_number (sort {$a cmp $b} keys %{$anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}}) @@ -450,7 +450,7 @@ INSERT INTO new_name => $old_scan_apc_ups_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0005", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0005", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0005", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } if ($scan_apc_ups_serial_number ne $old_scan_apc_ups_serial_number) { @@ -464,7 +464,7 @@ INSERT INTO new_value => $scan_apc_ups_serial_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0006", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0006", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0006", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } if ($scan_apc_ups_ip ne $old_scan_apc_ups_ip) { @@ -477,7 +477,7 @@ INSERT INTO new_value => $scan_apc_ups_ip, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0007", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0007", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0007", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } if ($scan_apc_ups_model ne $old_scan_apc_ups_model) { @@ -491,7 +491,7 @@ INSERT INTO new_value => $scan_apc_ups_model, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0008", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0008", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0008", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } if ($scan_apc_ups_ac_restore_delay ne $old_scan_apc_ups_ac_restore_delay) { @@ -504,7 +504,7 @@ INSERT INTO new_value => $scan_apc_ups_ac_restore_delay, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0009", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0009", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0009", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } if ($scan_apc_ups_shutdown_delay ne $old_scan_apc_ups_shutdown_delay) { @@ -517,7 +517,7 @@ INSERT INTO new_value => $scan_apc_ups_shutdown_delay, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0010", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0010", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0010", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } if ($scan_apc_ups_firmware_version ne $old_scan_apc_ups_firmware_version) { @@ -530,7 +530,7 @@ INSERT INTO new_value => $scan_apc_ups_firmware_version, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0011", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0011", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0011", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } # Has the health changed? This is fairly complex as there are many possible health @@ -669,7 +669,7 @@ INSERT INTO old_value => "#!string!scan_apc_ups_health_".sprintf("%04d", $say_old_scan_apc_ups_health)."!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0012", variables => $variables}); - $anvil->Alert->register({alert_level => $level, message => "scan_apc_ups_warning_0012", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => $level, message => "scan_apc_ups_warning_0012", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } if ($scan_apc_ups_low_transfer_voltage ne $old_scan_apc_ups_low_transfer_voltage) @@ -691,7 +691,7 @@ INSERT INTO old_value => $old_scan_apc_ups_low_transfer_voltage, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => $message_key, message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => $message_key, variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } # Has the last transfer reason changed? There are 10 reasons why this might happen, @@ -735,7 +735,7 @@ INSERT INTO old_value => "#!string!scan_apc_ups_last_transfer_".sprintf("%04d", $say_old_scan_apc_ups_last_transfer_reason)."!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0015", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0015", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0015", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } if ($scan_apc_ups_manufactured_date ne $old_scan_apc_ups_manufactured_date) { @@ -749,7 +749,7 @@ INSERT INTO new_value => $scan_apc_ups_manufactured_date, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0016", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0016", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0016", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } # Has the NMC's firmware changed? @@ -765,7 +765,7 @@ INSERT INTO new_value => $scan_apc_ups_nmc_firmware_version, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0017", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0017", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0017", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } # Has the NMC serial number changed? If the user changed the network card, @@ -782,7 +782,7 @@ INSERT INTO new_value => $scan_apc_ups_nmc_serial_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0018", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0018", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0018", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } # As with above, if the MAC address changed, it is probably because the NMC @@ -799,7 +799,7 @@ INSERT INTO new_value => $scan_apc_ups_nmc_mac_address, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_apc_ups_warning_0019", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0019", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0019", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } if ($ups_changed) @@ -888,7 +888,7 @@ WHERE old_value => "#!string!scan_apc_ups_sensitivity_".sprintf("%04d", $say_old_scan_apc_ups_input_sensitivity)."!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0020", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0020", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_warning_0020", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); } # Has the input voltage changed? @@ -942,7 +942,7 @@ WHERE { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0021", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0021", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0021", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } elsif ($scan_apc_ups_input_voltage > $high_transfer_voltage) @@ -954,7 +954,7 @@ WHERE { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0022", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0022", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0022", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } elsif ($scan_apc_ups_input_voltage > $clear_low_transfer) @@ -966,7 +966,7 @@ WHERE { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0023", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0023", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0023", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } } @@ -986,7 +986,7 @@ WHERE { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0026", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0026", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0026", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } elsif ($scan_apc_ups_input_voltage < $low_transfer_voltage) @@ -998,7 +998,7 @@ WHERE { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0027", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0027", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0027", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } elsif ($scan_apc_ups_input_voltage < $clear_high_transfer) @@ -1010,12 +1010,12 @@ WHERE { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0028", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0028", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0028", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => $message_key, message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => $message_key, variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } # Has the maximum input voltage seen in the last 60 seconds changed? @@ -1031,7 +1031,7 @@ WHERE old_value => $anvil->Convert->round({places => 1, number => $old_scan_apc_ups_input_1m_maximum_input_voltage}), }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0029", variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0029", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0029", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } # Has the minimum input voltage seen in the last 60 seconds changed? @@ -1046,7 +1046,7 @@ WHERE old_value => $anvil->Convert->round({places => 1, number => $old_scan_apc_ups_input_1m_minimum_input_voltage}), }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0030", variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0030", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0030", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { input_changed => $input_changed }}); @@ -1103,7 +1103,7 @@ WHERE # Register an alert. $log_normal = 0; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0032", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0032", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0032", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } } @@ -1124,7 +1124,7 @@ WHERE # Register an alert. $log_normal = 0; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0033", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0033", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0033", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } } @@ -1133,7 +1133,7 @@ WHERE { # This is an info level alert as it changes all the time. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0031", variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0031", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0031", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } } @@ -1174,7 +1174,7 @@ WHERE }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); - $anvil->Alert->register({alert_level => $level, message => $message_key, message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => $level, message => $message_key, variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } # Has the estimated runtime changed? @@ -1204,7 +1204,7 @@ WHERE # Register an alert. $send_alert = 0; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0038", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0038", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0038", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } elsif ($scan_apc_ups_output_estimated_runtime > $anvil->data->{'scan-apc-ups'}{low_hold_up_clear_threshold}) @@ -1217,7 +1217,7 @@ WHERE # Register an alert. $send_alert = 0; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0039", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0039", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0039", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } @@ -1225,7 +1225,7 @@ WHERE { # A normal minor change. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0037", variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0037", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0037", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } } @@ -1243,7 +1243,7 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0040", variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0040", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0040", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } # Has the output voltage changed? @@ -1260,7 +1260,7 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0041", variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0041", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0041", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } # This is always changing... @@ -1281,7 +1281,7 @@ WHERE }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_warning_0042", variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0042", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_warning_0042", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output_changed => $output_changed }}); @@ -1376,7 +1376,7 @@ WHERE battery_number => $battery_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0008", variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_message_0008", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_message_0008", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } # Has the battery health changed? @@ -1431,7 +1431,7 @@ WHERE battery_model => $scan_apc_ups_battery_model, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); - $anvil->Alert->register({alert_level => $level, message => $message_key, message_variables => $variables, sort_position => $sort_position, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => $level, message => $message_key, variables => $variables, sort_position => $sort_position, set_by => $THIS_FILE}); } # Has the battery model changed? @@ -1447,7 +1447,7 @@ WHERE old_value => $old_scan_apc_ups_battery_model, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0012", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0012", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0012", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } # If the battery charge percentage has changed, it will usually be an 'info' @@ -1539,7 +1539,7 @@ LIMIT 1 # Register an alert. $alert_sent = 1; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_message_0014", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_message_0014", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_message_0014", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } } @@ -1558,7 +1558,7 @@ LIMIT 1 # Register an alert. $alert_sent = 1; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_message_0016", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_message_0016", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_message_0016", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } } @@ -1569,7 +1569,7 @@ LIMIT 1 { my $sort_position = $level eq "warning" ? 1 : $anvil->data->{'scan-apc-pdu'}{alert_sort}++; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); - $anvil->Alert->register({alert_level => $level, message => $message_key, message_variables => $variables, sort_position => $sort_position, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => $level, message => $message_key, variables => $variables, sort_position => $sort_position, set_by => $THIS_FILE}); } } @@ -1586,7 +1586,7 @@ LIMIT 1 battery_number => $battery_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0017", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0017", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0017", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } # Has the battery state changed? There are four possible battery states. @@ -1640,7 +1640,7 @@ LIMIT 1 battery_number => $battery_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); - $anvil->Alert->register({alert_level => $level, clear_alert => $clear_alert, message => $message_key, message_variables => $variables, sort_position => $sort_position, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => $level, clear_alert => $clear_alert, message => $message_key, variables => $variables, sort_position => $sort_position, set_by => $THIS_FILE}); } # Has the battery's temperature changed? Alerts will be processed @@ -1678,7 +1678,7 @@ LIMIT 1 time_span => $time_span, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0023", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0023", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0023", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } @@ -1692,7 +1692,7 @@ LIMIT 1 battery_number => $battery_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0020", variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_message_0020", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_message_0020", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } } @@ -1710,7 +1710,7 @@ LIMIT 1 }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0021", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0021", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_apc_ups_message_0021", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } # Has the UPS battery voltage changed? @@ -1727,7 +1727,7 @@ LIMIT 1 battery_number => $battery_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_ups_message_0022", variables => $variables}); - $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_message_0022", message_variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "info", message => "scan_apc_ups_message_0022", variables => $variables, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, set_by => $THIS_FILE}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { battery_changed => $battery_changed }}); @@ -2192,7 +2192,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_ac_restore_delay", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_ac_restore_delay}, }, file => $THIS_FILE, line => __LINE__}); @@ -2217,7 +2217,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_shutdown_delay", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_shutdown_delay}, }, file => $THIS_FILE, line => __LINE__}); @@ -2496,7 +2496,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_percentage_charge", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_percentage_charge}, }, file => $THIS_FILE, line => __LINE__}); @@ -2567,7 +2567,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_temperature", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_temperature}, }, file => $THIS_FILE, line => __LINE__}); @@ -2597,7 +2597,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_alarm_temperature", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_alarm_temperature}, }, file => $THIS_FILE, line => __LINE__}); @@ -2632,7 +2632,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::battery::${battery_number}::scan_apc_ups_battery_voltage", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{battery}{$battery_number}{scan_apc_ups_battery_voltage}, }, file => $THIS_FILE, line => __LINE__}); @@ -2666,7 +2666,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_frequency", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_frequency}, }, file => $THIS_FILE, line => __LINE__}); @@ -2698,7 +2698,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_sensitivity", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_sensitivity}, }, file => $THIS_FILE, line => __LINE__}); @@ -2727,7 +2727,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_voltage", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_voltage}, }, file => $THIS_FILE, line => __LINE__}); @@ -2756,7 +2756,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_1m_maximum_input_voltage", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_maximum_input_voltage}, }, file => $THIS_FILE, line => __LINE__}); @@ -2784,7 +2784,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_input_1m_minimum_input_voltage", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_input_1m_minimum_input_voltage}, }, file => $THIS_FILE, line => __LINE__}); @@ -2818,7 +2818,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_load_percentage", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_load_percentage}, }, file => $THIS_FILE, line => __LINE__}); @@ -2848,7 +2848,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_time_on_batteries", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_time_on_batteries}, }, file => $THIS_FILE, line => __LINE__}); @@ -2876,7 +2876,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_estimated_runtime", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_estimated_runtime}, }, file => $THIS_FILE, line => __LINE__}); @@ -2905,7 +2905,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_frequency", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_frequency}, }, file => $THIS_FILE, line => __LINE__}); @@ -2934,7 +2934,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_voltage", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_voltage}, }, file => $THIS_FILE, line => __LINE__}); @@ -2964,7 +2964,7 @@ sub gather_ups_data }}); if (($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output} eq "--") or ($anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output} =~ /\D/)) { - $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", message_variables => { + $anvil->Log->entry({log_level => 1, message_key => "scan_apc_ups_error_0001", variables => { name => "ups::scan_apc_ups_uuid::${scan_apc_ups_uuid}::scan_apc_ups_output_total_output", value => $anvil->data->{ups}{scan_apc_ups_uuid}{$scan_apc_ups_uuid}{scan_apc_ups_output_total_output}, }, file => $THIS_FILE, line => __LINE__}); @@ -3114,7 +3114,7 @@ INSERT INTO $anvil->Alert->register({ alert_level => "warning", message => "scan_apc_pdu_message_0002", - message_variables => $variables, + variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); @@ -3177,7 +3177,7 @@ INSERT INTO $anvil->Alert->register({ alert_level => "warning", message => "scan_apc_pdu_message_0004", - message_variables => $variables, + variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); @@ -3244,7 +3244,7 @@ INSERT INTO $anvil->Alert->register({ alert_level => "warning", message => "scan_apc_pdu_message_0005", - message_variables => $variables, + variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++, }); @@ -3304,7 +3304,7 @@ sub process_temperature { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0001", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0001", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0001", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } elsif ($battery_temperature > $critical_temperature) @@ -3323,7 +3323,7 @@ sub process_temperature { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0003", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0003", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_apc_ups_warning_0003", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } @@ -3338,7 +3338,7 @@ sub process_temperature { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0004", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0004", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0004", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } elsif ($battery_temperature < $clear_critical_temperature) @@ -3352,7 +3352,7 @@ sub process_temperature { # Register an alert. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_apc_ups_warning_0002", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0002", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_apc_ups_warning_0002", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } diff --git a/scancore-agents/scan-cluster/scan-cluster b/scancore-agents/scan-cluster/scan-cluster index 251c778a..ad8cd0e9 100755 --- a/scancore-agents/scan-cluster/scan-cluster +++ b/scancore-agents/scan-cluster/scan-cluster @@ -151,7 +151,7 @@ WHERE old_cluster_name => $old_cluster_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0002", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0002", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0002", variables => $variables, set_by => $THIS_FILE}); } } else @@ -177,7 +177,7 @@ INSERT INTO my $variables = { cluster_name => $cluster_name }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0001", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0001", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0001", variables => $variables, set_by => $THIS_FILE}); } $anvil->Database->get_anvils(); @@ -230,7 +230,7 @@ INSERT INTO old_node_name => $old_scan_cluster_node_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0008", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0009", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0009", variables => $variables, set_by => $THIS_FILE}); } if ($scan_cluster_node_pacemaker_id ne $old_scan_cluster_node_pacemaker_id) { @@ -243,7 +243,7 @@ INSERT INTO old_pacemaker_id => $old_scan_cluster_node_pacemaker_id ? "#!string!scan_cluster_unit_0001!#" : "#!string!scan_cluster_unit_0002!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0004", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0004", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0004", variables => $variables, set_by => $THIS_FILE}); } if ($scan_cluster_node_in_ccm ne $old_scan_cluster_node_in_ccm) { @@ -256,7 +256,7 @@ INSERT INTO old_in_ccm => $old_scan_cluster_node_in_ccm ? "#!string!scan_cluster_unit_0001!#" : "#!string!scan_cluster_unit_0002!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0005", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0005", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0005", variables => $variables, set_by => $THIS_FILE}); } if ($scan_cluster_node_crmd_member ne $old_scan_cluster_node_crmd_member) { @@ -269,7 +269,7 @@ INSERT INTO old_crmd_member => $old_scan_cluster_node_crmd_member ? "#!string!scan_cluster_unit_0001!#" : "#!string!scan_cluster_unit_0002!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0006", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0006", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0006", variables => $variables, set_by => $THIS_FILE}); } if ($scan_cluster_node_cluster_member ne $old_scan_cluster_node_cluster_member) { @@ -282,7 +282,7 @@ INSERT INTO old_cluster_member => $old_scan_cluster_node_cluster_member ? "#!string!scan_cluster_unit_0001!#" : "#!string!scan_cluster_unit_0002!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0007", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0007", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0007", variables => $variables, set_by => $THIS_FILE}); } if ($scan_cluster_node_maintenance_mode ne $old_scan_cluster_node_maintenance_mode) { @@ -295,7 +295,7 @@ INSERT INTO old_maintenance_mode => $old_scan_cluster_node_maintenance_mode ? "#!string!scan_cluster_unit_0001!#" : "#!string!scan_cluster_unit_0002!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0008", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0008", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0008", variables => $variables, set_by => $THIS_FILE}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }}); @@ -365,7 +365,7 @@ INSERT INTO maintenance_mode => $scan_cluster_node_maintenance_mode ? "#!string!scan_cluster_unit_0001!#" : "#!string!scan_cluster_unit_0002!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0003", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0003", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_cluster_alert_0003", variables => $variables, set_by => $THIS_FILE}); } } @@ -530,7 +530,7 @@ sub collect_data # Register an alert. my $variables = { host_name => $anvil->Get->host_name() }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0010", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_cluster_alert_0010", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_cluster_alert_0010", variables => $variables, set_by => $THIS_FILE}); # See if I need to mark us as out of the cluster. Normally, our peer would do this, # but if we went down at the same time as our peer, both of us might not update the @@ -606,7 +606,7 @@ WHERE # Register an alert. my $variables = { host_name => $anvil->Get->host_name() }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_cluster_alert_0011", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_cluster_alert_0011", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", clear_alert => 1, message => "scan_cluster_alert_0011", variables => $variables, set_by => $THIS_FILE}); } } diff --git a/scancore-agents/scan-hardware/scan-hardware b/scancore-agents/scan-hardware/scan-hardware index aae425b6..09a6cd36 100755 --- a/scancore-agents/scan-hardware/scan-hardware +++ b/scancore-agents/scan-hardware/scan-hardware @@ -200,13 +200,15 @@ sub collect_cpu_data if ($changed) { # Register an alert. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0001", variables => { + my $variables = { these_flags => $these_flags, flags => $flags, - }}); + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0001", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", - message => "scan_hardware_alert_0001,!!these_flags!".$these_flags."!!,!!flags!".$flags."!!", + message => "scan_hardware_alert_0001", + variables => $variables, set_by => $THIS_FILE, }); } @@ -268,13 +270,15 @@ sub collect_cpu_data if ($changed) { # Register an alert. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0005", variables => { + my $variables = { this_model => $this_model, model => $model, - }}); + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0005", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", - message => "scan_hardware_alert_0005,!!this_model!".$this_model."!!,!!model!".$model."!!", + message => "scan_hardware_alert_0005", + variables => $variables, set_by => $THIS_FILE, }); } @@ -728,37 +732,57 @@ sub find_changes if ($new_scan_hardware_cpu_model ne $old_scan_hardware_cpu_model) { # CPU model changed, probably from a CPU upgrade or firmware flash, so just a notice level alert. - $update = 1; - $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0007,!!new!".$new_scan_hardware_cpu_model."!!,!!old!".$old_scan_hardware_cpu_model."!!"}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0007", variables => { new => $new_scan_hardware_cpu_model, old => $old_scan_hardware_cpu_model }}); + $update = 1; + my $variables = { + new => $new_scan_hardware_cpu_model, + old => $old_scan_hardware_cpu_model, + }; + $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0007", variables => $variables}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0007", variables => $variables}); } if ($new_scan_hardware_cpu_bugs ne $old_scan_hardware_cpu_bugs) { # This is probably from a CPU upgrade or firward flash - $update = 1; - $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0008,!!new!".$new_scan_hardware_cpu_bugs."!!,!!old!".$old_scan_hardware_cpu_bugs."!!"}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0008", variables => { new => $new_scan_hardware_cpu_bugs, old => $old_scan_hardware_cpu_bugs }}); + $update = 1; + my $variables = { + new => $new_scan_hardware_cpu_bugs, + old => $old_scan_hardware_cpu_bugs, + }; + $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0008", variables => $variables}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0008", variables => $variables}); } if ($new_scan_hardware_cpu_flags ne $old_scan_hardware_cpu_flags) { # This is probably from a CPU upgrade or firward flash - $update = 1; - $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0009,!!new!".$new_scan_hardware_cpu_flags."!!,!!old!".$old_scan_hardware_cpu_flags."!!"}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0009", variables => { new => $new_scan_hardware_cpu_flags, old => $old_scan_hardware_cpu_flags }}); + $update = 1; + my $variables = { + new => $new_scan_hardware_cpu_flags, + old => $old_scan_hardware_cpu_flags, + }; + $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0009", variables => $variables}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0009", variables => $variables}); } if ($new_scan_hardware_cpu_cores ne $old_scan_hardware_cpu_cores) { # This is probably from a CPU upgrade - $update = 1; - $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0010,!!new!".$new_scan_hardware_cpu_cores."!!,!!old!".$old_scan_hardware_cpu_cores."!!"}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0010", variables => { new => $new_scan_hardware_cpu_cores, old => $old_scan_hardware_cpu_cores }}); + $update = 1; + my $variables = { + new => $new_scan_hardware_cpu_cores, + old => $old_scan_hardware_cpu_cores, + }; + $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0010", variables => $variables}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0010", variables => $variables}); } if ($new_scan_hardware_cpu_threads ne $old_scan_hardware_cpu_threads) { # This is probably from a CPU upgrade - $update = 1; - $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0011,!!new!".$new_scan_hardware_cpu_threads."!!,!!old!".$old_scan_hardware_cpu_threads."!!"}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0011", variables => { new => $new_scan_hardware_cpu_threads, old => $old_scan_hardware_cpu_threads }}); + $update = 1; + my $variables = { + new => $new_scan_hardware_cpu_threads, + old => $old_scan_hardware_cpu_threads, + }; + $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0011", variables => $variables}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0011", variables => $variables}); } if ($new_scan_hardware_ram_total ne $old_scan_hardware_ram_total) { @@ -774,7 +798,7 @@ sub find_changes old => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hardware_ram_total})." (".$anvil->Convert->add_commas({number => $old_scan_hardware_ram_total})." #!string!scan_hardware_unit_0001!#)", difference => $anvil->Convert->bytes_to_human_readable({'bytes' => $difference})." (".$anvil->Convert->add_commas({number => $difference})." #!string!scan_hardware_unit_0001!#)", }; - $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "warning", message => "scan_hardware_alert_0012", message_variables => $variables}); + $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "warning", message => "scan_hardware_alert_0012", variables => $variables}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0012", variables => $variables}); } else @@ -787,7 +811,7 @@ sub find_changes old => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hardware_ram_total})." (".$anvil->Convert->add_commas({number => $old_scan_hardware_ram_total})." #!string!scan_hardware_unit_0001!#)", difference => $anvil->Convert->bytes_to_human_readable({'bytes' => $difference})." (".$anvil->Convert->add_commas({number => $difference})." #!string!scan_hardware_unit_0001!#)", }; - $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0029", message_variables => $variables}); + $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "notice", message => "scan_hardware_alert_0029", variables => $variables}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0029", variables => $variables}); } } @@ -808,7 +832,7 @@ sub find_changes old => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hardware_memory_total})." (".$anvil->Convert->add_commas({number => $old_scan_hardware_memory_total})." #!string!scan_hardware_unit_0001!#)", difference => $anvil->Convert->bytes_to_human_readable({'bytes' => $difference})." (".$anvil->Convert->add_commas({number => $difference})." #!string!scan_hardware_unit_0001!#)", }; - $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "warning", message => "scan_hardware_alert_0013", message_variables => $variables}); + $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "warning", message => "scan_hardware_alert_0013", variables => $variables}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0013", variables => $variables}); } } @@ -830,7 +854,7 @@ sub find_changes old => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hardware_swap_total})." (".$anvil->Convert->add_commas({number => $old_scan_hardware_swap_total})." #!string!scan_hardware_unit_0001!#)", difference => $anvil->Convert->bytes_to_human_readable({'bytes' => $difference})." (".$anvil->Convert->add_commas({number => $difference})." #!string!scan_hardware_unit_0001!#)", }; - $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "warning", message => "scan_hardware_alert_0014", message_variables => $variables}); + $anvil->Alert->register({set_by => $THIS_FILE, alert_level => "warning", message => "scan_hardware_alert_0014", variables => $variables}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0014", variables => $variables}); } } @@ -936,13 +960,7 @@ sub find_changes swap_percent => $new_swap_percent_used, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "scan_hardware_alert_0020", variables => $variables}); - $anvil->Alert->register({ - debug => 2, - alert_level => "warning", - message => "scan_hardware_alert_0020", - message_variables => $variables, - set_by => $THIS_FILE, - }); + $anvil->Alert->register({alert_level => "warning", message => "scan_hardware_alert_0020", variables => $variables, set_by => $THIS_FILE }); } } elsif ($new_scan_hardware_swap_free < $anvil->data->{scancore}{'scan-hardware'}{swap}{clear_threshold}) @@ -958,19 +976,15 @@ sub find_changes if ($changed) { # Log and register that the alert has cleared. - my $say_used = $anvil->Convert->bytes_to_human_readable({'bytes' => $new_swap_bytes_used}); - my $say_swap = $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hardware_swap_total}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "scan_hardware_alert_0021", variables => { + my $say_used = $anvil->Convert->bytes_to_human_readable({'bytes' => $new_swap_bytes_used}); + my $say_swap = $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hardware_swap_total}); + my $variables = { say_used => $say_used, say_swap => $say_swap, swap_percent => $new_swap_percent_used, - }}); - $anvil->Alert->register({ - debug => 2, - alert_level => "warning", - message => "scan_hardware_alert_0021,!!say_used!".$say_used."!!,!!say_swap!".$say_swap."!!,!!swap_percent!".$new_swap_percent_used."!!", - set_by => $THIS_FILE, - }); + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "scan_hardware_alert_0021", variables => $variables}); + $anvil->Alert->register({alert_level => "warning", message => "scan_hardware_alert_0021", variables => $variables, set_by => $THIS_FILE }); } } } @@ -1008,7 +1022,7 @@ WHERE else { # New record, send an alert telling that we've found data. - my $message_variables = { + my $variables = { total_cores => $new_scan_hardware_cpu_cores, total_threads => $new_scan_hardware_cpu_threads, cpu_bugs => $new_scan_hardware_cpu_bugs, @@ -1022,8 +1036,8 @@ WHERE ram_swap_total => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hardware_swap_total})." (".$anvil->Convert->add_commas({number => $new_scan_hardware_swap_total})." #!string!scan_hardware_unit_0001!#)", ram_swap_free => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hardware_swap_free})." (".$anvil->Convert->add_commas({number => $new_scan_hardware_swap_free})." #!string!scan_hardware_unit_0001!#)", }; - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_hardware_alert_0022", message_variables => $message_variables, set_by => $THIS_FILE }); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0019", variables => $message_variables}); + $anvil->Alert->register({alert_level => "notice", message => "scan_hardware_alert_0022", variables => $variables, set_by => $THIS_FILE }); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0019", variables => $variables}); # INSERT my $scan_hardware_uuid = $anvil->Get->uuid(); @@ -1129,7 +1143,7 @@ INSERT INTO old_serial_number => $old_scan_hardware_ram_module_serial_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "scan_hardware_alert_0023", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "warning", message => "scan_hardware_alert_0023", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_hardware_alert_0023", variables => $variables, set_by => $THIS_FILE}); } else { @@ -1146,7 +1160,7 @@ INSERT INTO old_serial_number => $old_scan_hardware_ram_module_serial_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "scan_hardware_alert_0024", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "warning", message => "scan_hardware_alert_0024", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_hardware_alert_0024", variables => $variables, set_by => $THIS_FILE}); } my $query = " @@ -1178,7 +1192,7 @@ WHERE serial_number => $new_scan_hardware_ram_module_serial_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "scan_hardware_alert_0025", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "notice", message => "scan_hardware_alert_0025", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_hardware_alert_0025", variables => $variables, set_by => $THIS_FILE}); # INSERT my $scan_hardware_ram_module_uuid = $anvil->Get->uuid(); @@ -1243,7 +1257,7 @@ INSERT INTO old_serial_number => $old_scan_hardware_ram_module_serial_number, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "scan_hardware_alert_0026", variables => $variables}); - $anvil->Alert->register({debug => 2, alert_level => "warning", message => "scan_hardware_alert_0026", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_hardware_alert_0026", variables => $variables, set_by => $THIS_FILE}); my $query = " UPDATE @@ -1331,7 +1345,7 @@ sub process_health difference => $anvil->Convert->bytes_to_human_readable({'bytes' => $difference})." (".$anvil->Convert->add_commas({number => $difference})." #!string!suffix_0009!#)", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0027", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_hardware_alert_0027", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_hardware_alert_0027", variables => $variables, set_by => $THIS_FILE}); } } my ($health_uuid) = $anvil->Database->insert_or_update_health({ @@ -1364,7 +1378,7 @@ sub process_health ram => $anvil->Convert->bytes_to_human_readable({'bytes' => $hardware_ram_total})." (".$anvil->Convert->add_commas({number => $hardware_ram_total})." #!string!suffix_0009!#)", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hardware_alert_0028", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_hardware_alert_0028", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_hardware_alert_0028", variables => $variables, set_by => $THIS_FILE}); } my ($health_uuid) = $anvil->Database->insert_or_update_health({ debug => 2, diff --git a/scancore-agents/scan-ipmitool/scan-ipmitool b/scancore-agents/scan-ipmitool/scan-ipmitool index 87ed2aa7..fe96680f 100755 --- a/scancore-agents/scan-ipmitool/scan-ipmitool +++ b/scancore-agents/scan-ipmitool/scan-ipmitool @@ -108,14 +108,13 @@ if (($< != 0) && ($> != 0)) $anvil->nice_exit({exit_code => 1}); } -### TODO: Rework this whole agent... -# Get the handle to the AN::Tools and preset some variables I will use. +# Here we store data and variables for this agent. $anvil->data->{'scan-ipmitool'} = { disable => 0, # It will be marked as 'clear' when the temperature drops this many °C below the # critical temperature. machine => {}, - alert_sort => 0, + alert_sort => 2, # These are used when no other limits are set for a given sensor. thresholds => { 'default' => { @@ -261,95 +260,27 @@ sub process_health # This will hold our updates. $anvil->data->{'scan-ipmitool'}{queries} = []; - # Read in previous health values. - my $query = " -SELECT - health_uuid, - 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__}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results }}); - foreach my $row (@{$results}) - { - my $health_uuid = $row->[0]; - my $health_source_name = $row->[1]; - my $health_source_weight = $row->[2]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - health_uuid => $health_uuid, - health_source_name => $health_source_name, - health_source_weight => $health_source_weight, - }}); - - $anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}{uuid} = $health_uuid; - $anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}{value} = $health_source_weight; - } - # Read in the new ones foreach my $health_source_name (sort {$a cmp $b} keys %{$anvil->data->{'scan-ipmitool'}{health}{new}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "health::new::$health_source_name" => $anvil->data->{'scan-ipmitool'}{health}{new}{$health_source_name}, }}); - if (exists $anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}) - { - # We've seen this before. Has it changed? - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "health::old::${health_source_name}::value" => $anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}{value}, - }}); - - if ($anvil->data->{'scan-ipmitool'}{health}{new}{$health_source_name} ne $anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}{value}) - { - # It has changed, update it. - my $query = " -UPDATE - health -SET - health_source_weight = ".$anvil->Database->quote($anvil->data->{'scan-ipmitool'}{health}{new}{$health_source_name}).", - modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." -WHERE - health_uuid = ".$anvil->Database->quote($anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}{uuid})." -;"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); - - push @{$anvil->data->{'scan-ipmitool'}{queries}}, $query; - } + + my $health_uuid = $anvil->Database->insert_or_update_health({ + debug => 2, + cache => $anvil->data->{'scan-ipmitool'}{queries}, + health_host_uuid => $anvil->Get->host_uuid, + health_agent_name => $THIS_FILE, + health_source_name => $health_source_name, + health_source_weight => $anvil->data->{'scan-ipmitool'}{health}{new}{$health_source_name}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_uuid => $health_uuid }}); - # Delete the new old key, regardless of whether it has changed now. - delete $anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}; - } - else + # Delete the new old key, if it existed + if ($anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}) { - # New entry, INSERT it. - my $query = " -INSERT INTO - health -( - health_uuid, - health_host_uuid, - health_agent_name, - health_source_name, - health_source_weight, - modified_date -) VALUES ( - ".$anvil->Database->quote($anvil->Get->uuid).", - ".$anvil->Database->quote($anvil->Get->host_uuid).", - ".$anvil->Database->quote($THIS_FILE).", - ".$anvil->Database->quote($health_source_name).", - ".$anvil->Database->quote($anvil->data->{'scan-ipmitool'}{health}{new}{$health_source_name}).", - ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." -);"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); - - push @{$anvil->data->{'scan-ipmitool'}{queries}}, $query; + delete $anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}; } } @@ -357,26 +288,13 @@ INSERT INTO foreach my $health_source_name (sort {$a cmp $b} keys %{$anvil->data->{'scan-ipmitool'}{health}{old}}) { # Well set the source name to 'DELETED'. - my $query = " -UPDATE - health -SET - health_source_name = 'DELETED', - modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." -WHERE - health_uuid = ".$anvil->Database->quote($anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}{uuid})." -;"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); - push @{$anvil->data->{'scan-ipmitool'}{queries}}, $query; - - $query = " -DELETE FROM - health -WHERE - health_uuid = ".$anvil->Database->quote($anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}{uuid})." -;"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); - push @{$anvil->data->{'scan-ipmitool'}{queries}}, $query; + my $health_uuid = $anvil->Database->insert_or_update_health({ + debug => 2, + cache => $anvil->data->{'scan-ipmitool'}{queries}, + health_uuid => $anvil->data->{'scan-ipmitool'}{health}{old}{$health_source_name}{uuid}, + 'delete' => 1, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_uuid => $health_uuid }}); } # Now commit the changes. @@ -436,7 +354,7 @@ sub find_changes sensor => $scan_ipmitool_sensor_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_ipmitool_message_0002", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_ipmitool_message_0002", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_ipmitool_message_0002", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++}); next; } if (not $new_scan_ipmitool_value_sensor_value) @@ -446,7 +364,7 @@ sub find_changes sensor => $scan_ipmitool_sensor_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_ipmitool_message_0003", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_ipmitool_message_0003", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_ipmitool_message_0003", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++}); next; } @@ -597,10 +515,10 @@ WHERE old_high_warning => $old_scan_ipmitool_sensor_high_warning eq "" ? "--" : $old_scan_ipmitool_sensor_high_warning, old_low_warning => $old_scan_ipmitool_sensor_low_warning eq "" ? "--" : $old_scan_ipmitool_sensor_low_warning, }; - my $sort_position = (($level eq "warning") or ($level eq "critical")) ? 1 : $anvil->data->{'scan-apc-pdu'}{alert_sort}++; + my $sort_position = (($level eq "warning") or ($level eq "critical")) ? 1 : $anvil->data->{'scan-ipmitool'}{alert_sort}++; my $log_level = (($level eq "warning") or ($level eq "critical")) ? 1 : 2; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables}); - $anvil->Alert->register({alert_level => $level, message => $message_key, message_variables => $variables, set_by => $THIS_FILE, sort_position => $sort_position}); + $anvil->Alert->register({alert_level => $level, message => $message_key, variables => $variables, set_by => $THIS_FILE, sort_position => $sort_position}); } else { @@ -613,7 +531,7 @@ WHERE old_sensor_value => $old_sensor_value }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); - $anvil->Alert->register({alert_level => $level, message => $message_key, message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => $level, message => $message_key, variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++}); } } else @@ -632,18 +550,18 @@ WHERE { # Huh, interesting. Well, update $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - new_scan_ipmitool_sensor_units => $new_scan_ipmitool_sensor_units, - new_scan_ipmitool_sensor_status => $new_scan_ipmitool_sensor_status, + new_scan_ipmitool_sensor_units => $new_scan_ipmitool_sensor_units, + new_scan_ipmitool_sensor_status => $new_scan_ipmitool_sensor_status, new_scan_ipmitool_sensor_high_critical => $new_scan_ipmitool_sensor_high_critical, - new_scan_ipmitool_sensor_high_warning => $new_scan_ipmitool_sensor_high_warning, - new_scan_ipmitool_sensor_low_critical => $new_scan_ipmitool_sensor_low_critical, - new_scan_ipmitool_sensor_low_warning => $new_scan_ipmitool_sensor_low_warning, - old_scan_ipmitool_sensor_units => $old_scan_ipmitool_sensor_units, - old_scan_ipmitool_sensor_status => $old_scan_ipmitool_sensor_status, + new_scan_ipmitool_sensor_high_warning => $new_scan_ipmitool_sensor_high_warning, + new_scan_ipmitool_sensor_low_critical => $new_scan_ipmitool_sensor_low_critical, + new_scan_ipmitool_sensor_low_warning => $new_scan_ipmitool_sensor_low_warning, + old_scan_ipmitool_sensor_units => $old_scan_ipmitool_sensor_units, + old_scan_ipmitool_sensor_status => $old_scan_ipmitool_sensor_status, old_scan_ipmitool_sensor_high_critical => $old_scan_ipmitool_sensor_high_critical, - old_scan_ipmitool_sensor_high_warning => $old_scan_ipmitool_sensor_high_warning, - old_scan_ipmitool_sensor_low_critical => $old_scan_ipmitool_sensor_low_critical, - old_scan_ipmitool_sensor_low_warning => $old_scan_ipmitool_sensor_low_warning, + old_scan_ipmitool_sensor_high_warning => $old_scan_ipmitool_sensor_high_warning, + old_scan_ipmitool_sensor_low_critical => $old_scan_ipmitool_sensor_low_critical, + old_scan_ipmitool_sensor_low_warning => $old_scan_ipmitool_sensor_low_warning, }}); ### NOTE: These were added to debug duplicate scan_ipmitool_values entries. @@ -654,7 +572,7 @@ WHERE sensor => $scan_ipmitool_sensor_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_ipmitool_message_0015", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_ipmitool_message_0015", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_ipmitool_message_0015", variables => $variables, set_by => $THIS_FILE, show_header => 0, sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++}); next; } @@ -709,10 +627,10 @@ AND old_low_warning => $old_scan_ipmitool_sensor_low_warning eq "" ? "--" : $old_scan_ipmitool_sensor_low_warning." ".$old_scan_ipmitool_sensor_units, }; - my $sort_position = (($level eq "warning") or ($level eq "critical")) ? 1 : $anvil->data->{'scan-apc-pdu'}{alert_sort}++; + my $sort_position = (($level eq "warning") or ($level eq "critical")) ? 1 : $anvil->data->{'scan-ipmitool'}{alert_sort}++; my $log_level = (($level eq "warning") or ($level eq "critical")) ? 1 : 2; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables}); - $anvil->Alert->register({alert_level => $level, message => $message_key, message_variables => $variables, set_by => $THIS_FILE, sort_position => $sort_position}); + $anvil->Alert->register({alert_level => $level, message => $message_key, variables => $variables, set_by => $THIS_FILE, sort_position => $sort_position}); } # Delete the old key so that I can check to see what sensors @@ -726,7 +644,7 @@ AND if ($anvil->data->{ipmi}{$machine}{scan_ipmitool_sensor_name}{$scan_ipmitool_sensor_name}{scan_ipmitool_value_sensor_value} eq "") { # Ignore it. - $anvil->Log->entry({log_level => 3, message_key => "scan_ipmitool_log_0005", message_variables => { sensor_name => $scan_ipmitool_sensor_name }, file => $THIS_FILE, line => __LINE__}); + $anvil->Log->entry({log_level => 3, message_key => "scan_ipmitool_log_0005", variables => { sensor_name => $scan_ipmitool_sensor_name }, file => $THIS_FILE, line => __LINE__}); delete $anvil->data->{ipmi}{$machine}{scan_ipmitool_sensor_name}{$scan_ipmitool_sensor_name}; next; } @@ -746,7 +664,7 @@ AND sensor => $scan_ipmitool_sensor_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_ipmitool_message_0017", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_ipmitool_message_0017", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_ipmitool_message_0017", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++}); next; } if (not $new_scan_ipmitool_value_sensor_value) @@ -756,7 +674,7 @@ AND sensor => $scan_ipmitool_sensor_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_ipmitool_message_0018", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_ipmitool_message_0018", message_variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-apc-pdu'}{alert_sort}++}); + $anvil->Alert->register({alert_level => "notice", message => "scan_ipmitool_message_0018", variables => $variables, set_by => $THIS_FILE, sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++}); next; } @@ -841,10 +759,10 @@ INSERT INTO }}); } - my $sort_position = $level eq "warning" ? 1 : $anvil->data->{'scan-apc-pdu'}{alert_sort}++; + my $sort_position = $level eq "warning" ? 1 : $anvil->data->{'scan-ipmitool'}{alert_sort}++; my $log_level = $level eq "warning" ? 1 : 2; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => "scan_ipmitool_message_0019", variables => $variables}); - $anvil->Alert->register({alert_level => $level, message => "scan_ipmitool_message_0019", message_variables => $variables, set_by => $THIS_FILE, sort_position => $sort_position}); + $anvil->Alert->register({alert_level => $level, message => "scan_ipmitool_message_0019", variables => $variables, set_by => $THIS_FILE, sort_position => $sort_position}); } } } @@ -860,7 +778,7 @@ INSERT INTO if ($anvil->data->{ipmi}{$machine}{scan_ipmitool_sensor_name}{$scan_ipmitool_sensor_name}{scan_ipmitool_value_sensor_value} eq "") { # Ignore it. - $anvil->Log->entry({log_level => 3, message_key => "scan_ipmitool_log_0005", message_variables => { sensor_name => $scan_ipmitool_sensor_name }, file => $THIS_FILE, line => __LINE__}); + $anvil->Log->entry({log_level => 3, message_key => "scan_ipmitool_log_0005", variables => { sensor_name => $scan_ipmitool_sensor_name }, file => $THIS_FILE, line => __LINE__}); delete $anvil->data->{ipmi}{$machine}{scan_ipmitool_sensor_name}{$scan_ipmitool_sensor_name}; next; } @@ -983,10 +901,10 @@ INSERT INTO low_critical => $new_scan_ipmitool_sensor_low_critical eq "" ? "--" : $new_scan_ipmitool_sensor_low_critical." ".$new_scan_ipmitool_sensor_units, low_warning => $new_scan_ipmitool_sensor_low_warning eq "" ? "--" : $new_scan_ipmitool_sensor_low_warning." ".$new_scan_ipmitool_sensor_units, }; - my $sort_position = $level eq "warning" ? 1 : $anvil->data->{'scan-apc-pdu'}{alert_sort}++; + my $sort_position = $level eq "warning" ? 1 : $anvil->data->{'scan-ipmitool'}{alert_sort}++; my $log_level = $level eq "warning" ? 1 : 2; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => "scan_ipmitool_message_0019", variables => $variables}); - $anvil->Alert->register({alert_level => $level, message => "scan_ipmitool_message_0019", message_variables => $variables, set_by => $THIS_FILE, sort_position => $sort_position}); + $anvil->Alert->register({alert_level => $level, message => "scan_ipmitool_message_0019", variables => $variables, set_by => $THIS_FILE, sort_position => $sort_position}); } } @@ -1112,6 +1030,8 @@ sub process_temperature my ($anvil, $machine) = @_; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine => $machine }}); + $anvil->data->{'scan-ipmitool'}{queries} = []; + # First, read in all existing entries. We'll compare and UPDATE or INSERT as needed and DELETE any # stale entries. my $query = " @@ -1160,11 +1080,11 @@ AND my $new_temperature_state = $anvil->data->{new}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_state}; my $new_temperature_is = $anvil->data->{new}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_is}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "scan_ipmitool_sensor_name" => $scan_ipmitool_sensor_name, - "new_temperature_uuid" => $new_temperature_uuid, - "new_temperature_value_c" => $new_temperature_value_c, - "new_temperature_state" => $new_temperature_state, - "new_temperature_is" => $new_temperature_is, + scan_ipmitool_sensor_name => $scan_ipmitool_sensor_name, + new_temperature_uuid => $new_temperature_uuid, + new_temperature_value_c => $new_temperature_value_c, + new_temperature_state => $new_temperature_state, + new_temperature_is => $new_temperature_is, }}); if ($new_temperature_value_c eq "na") @@ -1205,7 +1125,7 @@ AND # If it's not OK, set the weight if ($new_temperature_state ne "ok") { - my $health_source_name = "temperature:".$scan_ipmitool_sensor_name; + my $health_source_name = "temperature:".$scan_ipmitool_sensor_name; $anvil->data->{'scan-ipmitool'}{health}{new}{$health_source_name} = $new_temperature_weight; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "health::new::$health_source_name" => $anvil->data->{'scan-ipmitool'}{health}{new}{$health_source_name}, @@ -1214,123 +1134,50 @@ AND } # Now see if the variable was seen before and, if so, if it changed. + my $temperature_uuid = ""; if (ref($anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name})) { # Update the existing entry, if needed. - my $old_temperature_uuid = $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_uuid}; - my $old_temperature_value_c = $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_value_c}; - my $old_temperature_weight = $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_weight}; - my $old_temperature_state = $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_state}; - my $old_temperature_is = $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_is}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - old_temperature_uuid => $old_temperature_uuid, - old_temperature_value_c => $old_temperature_value_c, - old_temperature_weight => $old_temperature_weight, - old_temperature_state => $old_temperature_state, - old_temperature_is => $old_temperature_is, - }}); - - if (($new_temperature_value_c ne $old_temperature_value_c) or - ($new_temperature_weight ne $old_temperature_weight) or - ($new_temperature_state ne $old_temperature_state) or - ($new_temperature_is ne $old_temperature_is)) - { - my $query = " -UPDATE - temperature -SET - temperature_value_c = ".$anvil->Database->quote($new_temperature_value_c).", - temperature_weight = ".$anvil->Database->quote($new_temperature_weight).", - temperature_state = ".$anvil->Database->quote($new_temperature_state).", - temperature_is = ".$anvil->Database->quote($new_temperature_is).", - modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." -WHERE - temperature_uuid = ".$anvil->Database->quote($old_temperature_uuid)."; -"; - push @{$anvil->data->{'scan-ipmitool'}{queries}}, $query; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - name1 => "query", value1 => $query - }}); - } - - # We still want this value, so delete it from the hash so it doesn't get deleted in - # the next step. - delete $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}; + my $temperature_uuid = $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_uuid}; + } + + # Generate and store the UUID. + my $sensor_host_uuid = $anvil->Get->host_uuid_from_name({host_name => $machine}); + if (not $sensor_host_uuid) + { + $sensor_host_uuid = $machine; } - else + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_host_uuid => $sensor_host_uuid }}); + $temperature_uuid = $anvil->Database->insert_or_update_temperature({ + cache => $anvil->data->{'scan-ipmitool'}{queries}, + debug => 2, + temperature_uuid => $temperature_uuid, + temperature_host_uuid => $anvil->Get->host_uuid, + temperature_agent_name => $THIS_FILE, + temperature_sensor_host => $sensor_host_uuid, + temperature_sensor_name => $scan_ipmitool_sensor_name, + temperature_value_c => $new_temperature_value_c, + temperature_state => $new_temperature_state, + temperature_is => $new_temperature_is, + temperature_weight => $new_temperature_weigh, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { temperature_uuid => $temperature_uuid }}); + + # We still want this value, so delete it from the hash. + if (exists $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}) { - ### New entry - # Generate and store the UUID. - my $scan_ipmitool_uuid = $anvil->Get->uuid() or $anvil->Alert->error({title_key => "error_title_0020", message_key => "error_message_0024", code => 2, file => $THIS_FILE, line => __LINE__});; - $anvil->data->{new}{$machine}{temperature}{$scan_ipmitool_sensor_name}{scan_ipmitool_uuid} = $scan_ipmitool_uuid; - my $query = " -INSERT INTO - temperature -( - temperature_uuid, - temperature_host_uuid, - temperature_sensor_host, - temperature_sensor_name, - temperature_agent_name, - temperature_value_c, - temperature_weight, - temperature_state, - temperature_is, - modified_date -) VALUES ( - ".$anvil->Database->quote($scan_ipmitool_uuid).", - ".$anvil->Database->quote($anvil->Get->host_uuid).", - ".$anvil->Database->quote($machine).", - ".$anvil->Database->quote($scan_ipmitool_sensor_name).", - ".$anvil->Database->quote($THIS_FILE).", - ".$anvil->Database->quote($new_temperature_value_c).", - ".$anvil->Database->quote($new_temperature_weight).", - ".$anvil->Database->quote($new_temperature_state).", - ".$anvil->Database->quote($new_temperature_is).", - ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." -); -"; - push @{$anvil->data->{'scan-ipmitool'}{queries}}, $query; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + delete $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}; } - } - - # Now, if any undeleted old entries remain, delete them from the database. - foreach my $scan_ipmitool_sensor_name (sort {$a cmp $b} keys %{$anvil->data->{old}{$machine}{temperature}}) - { - my $temperature_uuid = $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_uuid}; - my $old_temperature_value_c = $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_value_c}; - my $old_temperature_state = $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_state}; - my $old_temperature_is = $anvil->data->{old}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_is}; + + $anvil->data->{new}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_uuid} = $temperature_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - temperature_uuid => $temperature_uuid, - old_temperature_value_c => $old_temperature_value_c, - old_temperature_state => $old_temperature_state, - old_temperature_is => $old_temperature_is, + "new::${machine}::temperature::${scan_ipmitool_sensor_name}::temperature_uuid" => $anvil->data->{new}{$machine}{temperature}{$scan_ipmitool_sensor_name}{temperature_uuid}, }}); - - # Mark the sensor as DELETEd. - my $query = " -UPDATE - temperature -SET - temperature_state = 'DELETED', - modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." -WHERE - temperature_uuid = ".$anvil->Database->quote($temperature_uuid)." -;"; - push @{$anvil->data->{'scan-ipmitool'}{queries}}, $query; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); - $query = " -DELETE FROM - temperature -WHERE - temperature_uuid = ".$anvil->Database->quote($temperature_uuid)." -"; - push @{$anvil->data->{'scan-ipmitool'}{queries}}, $query; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); } + # Now commit the changes. + $anvil->Database->write({query => $anvil->data->{'scan-ipmitool'}{queries}, source => $THIS_FILE, line => __LINE__}); + return(0); } @@ -1835,7 +1682,7 @@ sub process_temperature_change old_sensor_value => $old_sensor_value }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "scan_ipmitool_message_0010", variables => $variables}); - $anvil->Alert->register({alert_level => "warning", message => "scan_ipmitool_message_0010", message_variables => $variables, sort_position => 1, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_ipmitool_message_0010", variables => $variables, sort_position => 1, set_by => $THIS_FILE}); } } } diff --git a/scancore-agents/scan-ipmitool/scan-ipmitool.xml b/scancore-agents/scan-ipmitool/scan-ipmitool.xml index 98253c9e..459db991 100644 --- a/scancore-agents/scan-ipmitool/scan-ipmitool.xml +++ b/scancore-agents/scan-ipmitool/scan-ipmitool.xml @@ -11,7 +11,7 @@ NOTE: All string keys MUST be prefixed with the agent name! ie: 'scan_ipmitool_l - + No IPMI BMC found on this host nor where any other machines with IPMI found or where accessible. Nothing to do. diff --git a/scancore-agents/scan-lvm/scan-lvm b/scancore-agents/scan-lvm/scan-lvm index f285a6bd..92af839c 100755 --- a/scancore-agents/scan-lvm/scan-lvm +++ b/scancore-agents/scan-lvm/scan-lvm @@ -174,7 +174,7 @@ sub find_changes_in_lvs lv_name => $scan_lvm_lv_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0021", variables => $variables}); - $anvil->Alert->register({debug => 3, clear_alert => 1, alert_level => "warning", message => "scan_lvm_alert_0021", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({clear_alert => 1, alert_level => "warning", message => "scan_lvm_alert_0021", variables => $variables, set_by => $THIS_FILE}); } else { @@ -185,7 +185,7 @@ sub find_changes_in_lvs old_lv_name => $old_scan_lvm_lv_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0022", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0022", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0022", variables => $variables, set_by => $THIS_FILE}); } } if ($scan_lvm_lv_attributes ne $old_scan_lvm_lv_attributes) @@ -200,7 +200,7 @@ sub find_changes_in_lvs old_attributes => $old_scan_lvm_lv_attributes, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0023", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0023", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0023", variables => $variables, set_by => $THIS_FILE}); } if ($scan_lvm_lv_on_vg ne $old_scan_lvm_lv_on_vg) { @@ -214,7 +214,7 @@ sub find_changes_in_lvs old_lv_on_vg => $old_scan_lvm_lv_on_vg, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0024", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "warning", message => "scan_lvm_alert_0024", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0024", variables => $variables, set_by => $THIS_FILE}); } if ($scan_lvm_lv_size ne $old_scan_lvm_lv_size) { @@ -233,13 +233,13 @@ sub find_changes_in_lvs { # Grew, probably added a new PV $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0025", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0025", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0025", variables => $variables, set_by => $THIS_FILE}); } else { # Shrank, $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0026", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0026", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0026", variables => $variables, set_by => $THIS_FILE}); } } if ($scan_lvm_lv_path ne $old_scan_lvm_lv_path) @@ -254,7 +254,7 @@ sub find_changes_in_lvs old_lv_path => $old_scan_lvm_lv_path, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0027", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0027", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0027", variables => $variables, set_by => $THIS_FILE}); } if ($scan_lvm_lv_on_pvs ne $old_scan_lvm_lv_on_pvs) { @@ -267,7 +267,7 @@ sub find_changes_in_lvs old_lv_on_pvs => $old_scan_lvm_lv_path, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0028", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0028", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0028", variables => $variables, set_by => $THIS_FILE}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }}); @@ -308,7 +308,7 @@ WHERE lv_on_pvs => $scan_lvm_lv_on_pvs, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0029", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0029", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0029", variables => $variables, set_by => $THIS_FILE}); my $scan_lvm_lv_uuid = $anvil->Get->uuid(); my $query = " @@ -360,7 +360,7 @@ INSERT INTO lv_name => $old_scan_lvm_lv_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0031", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "warning", message => "scan_lvm_alert_0031", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0031", variables => $variables, set_by => $THIS_FILE}); # Update it PV name to be 'DELTED' my $query = " @@ -431,7 +431,7 @@ sub find_changes_in_vgs vg_name => $scan_lvm_vg_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0011", variables => $variables}); - $anvil->Alert->register({debug => 3, clear_alert => 1, alert_level => "warning", message => "scan_lvm_alert_0011", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({clear_alert => 1, alert_level => "warning", message => "scan_lvm_alert_0011", variables => $variables, set_by => $THIS_FILE}); } else { @@ -442,7 +442,7 @@ sub find_changes_in_vgs old_vg_name => $old_scan_lvm_vg_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0012", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0012", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0012", variables => $variables, set_by => $THIS_FILE}); } } if ($scan_lvm_vg_attributes ne $old_scan_lvm_vg_attributes) @@ -457,7 +457,7 @@ sub find_changes_in_vgs old_attributes => $old_scan_lvm_vg_attributes, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0013", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0013", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0013", variables => $variables, set_by => $THIS_FILE}); } if ($scan_lvm_vg_extent_size ne $old_scan_lvm_vg_extent_size) { @@ -473,7 +473,7 @@ sub find_changes_in_vgs old_vg_extent_size_bytes => $anvil->Convert->add_commas({number => $old_scan_lvm_vg_extent_size}), }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0014", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "warning", message => "scan_lvm_alert_0014", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0014", variables => $variables, set_by => $THIS_FILE}); } if ($scan_lvm_vg_size ne $old_scan_lvm_vg_size) { @@ -492,13 +492,13 @@ sub find_changes_in_vgs { # Grew, probably added a new PV $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0015", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0015", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0015", variables => $variables, set_by => $THIS_FILE}); } else { # Shrank, wat? $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0016", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "warning", message => "scan_lvm_alert_0016", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0016", variables => $variables, set_by => $THIS_FILE}); } } if ($scan_lvm_vg_free ne $old_scan_lvm_vg_free) @@ -518,13 +518,13 @@ sub find_changes_in_vgs { # Likely a new LV was created or an existing one was extended. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0017", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0017", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0017", variables => $variables, set_by => $THIS_FILE}); } else { # An old LV was probably removed. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0018", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0018", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0018", variables => $variables, set_by => $THIS_FILE}); } } @@ -566,7 +566,7 @@ WHERE vg_free_bytes => $anvil->Convert->add_commas({number => $scan_lvm_vg_free}), }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0020", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0020", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0020", variables => $variables, set_by => $THIS_FILE}); my $scan_lvm_vg_uuid = $anvil->Get->uuid(); my $query = " @@ -616,7 +616,7 @@ INSERT INTO vg_name => $old_scan_lvm_vg_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0030", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "warning", message => "scan_lvm_alert_0030", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0030", variables => $variables, set_by => $THIS_FILE}); # Update it PV name to be 'DELTED' my $query = " @@ -686,7 +686,7 @@ sub find_changes_in_pvs pv_name => $scan_lvm_pv_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0001", variables => $variables}); - $anvil->Alert->register({debug => 3, clear_alert => 1, alert_level => "warning", message => "scan_lvm_alert_0001", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({clear_alert => 1, alert_level => "warning", message => "scan_lvm_alert_0001", variables => $variables, set_by => $THIS_FILE}); } else { @@ -697,7 +697,7 @@ sub find_changes_in_pvs old_pv_name => $old_scan_lvm_pv_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0002", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "warning", message => "scan_lvm_alert_0002", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0002", variables => $variables, set_by => $THIS_FILE}); } } if ($scan_lvm_pv_used_by_vg ne $old_scan_lvm_pv_used_by_vg) @@ -714,7 +714,7 @@ sub find_changes_in_pvs vg_name => $scan_lvm_pv_used_by_vg, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0004", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0004", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0004", variables => $variables, set_by => $THIS_FILE}); } else { @@ -726,7 +726,7 @@ sub find_changes_in_pvs old_vg_name => $old_scan_lvm_pv_used_by_vg, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0005", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0005", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0005", variables => $variables, set_by => $THIS_FILE}); } } if ($scan_lvm_pv_attributes ne $old_scan_lvm_pv_attributes) @@ -741,7 +741,7 @@ sub find_changes_in_pvs old_attributes => $old_scan_lvm_pv_attributes, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0006", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0006", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0006", variables => $variables, set_by => $THIS_FILE}); } if ($scan_lvm_pv_size ne $old_scan_lvm_pv_size) { @@ -760,13 +760,13 @@ sub find_changes_in_pvs { # Yup $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0007", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0007", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0007", variables => $variables, set_by => $THIS_FILE}); } else { # Uhhhh... We'll make this a warning as it shouldn't happen. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0008", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "warning", message => "scan_lvm_alert_0008", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0008", variables => $variables, set_by => $THIS_FILE}); } } if ($scan_lvm_pv_free ne $old_scan_lvm_pv_free) @@ -786,13 +786,13 @@ sub find_changes_in_pvs { # Yup $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0009", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0009", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0009", variables => $variables, set_by => $THIS_FILE}); } else { # Uhhhh... We'll make this a warning as it shouldn't happen. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0010", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "warning", message => "scan_lvm_alert_0010", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0010", variables => $variables, set_by => $THIS_FILE}); } } @@ -833,7 +833,7 @@ WHERE pv_free_bytes => $anvil->Convert->add_commas({number => $scan_lvm_pv_free}), }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0019", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "notice", message => "scan_lvm_alert_0019", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0019", variables => $variables, set_by => $THIS_FILE}); my $scan_lvm_pv_uuid = $anvil->Get->uuid(); my $query = " @@ -883,7 +883,7 @@ INSERT INTO pv_name => $old_scan_lvm_pv_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0003", variables => $variables}); - $anvil->Alert->register({debug => 3, alert_level => "warning", message => "scan_lvm_alert_0003", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0003", variables => $variables, set_by => $THIS_FILE}); # Update it PV name to be 'DELTED' my $query = " diff --git a/scancore-agents/scan-server/scan-server b/scancore-agents/scan-server/scan-server index 11f46939..bfc70a83 100755 --- a/scancore-agents/scan-server/scan-server +++ b/scancore-agents/scan-server/scan-server @@ -255,7 +255,7 @@ DELETED - Marks a server as no longer existing definition => $virsh_definition, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0006", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0006", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0006", variables => $variables, set_by => $THIS_FILE}); } $anvil->data->{'scan-server'}{server_name}{$server_name}{server_uuid} = $server_uuid; @@ -366,7 +366,7 @@ DELETED - Marks a server as no longer existing new_definition => $database_definition, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0001", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0001", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0001", variables => $variables, set_by => $THIS_FILE}); } else { @@ -383,7 +383,7 @@ DELETED - Marks a server as no longer existing new_definition => $on_disk_definition, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0002", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0002", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0002", variables => $variables, set_by => $THIS_FILE}); } # In either case, update the virsh definition from the disk now (either to load the @@ -413,7 +413,7 @@ DELETED - Marks a server as no longer existing new_definition => $virsh_definition, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0003", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0003", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0003", variables => $variables, set_by => $THIS_FILE}); } my ($virsh_live_definition, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{virsh}." dumpxml ".$server_name, source => $THIS_FILE, line => __LINE__}); @@ -472,7 +472,7 @@ DELETED - Marks a server as no longer existing new_name => $server_name, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0004", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0004", message_variables => $variables, set_by => $THIS_FILE }); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0004", variables => $variables, set_by => $THIS_FILE }); $update = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update => $update }}); } @@ -485,7 +485,7 @@ DELETED - Marks a server as no longer existing new_state => $server_state, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0005", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0005", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0005", variables => $variables, set_by => $THIS_FILE}); $update = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update => $update }}); @@ -511,7 +511,7 @@ DELETED - Marks a server as no longer existing new_boot_time_epoch => $anvil->Convert->add_commas({number => $server_boot_time}), }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0008", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0008", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0008", variables => $variables, set_by => $THIS_FILE}); $update = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update => $update }}); } @@ -526,7 +526,7 @@ DELETED - Marks a server as no longer existing new_anvil_uuid => $server_anvil_uuid, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0009", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0009", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0009", variables => $variables, set_by => $THIS_FILE}); $update = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update => $update }}); } @@ -536,7 +536,7 @@ DELETED - Marks a server as no longer existing my $say_user_stop = $server_user_stop eq "TRUE" ? "scan_server_alert_0010" : "scan_server_alert_0011"; my $variables = { server => $server_name }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $say_user_stop, variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => $say_user_stop, message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => $say_user_stop, variables => $variables, set_by => $THIS_FILE}); $update = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update => $update }}); } @@ -551,7 +551,7 @@ DELETED - Marks a server as no longer existing new_host_uuid => $server_host_uuid, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0012", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0012", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0012", variables => $variables, set_by => $THIS_FILE}); $update = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update => $update }}); } @@ -567,7 +567,7 @@ DELETED - Marks a server as no longer existing new_ram_in_use_bytes => $anvil->Convert->add_commas({number => $old_server_ram_in_use}), }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0013", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0013", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0013", variables => $variables, set_by => $THIS_FILE}); $update = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update => $update }}); } @@ -584,7 +584,7 @@ DELETED - Marks a server as no longer existing new_configured_ram_bytes => $anvil->Convert->add_commas({number => $old_server_configured_ram}), }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $say_ram, variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => $say_ram, message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => $say_ram, variables => $variables, set_by => $THIS_FILE}); $update = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update => $update }}); } @@ -720,7 +720,7 @@ WHERE # Now register an alert. my $variables = { server => $server_name }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0007", variables => $variables}); - $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0007", message_variables => $variables, set_by => $THIS_FILE}); + $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0007", variables => $variables, set_by => $THIS_FILE}); } } diff --git a/scancore-agents/scan-storcli/scan-storcli b/scancore-agents/scan-storcli/scan-storcli new file mode 100755 index 00000000..271940d7 --- /dev/null +++ b/scancore-agents/scan-storcli/scan-storcli @@ -0,0 +1,10076 @@ +#!/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 LSI-based RAID controllers using the 'storcli64' command line tool. +# +# https://alteeve.com +# +# Exit Codes: +# 0 - Success +# 1 - storcli64 not installed +# 2 - storcli64 is installed but it is not executable. +# 3 - No LSI-based controllers found. +# 4 - Got data from the wrong controller. +# 5 - Unexpecte status when querying adapter +# 6 - Failed to parse out the controller's serial number. +# 7 - Failed to match a BBU to a host controller's serial number. +# 8 - Failed to match a controller's serial number to a controller UUID. +# 9 - Failed to match a Cachevault to a host controller's serial number. +# 10 - Failed to match a virtual drive ID string to a host controller's serial number. +# 11 - Failed to match a drive group ID string to a host controller's serial number. +# 12 - Failed to get the controller serial number that a physical drive is connected to. +# 13 - Failed to get the serial number of a physical drive. +# 14 - Drive group UUID doesn't exist when it should have. +# 15 - Controller serial number for an existing drive group wasn't found. +# 16 - Non-numeric value in numeric virtual drive variable. +# +# 255 - The host's UUID isn't in the hosts table yet, ScanCore itself hasn't been run. +# +# TODO: +# - DELETE a remaining_reserve_space variable from a history.scan_storcli_variables on one dashboard and then +# trigger a resync. Appears to be causing a duplicate insert error. +# +# - Check the cache policy and reset it to 'writeback' if the BBU/FBU is healthy and the cache changes to +# write-through. +# - When two or more drives have errors, 'drive:other_error_count' is only set to '1'. It should be the +# number of drives with errors. Also, if the error on one drive got above 100, its weight should be '2' and +# above 1000, set to '3'. +# +# NOTE: +# - LSI seems to flip between "Virtual Drive" and "Virtual Disk". We're standardizing on "Virtual Drive". +# +# 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({log_level => 2, log_secure => 1}); +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); + +# 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-storcli'} = { + alert_sort => 2, + arguments => { + adapter_count => "show ctrlcount", + alarm_state => "show alarm", + # BBU battery or FBU capacitor bank info. + bgi_rate => "show bgirate", + bbu_data => "/bbu show all", + cc_rate => "show ccrate", + cachevault_data => "/cv show all", + controller_info => "show all", + physical_disk_data => "/eall /sall show all", + performance_mode => "show perfmode", + pr_rate => "show prrate", + rebuild_rate => "show rebuildrate", + virtual_drive_data => "/vall show all", + }, + disable => 0, + 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 => {}, + }, + cachevaults => { + by_serial => {}, + by_uuid => {}, + }, + bbus => { + by_serial => {}, + by_uuid => {}, + }, + physical_drives => { + by_serial => {}, + by_uuid => {}, + }, + disable => 0, + language => "en_CA", + log_level => 1, + log_language => "en_CA", + log_file => "/var/log/ScanCore.log", + log_db_transactions => 0, + thresholds => { + # 45646-00B_Cache_Backup_Products_SAS_SATA_RAID_Controller_UserGd.pdf -> Specifications for the BBU Models + bbu => { + normal => { + high_warning => 35, + high_critical => 40, + low_warning => 15, + low_critical => 10, + jump => 3, + buffer => 2, + }, + discharging => { + high_warning => 50, + high_critical => 55, + low_warning => 15, + low_critical => 10, + jump => 3, + buffer => 2, + }, + }, + # 45646-00B_Cache_Backup_Products_SAS_SATA_RAID_Controller_UserGd.pdf -> Specifications for the Cachevaul Models + cachevault => { + high_warning => 50, + high_critical => 55, + low_warning => 5, + low_critical => 0, + jump => 5, + buffer => 3, + }, + # 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 + hdd => { + high_warning => 50, + high_critical => 55, + low_warning => 10, + low_critical => 5, + jump => 3, + buffer => 2, + }, + # http://toshiba.semicon-storage.com/us/product/storage-products/enterprise-ssd/px02smb-px02smfxxx.html + ssd => { + high_warning => 50, + high_critical => 55, + low_warning => 5, + low_critical => 0, + jump => 3, + buffer => 2, + }, + }, + # See email from M. Labrosse on 2014/04/14 @ 12:20; Specs not publicly available + raid_on_chip => { + high_warning => 108, + high_critical => 115, + low_warning => 15, + low_critical => 10, + jump => 10, + buffer => 5, + }, + }, + queries => [], +}; + +$anvil->Storage->read_config(); +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, '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-storcli'}{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 => 1, key => "scan_storcli_message_0001"}); + +# This does two things; It checks to see if storcli64 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_lsi_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 looks for anything other than temperature sensors that will feed into the health of the node. +sub pre_process_health +{ + my ($anvil) = @_; + + # Is the array degraded or partially degraded? + foreach my $id_string (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}}) + { + foreach my $drive_group (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$id_string}{drive_group}}) + { + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + + my $value = $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}; + if ($value eq "Partially Degraded") + { + # Partially degraded array + my $health_source_name = "drive_group:".$id_string,"-".$drive_group.":".$variable; + $anvil->data->{health}{new}{$health_source_name} = 5; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::$health_source_name" => $anvil->data->{health}{new}{$health_source_name}, + }}); + } + elsif ($value eq "Degraded") + { + # Degraded array + my $health_source_name = "drive_group:".$id_string,"-".$drive_group.":".$variable; + $anvil->data->{health}{new}{$health_source_name} = 10; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::$health_source_name" => $anvil->data->{health}{new}{$health_source_name}, + }}); + } + } + } + } + + # Controllers. + foreach my $serial_number (sort {$a cmp $b} keys %{$anvil->data->{controller}{serial_number}}) + { + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{serial_number}{$serial_number}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::serial_number::${serial_number}::variable::$variable" => $anvil->data->{controller}{serial_number}{$serial_number}{variable}{$variable}, + }}); + + my $value = $anvil->data->{controller}{serial_number}{$serial_number}{variable}{$variable}; + if (($variable eq "alarm_state") && (lc($value) ne "missing") && (lc($value) ne "off")) + { + my $health_source_name = "controller:".$variable; + $anvil->data->{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->{health}{new}{$health_source_name}, + }}); + } + elsif (($variable eq "memory_correctable_errors") && ($value ne "0")) + { + # TODO: I might want to scale this where 1~X = 1, Y~Z = 3, etc + my $health_source_name = "controller:".$variable; + $anvil->data->{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->{health}{new}{$health_source_name}, + }}); + } + elsif (($variable eq "memory_uncorrectable_errors") && ($value ne "0")) + { + # TODO: I might want to scale this where 1~X = 5, Y~Z = 10, etc + my $health_source_name = "controller:".$variable; + $anvil->data->{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->{health}{new}{$health_source_name}, + }}); + } + elsif (($variable eq "controller_status") && (lc($value) ne "optimal")) + { + # 'Needs Attention' when array degrades + my $health_source_name = "controller:".$variable; + $anvil->data->{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->{health}{new}{$health_source_name}, + }}); + } + } + } + + # Physical Drives. + foreach my $scan_storcli_virtual_drive_id_string (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}}) + { + foreach my $drive_group (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}}) + { + foreach my $enclosure_id (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}}) + { + foreach my $slot_number (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}}) + { + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${scan_storcli_virtual_drive_id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::${variable}" => $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + + my $value = $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}; + if ((($variable eq "media_error_count") or ($variable eq "other_error_count")) && ($value ne "0")) + { + # If the count is over 50, set to '2'. If over 5, set to 1. + my $health_source_name = "drive:".$variable; + if ($value > 50) + { + $anvil->data->{health}{new}{$health_source_name} = 2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:alarm-state" => $anvil->data->{health}{new}{'controller:alarm-state'}, + }}); + } + elsif ($value > 5) + { + $anvil->data->{health}{new}{$health_source_name} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:alarm-state" => $anvil->data->{health}{new}{'controller:alarm-state'}, + }}); + } + } + elsif (($variable eq "predictive_failure_count") && ($value ne "0")) + { + # A single tick of this requires immediate replacement. + my $health_source_name = "drive:".$variable; + $anvil->data->{health}{new}{$health_source_name} = 2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::controller:alarm-state" => $anvil->data->{health}{new}{'controller:alarm-state'}, + }}); + } + } + } + } + } + } + + # Cachevaults. + foreach my $cachevault_serial_number (sort {$a cmp $b} keys %{$anvil->data->{cachevault}{serial_number}}) + { + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cachevault::serial_number::${cachevault_serial_number}::variable::$variable" => $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{variable}{$variable}, + }}); + + my $value = $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{variable}{$variable}; + if (($variable eq "replacement_required") && (lc($value) eq "yes")) + { + my $health_source_name = "cachevault:".$cachevault_serial_number.":".$variable; + $anvil->data->{health}{new}{$health_source_name} = 5; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::$health_source_name" => $anvil->data->{health}{new}{$health_source_name}, + }}); + } + } + } + + # BBUs + foreach my $bbu_serial_number (sort {$a cmp $b} keys %{$anvil->data->{bbu}{serial_number}}) + { + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "bbu::serial_number::${bbu_serial_number}::variable::$variable" => $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}{$variable}, + }}); + + my $value = $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}{$variable}; + if (($variable eq "replacement_required") && (lc($value) eq "yes")) + { + my $health_source_name = "bbu:".$bbu_serial_number.":".$variable; + $anvil->data->{health}{new}{$health_source_name} = 5; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::$health_source_name" => $anvil->data->{health}{new}{$health_source_name}, + }}); + } + } + } + + 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-storcli'}{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__}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "results" => $results, + }}); + 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->{health}{old}{$health_source_name}{uuid} = $health_uuid; + $anvil->data->{health}{old}{$health_source_name}{value} = $health_source_weight; + } + + # Read in the new ones + foreach my $health_source_name (sort {$a cmp $b} keys %{$anvil->data->{health}{new}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::$health_source_name" => $anvil->data->{health}{new}{$health_source_name}, + }}); + + my $health_uuid = ""; + if (exists $anvil->data->{health}{old}{$health_source_name}) + { + $health_uuid = $anvil->data->{health}{old}{$health_source_name}{uuid}; + } + $health_uuid = $anvil->Database->insert_or_update_health({ + debug => 2, + cache => $anvil->data->{'scan-ipmitool'}{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->{health}{new}{$health_source_name}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_uuid => $health_uuid }}); + } + + # Delete any old entries that are left. + foreach my $health_source_name (sort {$a cmp $b} keys %{$anvil->data->{health}{old}}) + { + # Well set the source name to 'DELETED'. + my $health_uuid = $anvil->Database->insert_or_update_health({ + debug => 2, + cache => $anvil->data->{'scan-ipmitool'}{queries}, + 'delete' => 1, + health_uuid => $anvil->data->{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-storcli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-storcli'}{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_weight, + 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_uuid = $row->[0]; + my $temperature_sensor_name = $row->[1]; + my $temperature_sensor_host = $row->[2]; + my $temperature_value_c = $row->[3]; + my $temperature_weight = $row->[4]; + my $temperature_state = $row->[5]; + my $temperature_is = $row->[6]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + temperature_uuid => $temperature_uuid, + temperature_sensor_name => $temperature_sensor_name, + temperature_sensor_host => $temperature_sensor_host, + temperature_value_c => $temperature_value_c, + temperature_weight => $temperature_weight, + temperature_state => $temperature_state, + temperature_is => $temperature_is, + }}); + + $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host} = { + temperature_uuid => $temperature_uuid, + temperature_value_c => $temperature_value_c, + temperature_state => $temperature_state, + temperature_is => $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 = ""; + if ($new_temperature_state eq "warning") + { + $health_source_name = "temperature:".$serial_number; + $anvil->data->{health}{new}{$health_source_name} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::$health_source_name" => $anvil->data->{health}{new}{$health_source_name}, + }}); + } + elsif ($new_temperature_state eq "critical") + { + $health_source_name = "temperature:".$serial_number; + $anvil->data->{health}{new}{$health_source_name} = 2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "health::new::$health_source_name" => $anvil->data->{health}{new}{$health_source_name}, + }}); + } + + ### TODO: Left off here. + # Store + my $temperature_uuid = ""; + if (exists $anvil->data->{old}{temperature}{$variable}{$serial_number}) + { + $temperature_uuid = $anvil->data->{old}{temperature}{$variable}{$serial_number}{temperature_uuid}; + } + $temperature_uuid = $anvil->Database->insert_or_update_temperature({ + cache => $anvil->data->{'scan-ipmitool'}{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->{health}{new}{$health_source_name}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { temperature_uuid => $temperature_uuid }}); + } + } + + # Commit the queries. + $anvil->Database->write({query => $anvil->data->{'scan-storcli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-storcli'}{queries} = []; + + return(0); +} + +# This returns the value for a given storcli DB variable from this host. +sub get_scan_storcli_variable +{ + my ($anvil, $scan_storcli_variable_name, $scan_storcli_variable_source_table, $scan_storcli_variable_source_uuid) = @_; + + my $query = " +SELECT + scan_storcli_variable_value +FROM + scan_storcli_variables +WHERE + scan_storcli_variable_name = ".$anvil->Database->quote($scan_storcli_variable_name)." +AND + scan_storcli_variable_source_table = ".$anvil->Database->quote($scan_storcli_variable_source_table)." +AND + scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_variable_source_uuid)." +AND + scan_storcli_variable_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + my $value = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $value = "" if not defined $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + + return($value); +} + +# 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); + process_bbus($anvil); + process_cachevaults($anvil); + process_virtual_drives($anvil); # This calls process_drive_groups(); + process_physical_disks($anvil); + + return(0); +} + +# Look for added, changed or deleted drive groups. +sub process_drive_groups +{ + my ($anvil, $scan_storcli_virtual_drive_id_string, $scan_storcli_drive_group_virtual_drive_uuid, $controller_uuid, $host_controller_serial_number) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_virtual_drive_id_string => $scan_storcli_virtual_drive_id_string, + scan_storcli_drive_group_virtual_drive_uuid => $scan_storcli_drive_group_virtual_drive_uuid, + controller_uuid => $controller_uuid, + host_controller_serial_number => $host_controller_serial_number, + }}); + + ### NOTE: The parent VD may be VANISHED, in which case this DG is likely VANISHED, too. + # Show the drive group and drives. + foreach my $drive_group (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}}) + { + my $scan_storcli_drive_group_id_string = $scan_storcli_virtual_drive_id_string."-dg".$drive_group; + my $virtual_drive = ($scan_storcli_virtual_drive_id_string =~ /-vd(\d+)$/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_virtual_drive_id_string => $scan_storcli_virtual_drive_id_string, + scan_storcli_drive_group_id_string => $scan_storcli_drive_group_id_string, + virtual_drive => $virtual_drive, + drive_group => $drive_group, + }}); + + # Make sure I have the host's serial number and UUID. + if (not $host_controller_serial_number) + { + # Error! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_error_0011", variables => { id_string => $scan_storcli_virtual_drive_id_string }}); + $anvil->nice_exit({exit_code => 11}); + } + if (not $controller_uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_error_0008", variables => { serial_number => $host_controller_serial_number }}); + $anvil->nice_exit({exit_code => 8}); + } + + ### NOTE: This is here purely for debugging. + # Show the basic drive group data + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + $anvil->Log->variables({ + source => $THIS_FILE, + line => __LINE__, + level => 2, + prefix => $scan_storcli_drive_group_id_string." (".$drive_group.") - ".$type, + list => $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{$type}, + }); + } + + # Is this a new Drive Group? + my $scan_storcli_drive_group_uuid = ""; + my $is_new = 0; + if (exists $anvil->data->{'scan-storcli'}{drive_groups}{by_id_string}{$scan_storcli_drive_group_id_string}) + { + # Yes! + $scan_storcli_drive_group_uuid = $anvil->data->{'scan-storcli'}{drive_groups}{by_id_string}{$scan_storcli_drive_group_id_string}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_storcli_drive_group_uuid => $scan_storcli_drive_group_uuid }}); + } + else + { + # No, this is a new Drive Group. Create a new UUID for it. + $scan_storcli_drive_group_uuid = $anvil->Get->uuid(); + $is_new = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_drive_group_uuid => $scan_storcli_drive_group_uuid, + is_new => $is_new, + }}); + + # Add the keys for looking it up by UUID or serial number. + $anvil->data->{'scan-storcli'}{drive_groups}{by_id_string}{$scan_storcli_drive_group_id_string} = $scan_storcli_drive_group_uuid; + $anvil->data->{'scan-storcli'}{drive_groups}{by_uuid}{$scan_storcli_drive_group_uuid} = $scan_storcli_virtual_drive_id_string; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::drive_groups::by_id_string::$scan_storcli_virtual_drive_id_string" => $anvil->data->{'scan-storcli'}{drive_groups}{by_id_string}{$scan_storcli_drive_group_id_string}, + "scan-storcli::drive_groups::by_uuid::$scan_storcli_drive_group_uuid" => $anvil->data->{'scan-storcli'}{drive_groups}{by_uuid}{$scan_storcli_drive_group_uuid}, + }}); + } + + my $new_drive_group_access = ""; + my $new_drive_group_array_size = ""; + my $new_drive_group_array_state = ""; + my $new_drive_group_cache = ""; + my $new_drive_group_cachecade = ""; + my $new_drive_group_consistent = ""; + my $new_drive_group_disk_cache = ""; + my $new_drive_group_raid_type = ""; + my $new_drive_group_read_cache = ""; + my $new_drive_group_scheduled_cc = ""; + my $new_drive_group_write_cache = ""; + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${scan_storcli_virtual_drive_id_string}::drive_group::${drive_group}::variable::${variable}" => $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + + # Store and delete the value + if ($variable eq "access") + { + $new_drive_group_access = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_access => $new_drive_group_access }}); + next; + } + if ($variable eq "array_size") + { + $new_drive_group_array_size = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_array_size => $new_drive_group_array_size }}); + next; + } + if ($variable eq "array_state") + { + $new_drive_group_array_state = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_array_state => $new_drive_group_array_state }}); + next; + } + if ($variable eq "cache") + { + $new_drive_group_cache = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_cache => $new_drive_group_cache }}); + next; + } + if ($variable eq "cachecade") + { + $new_drive_group_cachecade = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_cachecade => $new_drive_group_cachecade }}); + next; + } + if ($variable eq "consistent") + { + $new_drive_group_consistent = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_consistent => $new_drive_group_consistent }}); + next; + } + if ($variable eq "disk_cache") + { + $new_drive_group_disk_cache = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_disk_cache => $new_drive_group_disk_cache }}); + next; + } + if ($variable eq "raid_type") + { + $new_drive_group_raid_type = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_raid_type => $new_drive_group_raid_type }}); + next; + } + if ($variable eq "read_cache") + { + $new_drive_group_read_cache = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_read_cache => $new_drive_group_read_cache }}); + next; + } + if ($variable eq "scheduled_consistency_check") + { + $new_drive_group_scheduled_cc = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_scheduled_cc => $new_drive_group_scheduled_cc }}); + next; + } + if ($variable eq "write_cache") + { + $new_drive_group_write_cache = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drive_group_write_cache => $new_drive_group_write_cache }}); + next; + } + } + + # Pull out the rest of the variables now. If the Drive Group is new, all variables will be + # INSERTed. If the Drive Group 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 Drive + # Group 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'. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { is_new => $is_new }}); + if ($is_new) + { + ### NOTE: DG 9999 will be mostly blank and that is fine + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_drive_group_uuid => $scan_storcli_drive_group_uuid, + controller_uuid => $controller_uuid, + scan_storcli_drive_group_id_string => $scan_storcli_drive_group_id_string, + new_drive_group_access => $new_drive_group_access, + new_drive_group_array_size => $new_drive_group_array_size, + new_drive_group_array_state => $new_drive_group_array_state, + new_drive_group_cache => $new_drive_group_cache, + new_drive_group_cachecade => $new_drive_group_cachecade, + new_drive_group_consistent => $new_drive_group_consistent, + new_drive_group_disk_cache => $new_drive_group_disk_cache, + new_drive_group_raid_type => $new_drive_group_raid_type, + new_drive_group_read_cache => $new_drive_group_read_cache, + new_drive_group_scheduled_cc => $new_drive_group_scheduled_cc, + new_drive_group_write_cache => $new_drive_group_write_cache, + }}); + + ### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'. + # Send an alert telling the user that we've found a new controller. + my $variables = { + on_controller => $host_controller_serial_number, + id_string => $scan_storcli_drive_group_id_string, + access => $new_drive_group_access, + array_size => $new_drive_group_array_size, + array_state => $new_drive_group_array_state, + cache => $new_drive_group_cache, + cachecade => $new_drive_group_cachecade, + consistent => $new_drive_group_consistent, + disk_cache => $new_drive_group_disk_cache, + raid_type => $new_drive_group_raid_type, + read_cache => $new_drive_group_read_cache, + scheduled_cc => $new_drive_group_scheduled_cc, + write_cache => $new_drive_group_write_cache, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_note_0005", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + message => "scan_storcli_note_0005", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_drive_groups +( + scan_storcli_drive_group_uuid, + scan_storcli_drive_group_host_uuid, + scan_storcli_drive_group_virtual_drive_uuid, + scan_storcli_drive_group_id_string, + scan_storcli_drive_group_access, + scan_storcli_drive_group_array_size, + scan_storcli_drive_group_array_state, + scan_storcli_drive_group_cache, + scan_storcli_drive_group_cachecade, + scan_storcli_drive_group_consistent, + scan_storcli_drive_group_disk_cache, + scan_storcli_drive_group_raid_type, + scan_storcli_drive_group_read_cache, + scan_storcli_drive_group_scheduled_cc, + scan_storcli_drive_group_write_cache, + modified_date +) VALUES ( + ".$anvil->Database->quote($scan_storcli_drive_group_uuid).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($scan_storcli_drive_group_virtual_drive_uuid).", + ".$anvil->Database->quote($scan_storcli_drive_group_id_string).", + ".$anvil->Database->quote($new_drive_group_access).", + ".$anvil->Database->quote($new_drive_group_array_size).", + ".$anvil->Database->quote($new_drive_group_array_state).", + ".$anvil->Database->quote($new_drive_group_cache).", + ".$anvil->Database->quote($new_drive_group_cachecade).", + ".$anvil->Database->quote($new_drive_group_consistent).", + ".$anvil->Database->quote($new_drive_group_disk_cache).", + ".$anvil->Database->quote($new_drive_group_raid_type).", + ".$anvil->Database->quote($new_drive_group_read_cache).", + ".$anvil->Database->quote($new_drive_group_scheduled_cc).", + ".$anvil->Database->quote($new_drive_group_write_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-storcli'}{queries}}, $query; + + # Process the rest of the variables and temperatures now. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{$type}}) + { + my $value = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + temperature => $temperature, + }}); + + # Send an alert telling the user that we've found a new controller. + my $variables = { + name => $variable, + value => $value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_note_0002", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + message => "scan_storcli_note_0002", + show_header => 0, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_drive_groups', + ".$anvil->Database->quote($scan_storcli_drive_group_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($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-storcli'}{queries}}, $query; + } + } + } + else + { + ### NOTE: The serial number should never change (a changed SN/Drive Group should be + ### picked up as a new Drive Group), but we check/update just to be safe. + # Look for changes. + my $main_table_changed = 0; + my $old_drive_group_id_string = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_id_string}; + my $old_drive_group_virtual_drive_uuid = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_virtual_drive_uuid}; + my $old_drive_group_access = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_access}; + my $old_drive_group_array_size = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_array_size}; + my $old_drive_group_array_state = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_array_state}; + my $old_drive_group_cache = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_cache}; + my $old_drive_group_cachecade = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_cachecade}; + my $old_drive_group_consistent = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_consistent}; + my $old_drive_group_disk_cache = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_disk_cache}; + my $old_drive_group_raid_type = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_raid_type}; + my $old_drive_group_read_cache = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_read_cache}; + my $old_drive_group_scheduled_cc = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_scheduled_cc}; + my $old_drive_group_write_cache = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_write_cache}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_drive_group_id_string => $scan_storcli_drive_group_id_string, + old_drive_group_id_string => $old_drive_group_id_string, + scan_storcli_drive_group_virtual_drive_uuid => $scan_storcli_drive_group_virtual_drive_uuid, + old_drive_group_virtual_drive_uuid => $old_drive_group_virtual_drive_uuid, + new_drive_group_access => $new_drive_group_access, + old_drive_group_access => $old_drive_group_access, + new_drive_group_array_size => $new_drive_group_array_size, + old_drive_group_array_size => $old_drive_group_array_size, + new_drive_group_array_state => $new_drive_group_array_state, + old_drive_group_array_state => $old_drive_group_array_state, + new_drive_group_cache => $new_drive_group_cache, + old_drive_group_cache => $old_drive_group_cache, + new_drive_group_cachecade => $new_drive_group_cachecade, + old_drive_group_cachecade => $old_drive_group_cachecade, + new_drive_group_consistent => $new_drive_group_consistent, + old_drive_group_consistent => $old_drive_group_consistent, + new_drive_group_disk_cache => $new_drive_group_disk_cache, + old_drive_group_disk_cache => $old_drive_group_disk_cache, + new_drive_group_raid_type => $new_drive_group_raid_type, + old_drive_group_raid_type => $old_drive_group_raid_type, + new_drive_group_read_cache => $new_drive_group_read_cache, + old_drive_group_read_cache => $old_drive_group_read_cache, + new_drive_group_scheduled_cc => $new_drive_group_scheduled_cc, + old_drive_group_scheduled_cc => $old_drive_group_scheduled_cc, + new_drive_group_write_cache => $new_drive_group_write_cache, + old_drive_group_write_cache => $old_drive_group_write_cache, + }}); + + if (not defined $old_drive_group_virtual_drive_uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_error_0014", variables => { drive_group => $drive_group }}); + $anvil->nice_exit({exit_code => 14}); + } + + if (($scan_storcli_drive_group_id_string ne $old_drive_group_id_string) or + ($scan_storcli_drive_group_virtual_drive_uuid ne $old_drive_group_virtual_drive_uuid) or + ($new_drive_group_access ne $old_drive_group_access) or + ($new_drive_group_array_size ne $old_drive_group_array_size) or + ($new_drive_group_array_state ne $old_drive_group_array_state) or + ($new_drive_group_cache ne $old_drive_group_cache) or + ($new_drive_group_cachecade ne $old_drive_group_cachecade) or + ($new_drive_group_consistent ne $old_drive_group_consistent) or + ($new_drive_group_disk_cache ne $old_drive_group_disk_cache) or + ($new_drive_group_raid_type ne $old_drive_group_raid_type) or + ($new_drive_group_read_cache ne $old_drive_group_read_cache) or + ($new_drive_group_scheduled_cc ne $old_drive_group_scheduled_cc) or + ($new_drive_group_write_cache ne $old_drive_group_write_cache)) + { + # Send a warning level alert because nothing should change here, ever. + my $message_key = "scan_storcli_warning_0024"; + if ($new_drive_group_access ne $old_drive_group_access) + { + if ($new_drive_group_access eq "VANISHED") + { + # Drive Group has returned. + $message_key = "scan_storcli_warning_0025"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + } + + my $variables = { + old_id_string => $old_drive_group_id_string, + new_id_string => $scan_storcli_drive_group_id_string, + new_access => $new_drive_group_access, + old_access => $old_drive_group_access, + new_array_size => $new_drive_group_array_size, + old_array_size => $old_drive_group_array_size, + new_array_state => $new_drive_group_array_state, + old_array_state => $old_drive_group_array_state, + new_cache => $new_drive_group_cache, + old_cache => $old_drive_group_cache, + new_cachecade => $new_drive_group_cachecade, + old_cachecade => $old_drive_group_cachecade, + new_consistent => $new_drive_group_consistent, + old_consistent => $old_drive_group_consistent, + new_disk_cache => $new_drive_group_disk_cache, + old_disk_cache => $old_drive_group_disk_cache, + new_raid_type => $new_drive_group_raid_type, + old_raid_type => $old_drive_group_raid_type, + new_read_cache => $new_drive_group_read_cache, + old_read_cache => $old_drive_group_read_cache, + new_scheduled_cc => $new_drive_group_scheduled_cc, + old_scheduled_cc => $old_drive_group_scheduled_cc, + new_write_cache => $new_drive_group_write_cache, + old_write_cache => $old_drive_group_write_cache, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => $message_key, + show_header => 0, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + $main_table_changed = 1; + + my $query = " +UPDATE + scan_storcli_drive_groups +SET + scan_storcli_drive_group_virtual_drive_uuid = ".$anvil->Database->quote($scan_storcli_drive_group_virtual_drive_uuid).", + scan_storcli_drive_group_id_string = ".$anvil->Database->quote($scan_storcli_drive_group_id_string).", + scan_storcli_drive_group_access = ".$anvil->Database->quote($new_drive_group_access).", + scan_storcli_drive_group_array_size = ".$anvil->Database->quote($new_drive_group_array_size).", + scan_storcli_drive_group_array_state = ".$anvil->Database->quote($new_drive_group_array_state).", + scan_storcli_drive_group_cache = ".$anvil->Database->quote($new_drive_group_cache).", + scan_storcli_drive_group_cachecade = ".$anvil->Database->quote($new_drive_group_cachecade).", + scan_storcli_drive_group_consistent = ".$anvil->Database->quote($new_drive_group_consistent).", + scan_storcli_drive_group_disk_cache = ".$anvil->Database->quote($new_drive_group_disk_cache).", + scan_storcli_drive_group_raid_type = ".$anvil->Database->quote($new_drive_group_raid_type).", + scan_storcli_drive_group_read_cache = ".$anvil->Database->quote($new_drive_group_read_cache).", + scan_storcli_drive_group_scheduled_cc = ".$anvil->Database->quote($new_drive_group_scheduled_cc).", + scan_storcli_drive_group_write_cache = ".$anvil->Database->quote($new_drive_group_write_cache).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_drive_group_uuid = ".$anvil->Database->quote($scan_storcli_drive_group_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-storcli'}{queries}}, $query; + } + + ### Process the rest of the variables now. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{$type}}) + { + my $new_variable_value = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + temperature => $temperature, + }}); + if (exists $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_drive_groups'}{source_uuid}{$scan_storcli_drive_group_uuid}{$type}{$variable}{scan_storcli_variable_uuid}) + { + # Look for changes + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_drive_groups'}{source_uuid}{$scan_storcli_drive_group_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_drive_groups'}{source_uuid}{$scan_storcli_drive_group_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + new_variable_value => $new_variable_value, + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_drive_groups'}{source_uuid}{$scan_storcli_drive_group_uuid}{$type}{$variable}; + + if (($new_variable_value ne $old_variable_value)) + { + # Changed! If the old value was 'VANISHED', then a + # sensor or variable returned. Otherwise, for now, we + # treat everything as 'warning' and step down + # explicitely anything not of concern that proves + # noisey later (better safe than sorry). + $anvil->data->{'scan-storcli'}{alert_sort}++; + + my $message_key = "scan_storcli_warning_0026"; + if ($old_variable_value eq "VANISHED") + { + $message_key = "scan_storcli_warning_0027"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + my $variables = { + id_string => $scan_storcli_drive_group_id_string, + name => $variable, + old_value => $old_variable_value, + new_value => $new_variable_value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => $message_key, + show_header => $main_table_changed ? 0 : 1, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = ".$anvil->Database->quote($new_variable_value).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + else + { + # New variable, record it. This is a 'warning' level as + # variables aren't expected to spawn into existence. + my $variables = { + id_string => $scan_storcli_drive_group_id_string, + name => $variable, + value => $new_variable_value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0043", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => "scan_storcli_warning_0043", + show_header => $main_table_changed ? 0 : 1, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_drive_groups', + ".$anvil->Database->quote($scan_storcli_drive_group_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($new_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-storcli'}{queries}}, $query; + } + } + } + + # Now look for any variables left from the previous scan that we didn't match up (and + # delete) this pass. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_drive_groups'}{source_uuid}{$scan_storcli_drive_group_uuid}{$type}}) + { + # This variable has vanished + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_drive_groups'}{source_uuid}{$scan_storcli_drive_group_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_drive_groups'}{source_uuid}{$scan_storcli_drive_group_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_drive_groups'}{source_uuid}{$scan_storcli_drive_group_uuid}{$type}{$variable}; + + # If the old value is already 'VANISHED', ignore it. + next if $old_variable_value eq "VANISHED"; + + ### NOTE: For now, we're going to use warning level because variables + ### shouldn't vanish, but under an-cm, it did happen for + ### reasons that we never figured out. So later, we may drop + ### the alert level in some cases. + # Still here? Alert and UPDATE. + my $variables = { + id_string => $scan_storcli_drive_group_id_string, + name => $variable, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0028", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => "scan_storcli_warning_0028", + show_header => $main_table_changed ? 0 : 1, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + } + + # Now commit the changes. We do this here so that the VD is in place before processing drive + # groups under it. + $anvil->Database->write({query => $anvil->data->{'scan-storcli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-storcli'}{queries} = []; + + # Delete the Drive Group from the last scan so that we can find controllers that have been removed. + if (exists $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::$scan_storcli_drive_group_uuid" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}, + }}); + delete $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}; + } + } + + ### NOTE: We can't check for vanished drive groups here as we're called by each virtual drive. + + return(0); +} + +# Look for added, changed or deleted virtual drives. +sub process_virtual_drives +{ + my ($anvil) = @_; + + # This method is a little different because as we process virtual drives, we will also process and + # drive groups under them. + $anvil->data->{'scan-storcli'}{queries} = []; + foreach my $scan_storcli_virtual_drive_id_string (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}}) + { + # The identifying string '-vd' where 'x' is the virtual drive number. + my $host_controller_serial_number = $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{on_controller}; + my $controller_uuid = $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$host_controller_serial_number}; + my $virtual_drive = ($scan_storcli_virtual_drive_id_string =~ /-vd(\d+)$/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_virtual_drive_id_string => $scan_storcli_virtual_drive_id_string, + host_controller_serial_number => $host_controller_serial_number, + controller_uuid => $controller_uuid, + virtual_drive => $virtual_drive, + }}); + + # Make sure I have the host's serial number and UUID. + if (not $host_controller_serial_number) + { + # Error! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_error_0010", variables => { id_string => $scan_storcli_virtual_drive_id_string }}); + $anvil->nice_exit({exit_code => 10}); + } + if (not $controller_uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_error_0008", variables => { serial_number => $host_controller_serial_number }}); + $anvil->nice_exit({exit_code => 8}); + } + + ### NOTE: This is here purely for debugging. + # Show the basic virtual drive data. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${scan_storcli_virtual_drive_id_string}::${type}" => $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{$type}, + }}); + next if not defined $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{$type}; + + # Log the hash with a prefix + $anvil->Log->variables({ + source => $THIS_FILE, + line => __LINE__, + level => 2, + prefix => "VD ".$virtual_drive." - ".$type, + list => $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{$type}, + }); + } + + # Is this a new Virtual Drive? + my $scan_storcli_virtual_drive_uuid = ""; + my $is_new = 0; + if (exists $anvil->data->{'scan-storcli'}{virtual_drives}{by_id_string}{$scan_storcli_virtual_drive_id_string}) + { + # Yes! + $scan_storcli_virtual_drive_uuid = $anvil->data->{'scan-storcli'}{virtual_drives}{by_id_string}{$scan_storcli_virtual_drive_id_string}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_storcli_virtual_drive_uuid => $scan_storcli_virtual_drive_uuid }}); + } + else + { + # No, this is a new Virtual Drive. Create a new UUID for it. + $scan_storcli_virtual_drive_uuid = $anvil->Get->uuid(); + $is_new = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_virtual_drive_uuid => $scan_storcli_virtual_drive_uuid, + is_new => $is_new, + }}); + + # Add the keys for looking it up by UUID or serial number. + $anvil->data->{'scan-storcli'}{virtual_drives}{by_id_string}{$scan_storcli_virtual_drive_id_string} = $scan_storcli_virtual_drive_uuid; + $anvil->data->{'scan-storcli'}{virtual_drives}{by_uuid}{$scan_storcli_virtual_drive_uuid} = $scan_storcli_virtual_drive_id_string; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::virtual_drives::by_id_string::$scan_storcli_virtual_drive_id_string" => $anvil->data->{'scan-storcli'}{virtual_drives}{by_id_string}{$scan_storcli_virtual_drive_id_string}, + "scan-storcli::virtual_drives::by_uuid::$scan_storcli_virtual_drive_uuid" => $anvil->data->{'scan-storcli'}{virtual_drives}{by_uuid}{$scan_storcli_virtual_drive_uuid}, + }}); + } + + ### These are the values for the main table. Anything else will go in the variables table. + # Creation date is a combination of two variables. + my $creation_date = ""; + my $creation_time = ""; + my $new_creation_date = ""; + my $new_data_protection = ""; + my $new_disk_cache_policy = ""; + my $new_emulation_type = ""; + my $new_encryption = ""; + my $new_blocks = ""; + my $new_strip_size = ""; + my $new_drives_per_span = ""; + my $new_span_depth = ""; + my $new_scsi_naa_id = ""; + if ($virtual_drive eq "9999") + { + # This is the fake VD + $creation_date = "2020/01/01"; + $creation_time = "00:00:00"; + $new_creation_date = "2020/01/01 00:00:00"; + $new_data_protection = "na"; + $new_disk_cache_policy = "na"; + $new_emulation_type = "na"; + $new_encryption = "na"; + $new_blocks = 0; + $new_strip_size = 0; + $new_drives_per_span = 0; + $new_span_depth = 0; + $new_scsi_naa_id = "placeholder"; + } + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${scan_storcli_virtual_drive_id_string}::variable::${variable}" => $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}, + }}); + + # Store and delete the value + if ($variable eq "creation_date") + { + # The creation date we store is a combination of two variables. That's why + # these first two entries are a little odd. + $creation_date = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + creation_date => $creation_date, + creation_time => $creation_time, + }}); + + # If I have the time, assemble. + if ($creation_time) + { + $new_creation_date = $creation_date." ".$creation_time; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_creation_date => $new_creation_date }}); + } + next; + } + if ($variable eq "creation_time") + { + $creation_time = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + creation_date => $creation_date, + creation_time => $creation_time, + }}); + + # If I have the date, assemble. + if ($creation_date) + { + $new_creation_date = $creation_date." ".$creation_time; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_creation_date => $new_creation_date }}); + } + next; + } + # Back to our regularly scheduled programming... + if ($variable eq "data_protection") + { + $new_data_protection = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_data_protection => $new_data_protection }}); + next; + } + if ($variable eq "disk_cache_policy") + { + $new_disk_cache_policy = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_disk_cache_policy => $new_disk_cache_policy }}); + next; + } + if ($variable eq "emulation_type") + { + $new_emulation_type = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_emulation_type => $new_emulation_type }}); + next; + } + if ($variable eq "encryption") + { + $new_encryption = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_encryption => $new_encryption }}); + next; + } + if ($variable eq "number_of_blocks") + { + $new_blocks = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_blocks => $new_blocks }}); + next; + } + if ($variable eq "strip_size") + { + $new_strip_size = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_strip_size => $new_strip_size }}); + next; + } + if ($variable eq "number_of_drives_per_span") + { + $new_drives_per_span = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_drives_per_span => $new_drives_per_span }}); + next; + } + if ($variable eq "span_depth") + { + $new_span_depth = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_span_depth => $new_span_depth }}); + next; + } + if ($variable eq "scsi_naa_id") + { + $new_scsi_naa_id = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scsi_naa_id => $new_scsi_naa_id }}); + next; + } + } + + # Pull out the rest of the variables now. If the Virtual Drive is new, all variables will be + # INSERTed. If the Virtual Drive 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 + # Virtual Drive 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'. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { is_new => $is_new }}); + if ($is_new) + { + ### NOTE: VD 9999 will be mostly blank and that is fine + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_virtual_drive_uuid => $scan_storcli_virtual_drive_uuid, + controller_uuid => $controller_uuid, + scan_storcli_virtual_drive_id_string => $scan_storcli_virtual_drive_id_string, + new_creation_date => $new_creation_date, + new_data_protection => $new_data_protection, + new_disk_cache_policy => $new_disk_cache_policy, + new_emulation_type => $new_emulation_type, + new_encryption => $new_encryption, + new_blocks => $new_blocks, + new_strip_size => $new_strip_size, + new_drives_per_span => $new_drives_per_span, + new_span_depth => $new_span_depth, + new_scsi_naa_id => $new_scsi_naa_id, + }}); + + ### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'. + my $variables = { + on_controller => $host_controller_serial_number, + id_string => $scan_storcli_virtual_drive_id_string, + creation_date => $new_creation_date, + data_protection => $new_data_protection, + disk_cache_policy => $new_disk_cache_policy, + emulation_type => $new_emulation_type, + encryption => $new_encryption, + blocks => $new_blocks, + strip_size => $new_strip_size, + drives_per_span => $new_drives_per_span, + span_depth => $new_span_depth, + scsi_naa_id => $new_scsi_naa_id, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_note_0004", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + message => "scan_storcli_note_0004", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_virtual_drives +( + scan_storcli_virtual_drive_uuid, + scan_storcli_virtual_drive_host_uuid, + scan_storcli_virtual_drive_controller_uuid, + scan_storcli_virtual_drive_id_string, + scan_storcli_virtual_drive_creation_date, + scan_storcli_virtual_drive_data_protection, + scan_storcli_virtual_drive_disk_cache_policy, + scan_storcli_virtual_drive_emulation_type, + scan_storcli_virtual_drive_encryption, + scan_storcli_virtual_drive_blocks, + scan_storcli_virtual_drive_strip_size, + scan_storcli_virtual_drive_drives_per_span, + scan_storcli_virtual_drive_span_depth, + scan_storcli_virtual_drive_scsi_naa_id, + modified_date +) VALUES ( + ".$anvil->Database->quote($scan_storcli_virtual_drive_uuid).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($controller_uuid).", + ".$anvil->Database->quote($scan_storcli_virtual_drive_id_string).", + ".$anvil->Database->quote($new_creation_date).", + ".$anvil->Database->quote($new_data_protection).", + ".$anvil->Database->quote($new_disk_cache_policy).", + ".$anvil->Database->quote($new_emulation_type).", + ".$anvil->Database->quote($new_encryption).", + ".$anvil->Database->quote($new_blocks).", + ".$anvil->Database->quote($new_strip_size).", + ".$anvil->Database->quote($new_drives_per_span).", + ".$anvil->Database->quote($new_span_depth).", + ".$anvil->Database->quote($new_scsi_naa_id).", + ".$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-storcli'}{queries}}, $query; + + # Process the rest of the variables and temperatures now. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{$type}}) + { + my $value = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + temperature => $temperature, + }}); + + # Send an alert telling the user that we've found a new controller. + my $variables = { + name => $variable, + value => $value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_note_0004", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + show_header => 0, + message => "scan_storcli_note_0002", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_virtual_drives', + ".$anvil->Database->quote($scan_storcli_virtual_drive_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($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-storcli'}{queries}}, $query; + } + } + } + else + { + ### NOTE: The serial number should never change (a changed SN/Virtual Drive should be + ### picked up as a new Virtual Drive), but we check/update just to be safe. + # Look for changes. + my $main_table_changed = 0; + my $old_scan_storcli_virtual_drive_id_string = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_id_string}; + my $old_controller_uuid = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_controller_uuid}; + my $old_creation_date = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_creation_date}; + my $old_data_protection = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_data_protection}; + my $old_disk_cache_policy = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_disk_cache_policy}; + my $old_emulation_type = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_emulation_type}; + my $old_encryption = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_encryption}; + my $old_blocks = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_blocks}; + my $old_strip_size = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_strip_size}; + my $old_drives_per_span = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_drives_per_span}; + my $old_span_depth = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_span_depth}; + my $old_scsi_naa_id = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_scsi_naa_id}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_virtual_drive_id_string => $scan_storcli_virtual_drive_id_string, + old_scan_storcli_virtual_drive_id_string => $old_scan_storcli_virtual_drive_id_string, + controller_uuid => $controller_uuid, + old_controller_uuid => $old_controller_uuid, + new_creation_date => $new_creation_date, + old_creation_date => $old_creation_date, + new_data_protection => $new_data_protection, + old_data_protection => $old_data_protection, + new_disk_cache_policy => $new_disk_cache_policy, + old_disk_cache_policy => $old_disk_cache_policy, + new_emulation_type => $new_emulation_type, + old_emulation_type => $old_emulation_type, + new_encryption => $new_encryption, + old_encryption => $old_encryption, + new_blocks => $new_blocks, + old_blocks => $old_blocks, + new_strip_size => $new_strip_size, + old_strip_size => $old_strip_size, + new_drives_per_span => $new_drives_per_span, + old_drives_per_span => $old_drives_per_span, + new_span_depth => $new_span_depth, + old_span_depth => $old_span_depth, + new_scsi_naa_id => $new_scsi_naa_id, + old_scsi_naa_id => $old_scsi_naa_id, + }}); + + if (($scan_storcli_virtual_drive_id_string ne $old_scan_storcli_virtual_drive_id_string) or + ($controller_uuid ne $old_controller_uuid) or + ($new_creation_date ne $old_creation_date) or + ($new_data_protection ne $old_data_protection) or + ($new_disk_cache_policy ne $old_disk_cache_policy) or + ($new_emulation_type ne $old_emulation_type) or + ($new_encryption ne $old_encryption) or + ($new_blocks ne $old_blocks) or + ($new_strip_size ne $old_strip_size) or + ($new_drives_per_span ne $old_drives_per_span) or + ($new_span_depth ne $old_span_depth) or + ($new_scsi_naa_id ne $old_scsi_naa_id)) + { + # I need the serial numbers for the controller UUIDs. + my $new_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$controller_uuid}; + my $old_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$old_controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_controller_serial_number => $new_controller_serial_number, + old_controller_serial_number => $old_controller_serial_number, + }}); + + # Send a warning level alert because nothing should change here, ever. + my $cleared = 0; + my $message_key = "scan_storcli_warning_0017"; + if ($new_creation_date ne $old_creation_date) + { + if ($old_creation_date eq "VANISHED") + { + # Virtual Drive has returned. + $cleared = 1; + $message_key = "scan_storcli_warning_0018"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + message_key => $message_key, + }}); + } + } + + my $variables = { + old_on_controller => $old_controller_serial_number, + new_on_controller => $new_controller_serial_number, + old_id_string => $old_scan_storcli_virtual_drive_id_string, + new_id_string => $scan_storcli_virtual_drive_id_string, + old_creation_date => $old_creation_date, + new_creation_date => $new_creation_date, + old_data_protection => $old_data_protection, + new_data_protection => $new_data_protection, + old_disk_cache_policy => $old_disk_cache_policy, + new_disk_cache_policy => $new_disk_cache_policy, + old_emulation_type => $old_emulation_type, + new_emulation_type => $new_emulation_type, + old_encryption => $old_encryption, + new_encryption => $new_encryption, + old_blocks => $old_blocks, + new_blocks => $new_blocks, + old_strip_size => $old_strip_size, + new_strip_size => $new_strip_size, + old_drives_per_span => $old_drives_per_span, + new_drives_per_span => $new_drives_per_span, + old_span_depth => $old_span_depth, + new_span_depth => $new_span_depth, + old_scsi_naa_id => $old_scsi_naa_id, + new_scsi_naa_id => $new_scsi_naa_id, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + clear_alert => $cleared, + message => $message_key, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + $main_table_changed = 1; + + my $query = " +UPDATE + scan_storcli_virtual_drives +SET + scan_storcli_virtual_drive_controller_uuid = ".$anvil->Database->quote($controller_uuid).", + scan_storcli_virtual_drive_id_string = ".$anvil->Database->quote($scan_storcli_virtual_drive_id_string).", + scan_storcli_virtual_drive_creation_date = ".$anvil->Database->quote($new_creation_date).", + scan_storcli_virtual_drive_data_protection = ".$anvil->Database->quote($new_data_protection).", + scan_storcli_virtual_drive_disk_cache_policy = ".$anvil->Database->quote($new_disk_cache_policy).", + scan_storcli_virtual_drive_emulation_type = ".$anvil->Database->quote($new_emulation_type).", + scan_storcli_virtual_drive_encryption = ".$anvil->Database->quote($new_encryption).", + scan_storcli_virtual_drive_blocks = ".$anvil->Database->quote($new_blocks).", + scan_storcli_virtual_drive_strip_size = ".$anvil->Database->quote($new_strip_size).", + scan_storcli_virtual_drive_drives_per_span = ".$anvil->Database->quote($new_drives_per_span).", + scan_storcli_virtual_drive_span_depth = ".$anvil->Database->quote($new_span_depth).", + scan_storcli_virtual_drive_scsi_naa_id = ".$anvil->Database->quote($new_scsi_naa_id).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_virtual_drive_uuid = ".$anvil->Database->quote($scan_storcli_virtual_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-storcli'}{queries}}, $query; + } + + ### Process the rest of the variables now. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{$type}}) + { + my $new_variable_value = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + temperature => $temperature, + }}); + if (exists $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_virtual_drives'}{source_uuid}{$scan_storcli_virtual_drive_uuid}{$type}{$variable}{scan_storcli_variable_uuid}) + { + # Look for changes + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_virtual_drives'}{source_uuid}{$scan_storcli_virtual_drive_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_virtual_drives'}{source_uuid}{$scan_storcli_virtual_drive_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + new_variable_value => $new_variable_value, + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_virtual_drives'}{source_uuid}{$scan_storcli_virtual_drive_uuid}{$type}{$variable}; + + if (($new_variable_value ne $old_variable_value)) + { + # Changed! If the old value was 'VANISHED', then a + # sensor or variable returned. Otherwise, for now, we + # treat everything as 'warning' and step down + # explicitely anything not of concern that proves + # noisey later (better safe than sorry). + $anvil->data->{'scan-storcli'}{alert_sort}++; + + my $cleared = 0; + my $level = "warning"; + my $message_key = "scan_storcli_warning_0019"; + if ($old_variable_value eq "VANISHED") + { + $message_key = "scan_storcli_warning_0020"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + + # If the 'name' is 'active operations' and the new is + # 'Background Initialization', we're in the middle of + # a BGI and this is not a warning. If the new is + # 'None', the CGI completed. + if ($variable =~ /Active Operations/i) + { + $level = "notice"; + if ($new_variable_value =~ /None/i) + { + # BGI done! + $message_key = "scan_storcli_note_0069"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + else + { + # BGI in progress still, pull out the + # percentage. + my $percentage = ($new_variable_value =~ /\(\d+%\)/)[0]; + if ($percentage) + { + # Successfully pulled the new + # percentage complete value. + $new_variable_value = $percentage; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_variable_value => $new_variable_value }}); + } + $message_key = "scan_storcli_note_0068"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + } + + my $variables = { + id_string => $scan_storcli_virtual_drive_id_string, + name => $variable, + old_value => $old_variable_value, + new_value => $new_variable_value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + alert_level => $level, + clear_alert => $cleared, + show_header => $main_table_changed ? 0 : 1, + message => $message_key, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = ".$anvil->Database->quote($new_variable_value).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + else + { + # New variable, record it. This is a 'warning' level as + # variables aren't expected to spawn into existence. + my $variables = { + id_string => $scan_storcli_virtual_drive_id_string, + name => $variable, + value => $new_variable_value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0022", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + clear_alert => 0, + show_header => $main_table_changed ? 0 : 1, + message => "scan_storcli_warning_0022", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_virtual_drives', + ".$anvil->Database->quote($scan_storcli_virtual_drive_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($new_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-storcli'}{queries}}, $query; + } + } + } + + # Now look for any variables left from the previous scan that we didn't match up (and + # delete) this pass. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_virtual_drives'}{source_uuid}{$scan_storcli_virtual_drive_uuid}{$type}}) + { + # This variable has vanished + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_virtual_drives'}{source_uuid}{$scan_storcli_virtual_drive_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_virtual_drives'}{source_uuid}{$scan_storcli_virtual_drive_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_virtual_drives'}{source_uuid}{$scan_storcli_virtual_drive_uuid}{$type}{$variable}; + + # If the old value is already 'VANISHED', ignore it. + next if $old_variable_value eq "VANISHED"; + + ### NOTE: For now, we're going to use warning level because variables + ### shouldn't vanish, but under an-cm, it did happen for + ### reasons that we never figured out. So later, we may drop + ### the alert level in some cases. + # Still here? Alert and UPDATE. + my $variables = { + id_string => $scan_storcli_virtual_drive_id_string, + name => $variable, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0021", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + clear_alert => 0, + show_header => $main_table_changed ? 0 : 1, + message => "scan_storcli_warning_0021", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + } + + # Now commit the changes. We do this here so that the VD is in place before processing drive + # groups under it. + $anvil->Database->write({query => $anvil->data->{'scan-storcli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-storcli'}{queries} = []; + + # Process drive groups under this virtual drive. They'll likely have vanished, too. + process_drive_groups($anvil, $scan_storcli_virtual_drive_id_string, $scan_storcli_virtual_drive_uuid, $controller_uuid, $host_controller_serial_number); + + # Delete the Virtual Drive from the last scan so that we can find controllers that have been removed. + if (exists $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}) + { + delete $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}; + } + } + + # See if any Virtual Drives have vanished. + foreach my $scan_storcli_virtual_drive_uuid (keys %{$anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}}) + { + # Virtual Drive vanished! + my $scan_storcli_virtual_drive_id_string = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_id_string}; + my $controller_uuid = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_controller_uuid}; + my $creation_date = $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_creation_date}; + my $host_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_virtual_drive_id_string => $scan_storcli_virtual_drive_id_string, + controller_uuid => $controller_uuid, + creation_date => $creation_date, + host_controller_serial_number => $host_controller_serial_number, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}; + + # If the old creation date is already 'VANISHED', ignore it. + next if $creation_date 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 = { + id_string => $scan_storcli_virtual_drive_id_string, + controller_serial_number => $host_controller_serial_number, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0023", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + clear_alert => 0, + show_header => 1, + message => "scan_storcli_warning_0023", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_virtual_drives +SET + scan_storcli_virtual_drive_creation_date = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_virtual_drive_uuid = ".$anvil->Database->quote($scan_storcli_virtual_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-storcli'}{queries}}, $query; + + # Now commit the changes. We do this here so that the VD is in place before processing drive + # groups under it. + $anvil->Database->write({query => $anvil->data->{'scan-storcli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-storcli'}{queries} = []; + + # Process drive groups under this virtual drive. They'll likely have vanished, too. + process_drive_groups($anvil, $scan_storcli_virtual_drive_id_string, $scan_storcli_virtual_drive_uuid, $controller_uuid, $host_controller_serial_number); + } + + ### Now that we've processed virtual drives, see if in stray drive groups are left. + foreach my $scan_storcli_drive_group_uuid (keys %{$anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}}) + { + # Drive Group vanished! + my $scan_storcli_drive_group_id_string = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_id_string}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan_storcli_drive_group_id_string" => $scan_storcli_drive_group_id_string, + }}); + + # If this drive group is '9999', we won't care if it vanishes because it was a pseudo DG + # anyway. + next if $scan_storcli_drive_group_id_string =~ /-dg9999$/; + + # Still here? Gather the rest of the data. + my $controller_uuid = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { controller_uuid => $controller_uuid }}); + + # If I don't have the controller ID, see if I can parse it from the + if ((not $controller_uuid) && ($scan_storcli_drive_group_id_string =~ /^(.*?)-vd/)) + { + my $serial_number = $1; + $controller_uuid = $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$serial_number} ? $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$serial_number} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + serial_number => $serial_number, + controller_uuid => $controller_uuid, + }}); + } + + # If I still don't have a controller UUID, then something serious went wrong. + if (not $controller_uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_error_0015", variables => { drive_group_uuid => $scan_storcli_drive_group_uuid }}); + $anvil->nice_exit({exit_code => 15}); + } + + my $access = $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_access}; + my $host_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_drive_group_id_string => $scan_storcli_drive_group_id_string, + access => $access, + host_controller_serial_number => $host_controller_serial_number, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}; + + # If the old creation date is already 'VANISHED', ignore it. + next if $access 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 = { + id_string => $scan_storcli_drive_group_id_string, + controller_serial_number => $host_controller_serial_number, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0028", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + clear_alert => 0, + show_header => 1, + message => "scan_storcli_warning_0028", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_drive_groups +SET + scan_storcli_drive_group_access = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_drive_group_uuid = ".$anvil->Database->quote($scan_storcli_drive_group_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-storcli'}{queries}}, $query; + + # Now commit the changes. We do this here so that the VD is in place before processing drive + # groups under it. + $anvil->Database->write({query => $anvil->data->{'scan-storcli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-storcli'}{queries} = []; + } + + return(0); +} + +# Look for added, changed or deleted physical drives. +sub process_physical_disks +{ + my ($anvil) = @_; + + foreach my $scan_storcli_virtual_drive_id_string (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}}) + { + my $virtual_drive = ($scan_storcli_virtual_drive_id_string =~ /-vd(\d+)$/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_virtual_drive_id_string => $scan_storcli_virtual_drive_id_string, + virtual_drive => $virtual_drive, + }}); + + foreach my $drive_group (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drive_group => $drive_group }}); + + foreach my $enclosure_id (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { enclosure_id => $enclosure_id }}); + + foreach my $slot_number (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { slot_number => $slot_number }}); + + # This function is really just to help keep code clean and avoid massive indenting. + process_a_physical_disk($anvil, $scan_storcli_virtual_drive_id_string, $drive_group, $enclosure_id, $slot_number); + } + } + } + } + + # See if any Physical Disks have vanished. + foreach my $scan_storcli_physical_drive_uuid (keys %{$anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}}) + { + # Physical Disk vanished! + my $old_physical_disk_serial_number = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_serial_number}; + my $old_controller_uuid = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_controller_uuid}; + my $old_model = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_model}; + my $old_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$old_controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_physical_disk_serial_number => $old_physical_disk_serial_number, + old_controller_uuid => $old_controller_uuid, + old_model => $old_model, + old_controller_serial_number => $old_controller_serial_number, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}; + + # If the old alarm state is already 'VANISHED', ignore it. + next if $old_model 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 = { + physical_disk_serial_number => $old_physical_disk_serial_number, + controller_serial_number => $old_controller_serial_number, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_warning_0035", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + show_header => 1, + message => "scan_storcli_warning_0035", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_physical_drives +SET + scan_storcli_physical_drive_model = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_physical_drive_uuid = ".$anvil->Database->quote($scan_storcli_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-storcli'}{queries}}, $query; + } + + # Now commit the changes. + $anvil->Database->write({query => $anvil->data->{'scan-storcli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-storcli'}{queries} = []; + + return(0); +} + +### NOTE: I don't loop by drive serial number, like in the other process_X() functions, so this one is +### designed a little different. +# This does the work of processing a specific physical disk. +sub process_a_physical_disk +{ + my ($anvil, $scan_storcli_virtual_drive_id_string, $drive_group, $enclosure_id, $slot_number) = @_; + + my ($vd_controller_serial_number, $virtual_drive) = ($scan_storcli_virtual_drive_id_string =~ /^(.*?)-vd(\d+)$/); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + vd_controller_serial_number => $vd_controller_serial_number, + virtual_drive => $virtual_drive, + }}); + + # I need the drive's serial number right off the bat. + # = virtual_drive::0000000051622771-vd0 ::drive_group::0:: enclosure_id::7:: slot_number::1:: variable::serial_number: [S7M1RD440000E722PB9N] + my $scan_storcli_physical_drive_serial_number = $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_storcli_physical_drive_serial_number => $scan_storcli_physical_drive_serial_number }}); + if ($scan_storcli_physical_drive_serial_number) + { + # Got it, delete it now. + delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{serial_number}; + } + else + { + # Error! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_error_0013", variables => { + virtual_drive => $scan_storcli_virtual_drive_id_string, + drive_group => $drive_group, + enclosure_id => $enclosure_id, + slot_number => $slot_number, + }}); + $anvil->nice_exit({exit_code => 13}); + } + + # Make sure I have a controller serial number. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${scan_storcli_virtual_drive_id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::on_controller" => $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{on_controller}, + }}); + if (not $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{on_controller}) + { + # Error! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_error_0012", variables => { serial_number => $scan_storcli_physical_drive_serial_number }}); + $anvil->nice_exit({exit_code => 12}); + } + + my $host_controller_serial_number = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{on_controller}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_controller_serial_number => $host_controller_serial_number }}); + + # Now make sure I can translate this to a UUID. + if (not $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$host_controller_serial_number}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_error_0008", variables => { serial_number => $host_controller_serial_number }}); + $anvil->nice_exit({exit_code => 8}); + } + my $controller_uuid = $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$host_controller_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { controller_uuid => $controller_uuid }}); + + # Not gather the rest of the core table's values. + my $new_size = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_size}; + my $new_sector_size = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sector_size}; + my $new_vendor = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{manufacturer_identification}; + my $new_model = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_model}; + my $new_self_encrypting_drive = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{self_encrypting_drive}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_size => $new_size, + new_sector_size => $new_sector_size, + new_vendor => $new_vendor, + new_model => $new_model, + new_self_encrypting_drive => $new_self_encrypting_drive, + }}); + + # Get the temperature ranges, which depends on whether this is an SSD or HDD. + my $drive_temperature_key = "hdd"; + my $drive_media = $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_media}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drive_media => $drive_media }}); + + if (lc($drive_media) eq "ssd") + { + $drive_temperature_key = "ssd"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drive_temperature_key => $drive_temperature_key }}); + } + + # Setup our thermal thresholds + my $high_critical = $anvil->data->{'scan-storcli'}{thresholds}{drives}{$drive_temperature_key}{high_critical}; + my $high_warning = $anvil->data->{'scan-storcli'}{thresholds}{drives}{$drive_temperature_key}{high_warning}; + my $low_warning = $anvil->data->{'scan-storcli'}{thresholds}{drives}{$drive_temperature_key}{low_warning}; + my $low_critical = $anvil->data->{'scan-storcli'}{thresholds}{drives}{$drive_temperature_key}{low_critical}; + my $jump = $anvil->data->{'scan-storcli'}{thresholds}{drives}{$drive_temperature_key}{jump}; + my $buffer = $anvil->data->{'scan-storcli'}{thresholds}{drives}{$drive_temperature_key}{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 }}); + } + + # Is this a new physical disk? + my $is_new = 0; + my $scan_storcli_physical_drive_uuid = ""; + if (exists $anvil->data->{'scan-storcli'}{physical_drives}{by_serial}{$scan_storcli_physical_drive_serial_number}) + { + # Yup! + $scan_storcli_physical_drive_uuid = $anvil->data->{'scan-storcli'}{physical_drives}{by_serial}{$scan_storcli_physical_drive_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_storcli_physical_drive_uuid => $scan_storcli_physical_drive_uuid }}); + } + else + { + $is_new = 1; + $scan_storcli_physical_drive_uuid = $anvil->Get->uuid(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + is_new => $is_new, + scan_storcli_physical_drive_uuid => $scan_storcli_physical_drive_uuid, + }}); + + $anvil->data->{'scan-storcli'}{physical_drives}{by_serial}{$scan_storcli_physical_drive_serial_number} = $scan_storcli_physical_drive_uuid; + $anvil->data->{'scan-storcli'}{physical_drives}{by_uuid}{$scan_storcli_physical_drive_uuid} = $scan_storcli_physical_drive_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::physical_drives::by_serial::$scan_storcli_physical_drive_serial_number" => $anvil->data->{'scan-storcli'}{physical_drives}{by_serial}{$scan_storcli_physical_drive_serial_number}, + "scan-storcli::physical_drives::by_uuid::$scan_storcli_physical_drive_uuid" => $anvil->data->{'scan-storcli'}{physical_drives}{by_uuid}{$scan_storcli_physical_drive_uuid}, + }}); + } + + # Pull out the rest of the variables now. If the physical disk is new, all variables will be + # INSERTed. If the physical drive 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 physical disk 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 ($is_new) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_physical_drive_serial_number => $scan_storcli_physical_drive_serial_number, + scan_storcli_physical_drive_uuid => $scan_storcli_physical_drive_uuid, + host_controller_serial_number => $host_controller_serial_number, + virtual_drive => $virtual_drive, + drive_group => $drive_group, + controller_uuid => $controller_uuid, + new_size => $new_size, + new_sector_size => $new_sector_size, + new_vendor => $new_vendor, + new_model => $new_model, + new_self_encrypting_drive => $new_self_encrypting_drive, + }}); + + ### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'. + # Send an alert telling the user that we've found a new controller. + my $variables = { + on_controller => $host_controller_serial_number, + virtual_drive => $virtual_drive, + drive_group => $drive_group, + serial_number => $scan_storcli_physical_drive_serial_number, + size => $new_size, + sector_size => $new_sector_size, + vendor => $new_vendor, + model => $new_model, + self_encrypting_drive => $new_self_encrypting_drive, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_note_0006", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + show_header => 1, + message => "scan_storcli_note_0006", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_physical_drives +( + scan_storcli_physical_drive_uuid, + scan_storcli_physical_drive_host_uuid, + scan_storcli_physical_drive_controller_uuid, + scan_storcli_physical_drive_virtual_drive, + scan_storcli_physical_drive_drive_group, + scan_storcli_physical_drive_enclosure_id, + scan_storcli_physical_drive_slot_number, + scan_storcli_physical_drive_serial_number, + scan_storcli_physical_drive_size, + scan_storcli_physical_drive_sector_size, + scan_storcli_physical_drive_vendor, + scan_storcli_physical_drive_model, + scan_storcli_physical_drive_self_encrypting_drive, + modified_date +) VALUES ( + ".$anvil->Database->quote($scan_storcli_physical_drive_uuid).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($controller_uuid).", + ".$anvil->Database->quote($virtual_drive).", + ".$anvil->Database->quote($drive_group).", + ".$anvil->Database->quote($enclosure_id).", + ".$anvil->Database->quote($slot_number).", + ".$anvil->Database->quote($scan_storcli_physical_drive_serial_number).", + ".$anvil->Database->quote($new_size).", + ".$anvil->Database->quote($new_sector_size).", + ".$anvil->Database->quote($new_vendor).", + ".$anvil->Database->quote($new_model).", + ".$anvil->Database->quote($new_self_encrypting_drive).", + ".$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-storcli'}{queries}}, $query; + + # Process the rest of the variables and temperatures now. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{$type}}) + { + my $value = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + temperature => $temperature, + }}); + + # If this is a thermal sensor, we need to see if it is OK or not. + my $cleared = 0; + my $message_key = "scan_storcli_note_0002"; + my $alert_level = "notice"; + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + if ($type eq "temperature") + { + # 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 ($value > $high_critical) + { + # Crossed the 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_storcli_physical_drive_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the critical + # threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0012"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($value > $high_warning) + { + # Crossed the 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_storcli_physical_drive_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the critical + # threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0013"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($value < $low_critical) + { + # Dropped below the 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_storcli_physical_drive_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the critical + # threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0014"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($value < $low_warning) + { + # Crossed the 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_storcli_physical_drive_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the critical + # threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0015"; + $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 = "pd:".$scan_storcli_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}{$variable}{$sensor_host_key}{temperature_value_c} = $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 new physical drive sensor. + my $variables = { + serial_number => $scan_storcli_physical_drive_serial_number, + name => $variable, + value => $value, + high_critical_temperature => $high_critical, + high_warning_temperature => $high_warning, + low_critical_temperature => $low_critical, + low_warning_temperature => $low_warning, + }; + my $log_level = $alert_level eq "notice" ? 2 : 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + alert_level => $alert_level, + show_header => 0, + message => $message_key, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_physical_drives', + ".$anvil->Database->quote($scan_storcli_physical_drive_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($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-storcli'}{queries}}, $query; + } + } + } + else + { + ### NOTE: The serial number should never change, but we check/update just to be safe. + # Look for changes. + my $main_table_changed = 0; + my $old_controller_uuid = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_controller_uuid}; + my $old_virtual_drive = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_virtual_drive}; + my $old_drive_group = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_drive_group}; + my $old_enclosure_id = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_enclosure_id}; + my $old_slot_number = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_slot_number}; + my $old_physical_drive_serial_number = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_serial_number}; + my $old_size = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_size}; + my $old_sector_size = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_sector_size}; + my $old_vendor = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_vendor}; + my $old_model = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_model}; + my $old_self_encrypting_drive = $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_self_encrypting_drive}; + $old_controller_uuid = "" if not defined $old_controller_uuid; + $old_physical_drive_serial_number = "" if not defined $old_physical_drive_serial_number; + $old_model = "" if not defined $old_model; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_physical_drive_serial_number => $scan_storcli_physical_drive_serial_number, + old_physical_drive_serial_number => $old_physical_drive_serial_number, + controller_uuid => $controller_uuid, + old_controller_uuid => $old_controller_uuid, + virtual_drive => $virtual_drive, + old_virtual_drive => $old_virtual_drive, + drive_group => $drive_group, + old_drive_group => $old_drive_group, + enclosure_id => $enclosure_id, + old_enclosure_id => $old_enclosure_id, + slot_number => $slot_number, + old_slot_number => $old_slot_number, + new_size => $new_size, + old_size => $old_size, + new_sector_size => $new_sector_size, + old_sector_size => $old_sector_size, + new_vendor => $new_vendor, + old_vendor => $old_vendor, + new_model => $new_model, + old_model => $old_model, + new_self_encrypting_drive => $new_self_encrypting_drive, + old_self_encrypting_drive => $old_self_encrypting_drive, + }}); + + if (($scan_storcli_physical_drive_serial_number ne $old_physical_drive_serial_number) or + ($controller_uuid ne $old_controller_uuid) or + ($virtual_drive ne $old_virtual_drive) or + ($drive_group ne $old_drive_group) or + ($enclosure_id ne $old_enclosure_id) or + ($slot_number ne $old_slot_number) or + ($new_size ne $old_size) or + ($new_sector_size ne $old_sector_size) or + ($new_vendor ne $old_vendor) or + ($new_model ne $old_model) or + ($new_self_encrypting_drive ne $old_self_encrypting_drive)) + { + # I'll need the old controller's serial number. + my $old_host_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$old_controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_host_controller_serial_number => $old_host_controller_serial_number }}); + + # Send a warning level alert because these really should never change. + my $cleared = 0; + my $message_key = "scan_storcli_warning_0029"; + if ($new_model ne $old_model) + { + if ($old_model eq "VANISHED") + { + # Physical drive has returned. + $message_key = "scan_storcli_warning_0030"; + } + } + my $variables = { + new_on_controller => $host_controller_serial_number, + old_on_controller => $old_host_controller_serial_number, + new_virtual_drive => $virtual_drive, + old_virtual_drive => $old_virtual_drive, + new_drive_group => $drive_group, + old_drive_group => $old_drive_group, + new_enclosure_id => $enclosure_id, + old_enclosure_id => $old_enclosure_id, + new_slot_number => $slot_number, + old_slot_number => $old_slot_number, + new_serial_number => $scan_storcli_physical_drive_serial_number, + old_serial_number => $old_physical_drive_serial_number, + new_vendor => $new_vendor, + old_vendor => $old_vendor, + new_model => $new_model, + old_model => $old_model, + new_size => $new_size, + old_size => $old_size, + new_sector_size => $new_sector_size, + old_sector_size => $old_sector_size, + new_self_encrypting_drive => $new_self_encrypting_drive, + old_self_encrypting_drive => $old_self_encrypting_drive, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + show_header => 0, + message => $message_key, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + $main_table_changed = 1; + + my $query = " +UPDATE + scan_storcli_physical_drives +SET + scan_storcli_physical_drive_controller_uuid = ".$anvil->Database->quote($controller_uuid).", + scan_storcli_physical_drive_virtual_drive = ".$anvil->Database->quote($virtual_drive).", + scan_storcli_physical_drive_drive_group = ".$anvil->Database->quote($drive_group).", + scan_storcli_physical_drive_enclosure_id = ".$anvil->Database->quote($enclosure_id).", + scan_storcli_physical_drive_slot_number = ".$anvil->Database->quote($slot_number).", + scan_storcli_physical_drive_serial_number = ".$anvil->Database->quote($scan_storcli_physical_drive_serial_number).", + scan_storcli_physical_drive_size = ".$anvil->Database->quote($new_size).", + scan_storcli_physical_drive_sector_size = ".$anvil->Database->quote($new_sector_size).", + scan_storcli_physical_drive_vendor = ".$anvil->Database->quote($new_vendor).", + scan_storcli_physical_drive_model = ".$anvil->Database->quote($new_model).", + scan_storcli_physical_drive_self_encrypting_drive = ".$anvil->Database->quote($new_self_encrypting_drive).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_physical_drive_uuid = ".$anvil->Database->quote($scan_storcli_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-storcli'}{queries}}, $query; + } + + ### Process the rest of the variables now. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{$type}}) + { + my $new_variable_value = delete $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{$type}{$variable}; + $new_variable_value = "" if not defined $new_variable_value; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + temperature => $temperature, + }}); + if (exists $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_physical_drives'}{source_uuid}{$scan_storcli_physical_drive_uuid}{$type}{$variable}{scan_storcli_variable_uuid}) + { + # Look for changes + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_physical_drives'}{source_uuid}{$scan_storcli_physical_drive_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_physical_drives'}{source_uuid}{$scan_storcli_physical_drive_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + new_variable_value => $new_variable_value, + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_physical_drives'}{source_uuid}{$scan_storcli_physical_drive_uuid}{$type}{$variable}; + + # If there is no change, I still want to record the temperature + # (where applicable). So I setup like I will send an alert from the + # start, but will only actually send if something has changed. + my $cleared = 0; + my $message_key = "scan_storcli_warning_0031"; + my $alert_level = "info"; + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + if ($type eq "temperature") + { + # It's a temperature, so change the default message. + $message_key = "scan_storcli_note_0064"; + if (($new_variable_value ne $old_variable_value)) + { + # If the temperature is rising, see if we need to set + # a high warning or critical, or, clear a low warning + # or critical. Check for the reverse if the + # temperature is dropping. + if ($old_variable_value eq "VANISHED") + { + ### NOTE: We don't (yet) check to see if the + ### drive is overheating or freezing + ### here. That would require new logic + ### and is unlikely to be needed. + # Temperature is back. + $message_key = "scan_storcli_warning_0032"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + elsif ($new_variable_value > $old_variable_value) + { + # Rising + my $jumped = $new_variable_value - $old_variable_value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { jumped => $jumped }}); + if ($new_variable_value > $high_critical) + { + # Crossed the critical threshold. See + # if this is the first time. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_storcli_physical_drive_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we + # rose above the critical + # threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0008"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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_variable_value > $high_warning) + { + # Crossed the warning threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_storcli_physical_drive_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the + # critical threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0009"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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_variable_value > $clear_low_warning) + { + # Risen into the clear, make sure + # both warning and critical are + # cleared. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_storcli_physical_drive_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + my $cleared_warning = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_storcli_physical_drive_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared_critical => $cleared_critical, + cleared_warning => $cleared_warning, + }}); + if ($cleared_critical) + { + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0016"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + elsif ($cleared_warning) + { + # The temperature has dropped back down to + # safe levels. + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0016"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($new_variable_value > $clear_low_critical) + { + # Risen above critical, but not in + # the clear. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_storcli_physical_drive_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cleared_critical => $cleared_critical }}); + if ($cleared_critical) + { + # Set the warning. + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_storcli_physical_drive_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0017"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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, + }}); + } + elsif ($jumped > $jump) + { + # The temperature jumped a large + # amount. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0018"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + else + { + # Falling + my $jumped = $old_variable_value - $new_variable_value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { jumped => $jumped }}); + if ($new_variable_value < $low_critical) + { + # Dropped below the 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_storcli_physical_drive_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the + # critical threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0010"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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_variable_value < $low_warning) + { + # Crossed the 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_storcli_physical_drive_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the + # critical threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0011"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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, + }}); + } + elsif ($new_variable_value < $clear_high_warning) + { + # Dropped into the clear + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_storcli_physical_drive_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + my $cleared_warning = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_storcli_physical_drive_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared_critical => $cleared_critical, + cleared_warning => $cleared_warning, + }}); + if ($cleared_critical) + { + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0019"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + elsif ($cleared_warning) + { + # The temperature has dropped back down to + # safe levels. + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0019"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($new_variable_value < $clear_high_critical) + { + # Dropped below critical, but not in + # the clear. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_storcli_physical_drive_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cleared_critical => $cleared_critical }}); + if ($cleared_critical) + { + # Set the warning. + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_storcli_physical_drive_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0020"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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 ($jumped > $jump) + { + # The temperature dropped a large + # amount. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0021"; + $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 = "pd:".$scan_storcli_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}{$variable}{$sensor_host_key}{temperature_value_c} = $new_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}, + }}); + } + + # Now actually generate an alert and save the changes if something + # changed. + if (($new_variable_value ne $old_variable_value)) + { + # Changed! If the old value was 'VANISHED', then a + # sensor or variable returned. Otherwise, for now, we + # treat everything as 'warning' and step down + # explicitely anything not of concern that proves + # noisey later (better safe than sorry). + $anvil->data->{'scan-storcli'}{alert_sort}++; + + if ($type ne "temperature") + { + if ($old_variable_value eq "VANISHED") + { + $message_key = "scan_storcli_warning_0032"; + } + + # We want to watch for the 'error' counters. If they + # change, we make this a warning. + if ($variable =~ /error_count/) + { + # If we're over 6, it's a warning. If its + # under 6, a notice. If it's 0, clear. + if ($new_variable_value > 6) + { + $alert_level = "warning"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { alert_level => $alert_level }}); + } + elsif ($new_variable_value > 0) + { + $alert_level = "notice"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { alert_level => $alert_level }}); + } + $message_key = "scan_storcli_warning_0044"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + elsif ($variable =~ /fail/) + { + $alert_level = "warning"; + $message_key = "scan_storcli_warning_0045"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + my $variables = { + serial_number => $scan_storcli_physical_drive_serial_number, + name => $variable, + old_value => $old_variable_value ? $old_variable_value : "--", + new_value => $new_variable_value, + high_critical_temperature => $high_critical, + high_warning_temperature => $high_warning, + low_critical_temperature => $low_critical, + low_warning_temperature => $low_warning, + jump => $jump, + }; + my $log_level = $alert_level eq "notice" ? 2 : 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + alert_level => $alert_level, + show_header => $main_table_changed ? 0 : 1, + message => $message_key, + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = ".$anvil->Database->quote($new_variable_value).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + else + { + # New variable, record it. This is a 'warning' level as + # variables aren't expected to spawn into existence. + my $variables = { + serial_number => $scan_storcli_physical_drive_serial_number, + name => $variable, + value => $new_variable_value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_warning_0033", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + show_header => $main_table_changed ? 0 : 1, + message => "scan_storcli_warning_0033", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_physical_drives', + ".$anvil->Database->quote($scan_storcli_physical_drive_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($new_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-storcli'}{queries}}, $query; + } + } + } + + # Now look for any variables left from the previous scan that we didn't match up (and delete) + # this pass. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_physical_drives'}{source_uuid}{$scan_storcli_physical_drive_uuid}{$type}}) + { + # This variable has vanished + next if not defined $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_physical_drives'}{source_uuid}{$scan_storcli_physical_drive_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_physical_drives'}{source_uuid}{$scan_storcli_physical_drive_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_physical_drives'}{source_uuid}{$scan_storcli_physical_drive_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_physical_drives'}{source_uuid}{$scan_storcli_physical_drive_uuid}{$type}{$variable}; + + # If the old value is already 'VANISHED', ignore it. + next if $old_variable_value eq "VANISHED"; + + ### NOTE: For now, we're going to use warning level because variables + ### shouldn't vanish, but under an-cm, it did happen for + ### reasons that we never figured out. So later, we may drop + ### the alert level in some cases. + # Still here? Alert and UPDATE. + my $variables = { + serial_number => $scan_storcli_physical_drive_serial_number, + name => $variable, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_warning_0034", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + show_header => $main_table_changed ? 0 : 1, + message => "scan_storcli_warning_0034", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + } + + # Delete the Physical Drive from the last scan so that we can find disks that have been removed. + if (exists $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}) + { + delete $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}; + } + + return(0); +} + +# Look for added, changed or deleted cachevaults (FBUs). +sub process_cachevaults +{ + my ($anvil) = @_; + + # Setup our thermal thresholds + my $high_critical = $anvil->data->{'scan-storcli'}{thresholds}{cachevault}{high_critical}; + my $high_warning = $anvil->data->{'scan-storcli'}{thresholds}{cachevault}{high_warning}; + my $low_warning = $anvil->data->{'scan-storcli'}{thresholds}{cachevault}{low_warning}; + my $low_critical = $anvil->data->{'scan-storcli'}{thresholds}{cachevault}{low_critical}; + my $jump = $anvil->data->{'scan-storcli'}{thresholds}{cachevault}{jump}; + my $buffer = $anvil->data->{'scan-storcli'}{thresholds}{cachevault}{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, + }}); + + # Find new, changed and replaced Cachevaults (FBUs). + $anvil->data->{'scan-storcli'}{queries} = []; + foreach my $cachevault_serial_number (sort {$a cmp $b} keys %{$anvil->data->{cachevault}{serial_number}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cachevault_serial_number => $cachevault_serial_number }}); + + # Is this a new Cachevault? + my $cachevault_uuid = ""; + my $is_new = 0; + if (exists $anvil->data->{'scan-storcli'}{cachevaults}{by_serial}{$cachevault_serial_number}) + { + # Yes! + $cachevault_uuid = $anvil->data->{'scan-storcli'}{cachevaults}{by_serial}{$cachevault_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cachevault_uuid => $cachevault_uuid }}); + } + else + { + # No, this is a new Cachevault. Create a new UUID for it. + $cachevault_uuid = $anvil->Get->uuid(); + $is_new = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cachevault_uuid => $cachevault_uuid, + is_new => $is_new, + }}); + + # Add the keys for looking it up by UUID or serial number. + $anvil->data->{'scan-storcli'}{cachevaults}{by_serial}{$cachevault_serial_number} = $cachevault_uuid; + $anvil->data->{'scan-storcli'}{cachevaults}{by_uuid}{$cachevault_uuid} = $cachevault_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::cachevaults::by_serial::$cachevault_serial_number" => $anvil->data->{'scan-storcli'}{cachevaults}{by_serial}{$cachevault_serial_number}, + "scan-storcli::cachevaults::by_uuid::$cachevault_uuid" => $anvil->data->{'scan-storcli'}{cachevaults}{by_uuid}{$cachevault_uuid}, + }}); + } + + # First up, get the controller serial number and translate that to a controller_uuid. + if (not $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{host_controller_serial_number}) + { + # Error! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_error_0009", variables => { serial_number => $cachevault_serial_number }}); + $anvil->nice_exit({exit_code => 9}); + } + my $host_controller_serial_number = $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{host_controller_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_controller_serial_number => $host_controller_serial_number }}); + + if (not $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$host_controller_serial_number}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_error_0008", variables => { serial_number => $host_controller_serial_number }}); + $anvil->nice_exit({exit_code => 8}); + } + my $controller_uuid = $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$host_controller_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { controller_uuid => $controller_uuid }}); + + # These are the values for the main table. Anything else will go in the variables table. + my $new_type = ""; + my $new_model = ""; + my $new_state = ""; + my $new_manufacture_date = ""; + my $new_design_capacity = ""; + my $new_replacement_needed = ""; + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + + # Store and delete the value + if ($variable eq "type") + { + $new_type = delete $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_type => $new_type }}); + next; + } + if ($variable eq "device_name") + { + $new_model = delete $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_model => $new_model }}); + next; + } + if ($variable eq "state") + { + $new_state = delete $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_state => $new_state }}); + next; + } + if ($variable eq "date_of_manufacture") + { + $new_manufacture_date = delete $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_manufacture_date => $new_manufacture_date }}); + next; + } + if ($variable eq "design_capacity") + { + $new_design_capacity = delete $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_design_capacity => $new_design_capacity }}); + next; + } + if ($variable eq "replacement_required") + { + $new_replacement_needed = delete $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_replacement_needed => $new_replacement_needed }}); + next; + } + } + + # Pull out the rest of the variables now. If the Cachevault is new, all variables will be + # INSERTed. If the Cachevault 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 + # Cachevault 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 ($is_new) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cachevault_uuid => $cachevault_uuid, + controller_uuid => $controller_uuid, + cachevault_serial_number => $cachevault_serial_number, + new_type => $new_type, + new_model => $new_model, + new_state => $new_state, + new_design_capacity => $new_design_capacity, + new_manufacture_date => $new_manufacture_date, + new_replacement_needed => $new_replacement_needed, + }}); + + ### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'. + # Send an alert telling the user that we've found a new controller. + my $variables = { + on_controller => $host_controller_serial_number, + serial_number => $cachevault_serial_number, + type => $new_type, + model => $new_model, + 'state' => $new_state, + design_capacity => $new_design_capacity, + manufacture_date => $new_manufacture_date, + replacement_needed => $new_replacement_needed, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_note_0007", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + message => "scan_storcli_note_0007", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_cachevaults +( + scan_storcli_cachevault_uuid, + scan_storcli_cachevault_host_uuid, + scan_storcli_cachevault_controller_uuid, + scan_storcli_cachevault_serial_number, + scan_storcli_cachevault_type, + scan_storcli_cachevault_model, + scan_storcli_cachevault_state, + scan_storcli_cachevault_design_capacity, + scan_storcli_cachevault_manufacture_date, + scan_storcli_cachevault_replacement_needed, + modified_date +) VALUES ( + ".$anvil->Database->quote($cachevault_uuid).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($controller_uuid).", + ".$anvil->Database->quote($cachevault_serial_number).", + ".$anvil->Database->quote($new_type).", + ".$anvil->Database->quote($new_model).", + ".$anvil->Database->quote($new_state).", + ".$anvil->Database->quote($new_design_capacity).", + ".$anvil->Database->quote($new_manufacture_date).", + ".$anvil->Database->quote($new_replacement_needed).", + ".$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-storcli'}{queries}}, $query; + + # Process the rest of the variables and temperatures now. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{$type}}) + { + my $value = delete $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + temperature => $temperature, + }}); + + my $cleared = 0; + my $message_key = "scan_storcli_note_0002"; + my $alert_level = "info"; + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + if ($type eq "temperature") + { + # 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 ($value > $high_critical) + { + # Crossed the 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 => $cachevault_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the + # critical threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0036"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($value > $high_warning) + { + # Crossed the 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 => $cachevault_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the + # critical threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0037"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($value < $low_critical) + { + # Dropped below the 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 => $cachevault_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the + # critical threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0038"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($value < $low_warning) + { + # Crossed the 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 => $cachevault_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the critical + # threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0039"; + $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 = "cachevault:".$cachevault_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} = $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 new controller. + my $variables = { + serial_number => $cachevault_serial_number, + name => $variable, + value => $value, + high_critical_temperature => $high_critical, + high_warning_temperature => $high_warning, + low_critical_temperature => $low_critical, + low_warning_temperature => $low_warning, + }; + 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 => 0, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_cachevaults', + ".$anvil->Database->quote($cachevault_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($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-storcli'}{queries}}, $query; + } + } + } + else + { + ### NOTE: The serial number should never change (a changed SN/Cachevault should be + ### picked up as a new Cachevault), but we check/update just to be safe. + # Look for changes. + my $main_table_changed = 0; + my $old_cachevault_serial_number = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_serial_number}; + my $old_controller_uuid = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_controller_uuid}; + my $old_type = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_type}; + my $old_model = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_model}; + my $old_state = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_state}; + my $old_design_capacity = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_design_capacity}; + my $old_manufacture_date = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_manufacture_date}; + my $old_replacement_needed = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_replacement_needed}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cachevault_serial_number => $cachevault_serial_number, + old_cachevault_serial_number => $old_cachevault_serial_number, + controller_uuid => $controller_uuid, + old_controller_uuid => $old_controller_uuid, + new_type => $new_type, + old_type => $old_type, + new_model => $new_model, + old_model => $old_model, + new_state => $new_state, + old_state => $old_state, + new_design_capacity => $new_design_capacity, + old_design_capacity => $old_design_capacity, + new_manufacture_date => $new_manufacture_date, + old_manufacture_date => $old_manufacture_date, + new_replacement_needed => $new_replacement_needed, + old_replacement_needed => $old_replacement_needed, + }}); + + if (($cachevault_serial_number ne $old_cachevault_serial_number) or + ($controller_uuid ne $old_controller_uuid) or + ($new_type ne $old_type) or + ($new_model ne $old_model) or + ($new_state ne $old_state) or + ($new_design_capacity ne $old_design_capacity) or + ($new_manufacture_date ne $old_manufacture_date) or + ($new_replacement_needed ne $old_replacement_needed)) + { + # I need the serial numbers for the controller UUIDs. + my $new_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$controller_uuid}; + my $old_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$old_controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_controller_serial_number => $new_controller_serial_number, + old_controller_serial_number => $old_controller_serial_number, + }}); + + # Send a warning level alert because the most likely change is 'state' or + # 'replacement_needed'. + my $cleared = 0; + my $message_key = "scan_storcli_warning_0036"; + if ($new_state ne $old_state) + { + if ($old_state eq "VANISHED") + { + # Cachevault has returned. + $message_key = "scan_storcli_warning_0037"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + ### TODO: Verify this is the expected string on Cachevaults. + if ($new_state =~ /optimal/i) + { + $cleared = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cleared => $cleared }}); + } + } + my $variables = { + new_on_controller => $new_controller_serial_number, + old_on_controller => $old_controller_serial_number, + new_model => $new_model, + old_model => $old_model, + new_serial_number => $cachevault_serial_number, + old_serial_number => $old_cachevault_serial_number, + new_type => $new_type, + old_type => $old_type, + new_state => $new_state, + old_state => $old_state, + new_design_capacity => $new_design_capacity, + old_design_capacity => $old_design_capacity, + new_manufacture_date => $new_manufacture_date, + old_manufacture_date => $old_manufacture_date, + new_replacement_needed => $new_replacement_needed, + old_replacement_needed => $old_replacement_needed, + }; + $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 => 0, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + $main_table_changed = 1; + + my $query = " +UPDATE + scan_storcli_cachevaults +SET + scan_storcli_cachevault_controller_uuid = ".$anvil->Database->quote($controller_uuid).", + scan_storcli_cachevault_serial_number = ".$anvil->Database->quote($cachevault_serial_number).", + scan_storcli_cachevault_type = ".$anvil->Database->quote($new_type).", + scan_storcli_cachevault_model = ".$anvil->Database->quote($new_model).", + scan_storcli_cachevault_state = ".$anvil->Database->quote($new_state).", + scan_storcli_cachevault_manufacture_date = ".$anvil->Database->quote($new_manufacture_date).", + scan_storcli_cachevault_design_capacity = ".$anvil->Database->quote($new_design_capacity).", + scan_storcli_cachevault_replacement_needed = ".$anvil->Database->quote($new_replacement_needed).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_cachevault_uuid = ".$anvil->Database->quote($cachevault_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-storcli'}{queries}}, $query; + } + + ### Process the rest of the variables now. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{$type}}) + { + my $new_variable_value = delete $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + new_variable_value => $new_variable_value, + temperature => $temperature, + }}); + if (exists $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_cachevaults'}{source_uuid}{$cachevault_uuid}{$type}{$variable}{scan_storcli_variable_uuid}) + { + # Look for changes + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_cachevaults'}{source_uuid}{$cachevault_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_cachevaults'}{source_uuid}{$cachevault_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + new_variable_value => $new_variable_value, + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_cachevaults'}{source_uuid}{$cachevault_uuid}{$type}{$variable}; + + # If there is no change, I still want to record the + # temperature (where applicable). So I setup like I will send + # an alert from the start, but will only actually send if + # something has changed. + my $cleared = 1; + my $message_key = "scan_storcli_warning_0038"; + my $alert_level = "info"; + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + if ($type eq "temperature") + { + # It's a temperature, so change the default message. + $message_key = "scan_storcli_note_0065"; + if (($new_variable_value ne $old_variable_value)) + { + # If the temperature is rising, see if we + # need to set a high warning or critical, or, + # clear a low warning or critical. Check for + # the reverse if the temperature is dropping. + if ($old_variable_value eq "VANISHED") + { + ### NOTE: We don't (yet) check to see + ### if the drive is overheating + ### or freezing here. That + ### would require new logic and + ### is unlikely to be needed. + # Temperature is back. + $cleared = 1; + $message_key = "scan_storcli_warning_0039"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + message_key => $message_key, + }}); + } + elsif ($old_variable_value > $new_variable_value) + { + # Rising + my $jumped = $new_variable_value - $old_variable_value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { jumped => $jumped }}); + if ($new_variable_value > $high_critical) + { + # Crossed the critical + # threshold. See if this is + # the first time. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $cachevault_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0040"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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_variable_value > $high_warning) + { + # Crossed the warning + # threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $cachevault_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0041"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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_variable_value > $clear_low_warning) + { + # Risen into the clear, make + # sure both warning and + # critical are cleared. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $cachevault_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + my $cleared_warning = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $cachevault_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared_critical => $cleared_critical, + cleared_warning => $cleared_warning, + }}); + if ($cleared_critical) + { + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0042"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + elsif ($cleared_warning) + { + # The temperature has + # dropped back down + # to safe levels. + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0042"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($new_variable_value > $clear_low_critical) + { + # Risen above critical, but + # not in the clear. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $cachevault_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cleared_critical => $cleared_critical }}); + if ($cleared_critical) + { + # Set the warning. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $cachevault_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0043"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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, + }}); + } + elsif ($jumped > $jump) + { + # The temperature jumped a + # large amount. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0044"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + else + { + # Falling + my $jumped = $old_variable_value - $new_variable_value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { jumped => $jumped }}); + if ($new_variable_value < $low_critical) + { + # Dropped below the 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 => $cachevault_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0045"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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_variable_value < $low_warning) + { + # Crossed the 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 => $cachevault_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0046"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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, + }}); + } + elsif ($new_variable_value < $clear_high_warning) + { + # Dropped into the clear + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $cachevault_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + my $cleared_warning = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $cachevault_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared_critical => $cleared_critical, + cleared_warning => $cleared_warning, + }}); + if ($cleared_critical) + { + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0047"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + elsif ($cleared_warning) + { + # The temperature has + # dropped back down + # to safe levels. + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0047"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($new_variable_value < $clear_high_critical) + { + # Dropped below critical, but + # not in the clear. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $cachevault_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cleared_critical => $cleared_critical }}); + if ($cleared_critical) + { + # Set the warning. + my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $cachevault_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0048"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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 ($jumped > $jump) + { + # The temperature dropped a + # large amount. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0049"; + $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 = "cachevault:".$cachevault_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_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}, + }}); + } + + # Now actually generate an alert and save the changes if something + # changed. + if (($new_variable_value ne $old_variable_value)) + { + # Changed! If the old value was 'VANISHED', then a + # sensor or variable returned. Otherwise, for now, we + # treat everything as 'warning' and step down + # explicitely anything not of concern that proves + # noisey later (better safe than sorry). + $anvil->data->{'scan-storcli'}{alert_sort}++; + + if ($type ne "temperature") + { + if ($old_variable_value eq "VANISHED") + { + $message_key = "scan_storcli_warning_0039"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + + # Check for some important issues + #if ($variable =~ /memory_correctable_errors/) + # Nothing seems to be of special interest... See: SELECT a.host_name, b.scan_storcli_cachevault_serial_number AS sn, b.scan_storcli_cachevault_type, scan_storcli_cachevault_model, c.scan_storcli_variable_name AS variable, c.scan_storcli_variable_value AS value, c.scan_storcli_variable_is_temperature AS temp, c.modified_date FROM hosts a, scan_storcli_cachevaults b, scan_storcli_variables c WHERE a.host_uuid = b.scan_storcli_cachevault_host_uuid AND b.scan_storcli_cachevault_uuid = c.scan_storcli_variable_source_uuid AND a.host_name = 'an-a07n01.alteeve.com'; + } + my $variables = { + serial_number => $cachevault_serial_number, + name => $variable, + old_value => $old_variable_value ? $old_variable_value : "--", + new_value => $new_variable_value, + high_critical_temperature => $high_critical, + high_warning_temperature => $high_warning, + low_critical_temperature => $low_critical, + low_warning_temperature => $low_warning, + jump => $jump, + }; + 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 => $main_table_changed ? 0 : 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = ".$anvil->Database->quote($new_variable_value).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + else + { + # New variable, record it. This is a 'warning' level as + # variables aren't expected to spawn into existence. + my $variables = { + serial_number => $cachevault_serial_number, + name => $variable, + value => $new_variable_value, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0041", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => "scan_storcli_warning_0041", + variables => $variables, + show_header => $main_table_changed ? 0 : 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_cachevaults', + ".$anvil->Database->quote($cachevault_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($new_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-storcli'}{queries}}, $query; + } + } + } + + # Now look for any variables left from the previous scan that we didn't match up (and + # delete) this pass. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_cachevaults'}{source_uuid}{$cachevault_uuid}{$type}}) + { + # This variable has vanished + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_cachevaults'}{source_uuid}{$cachevault_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_cachevaults'}{source_uuid}{$cachevault_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_cachevaults'}{source_uuid}{$cachevault_uuid}{$type}{$variable}; + + # If the old value is already 'VANISHED', ignore it. + next if $old_variable_value eq "VANISHED"; + + ### NOTE: For now, we're going to use warning level because variables + ### shouldn't vanish, but under an-cm, it did happen for + ### reasons that we never figured out. So later, we may drop + ### the alert level in some cases. + # Still here? Alert and UPDATE. + my $variables = { + serial_number => $cachevault_serial_number, + name => $variable, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0040", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_storcli_warning_0040", + variables => $variables, + show_header => $main_table_changed ? 0 : 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + } + + # Delete the Cachevault from the last scan so that we can find controllers that have been removed. + if (exists $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}) + { + delete $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}; + } + } + + # See if any Cachevaults have vanished. + foreach my $cachevault_uuid (keys %{$anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}}) + { + # Cachevault vanished! + my $old_cachevault_serial_number = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_serial_number}; + my $old_controller_uuid = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_controller_uuid}; + my $old_state = $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}{scan_storcli_cachevault_state}; + my $old_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$old_controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_cachevault_serial_number => $old_cachevault_serial_number, + old_controller_uuid => $old_controller_uuid, + old_state => $old_state, + old_controller_serial_number => $old_controller_serial_number, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$cachevault_uuid}; + + # If the old alarm state is already 'VANISHED', ignore it. + next if $old_state 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 = { + cachevault_serial_number => $old_cachevault_serial_number, + controller_serial_number => $old_controller_serial_number, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0042", variables => $variables}); + $anvil->Alert->register({ + clear_alert => 0, + alert_level => "warning", + message => "scan_storcli_warning_0042", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_cachevaults +SET + scan_storcli_cachevault_state = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_cachevault_uuid = ".$anvil->Database->quote($cachevault_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-storcli'}{queries}}, $query; + } + + # Now commit the changes. + $anvil->Database->write({query => $anvil->data->{'scan-storcli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-storcli'}{queries} = []; + + return(0); +} + +# Look for added, changed or deleted battery backup units (BBUs). +sub process_bbus +{ + my ($anvil) = @_; + + # Find new, changed and replaced BBUs. + $anvil->data->{'scan-storcli'}{queries} = []; + foreach my $bbu_serial_number (sort {$a cmp $b} keys %{$anvil->data->{bbu}{serial_number}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bbu_serial_number => $bbu_serial_number }}); + + # Is this a new BBU? + my $bbu_uuid = ""; + my $is_new = 0; + if (exists $anvil->data->{'scan-storcli'}{bbus}{by_serial}{$bbu_serial_number}) + { + # Yes! + $bbu_uuid = $anvil->data->{'scan-storcli'}{bbus}{by_serial}{$bbu_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bbu_uuid => $bbu_uuid }}); + } + else + { + # No, this is a new BBU. Create a new UUID for it. + $bbu_uuid = $anvil->Get->uuid(); + $is_new = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bbu_uuid => $bbu_uuid, + is_new => $is_new, + }}); + + # Add the keys for looking it up by UUID or serial number. + $anvil->data->{'scan-storcli'}{bbus}{by_serial}{$bbu_serial_number} = $bbu_uuid; + $anvil->data->{'scan-storcli'}{bbus}{by_uuid}{$bbu_uuid} = $bbu_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::bbus::by_serial::$bbu_serial_number" => $anvil->data->{'scan-storcli'}{bbus}{by_serial}{$bbu_serial_number}, + "scan-storcli::bbus::by_uuid::$bbu_uuid" => $anvil->data->{'scan-storcli'}{bbus}{by_uuid}{$bbu_uuid}, + }}); + } + + # The temperature range of the BBU depends on whether it is charging or discharging. + my $bbu_temperature_key = "normal"; + # Get the charge state. + # - None + # - Discharging + # - Charging + my $charging = $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}{charging_status}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { charging => $charging }}); + + if ($charging =~ /^discharging$/i) + { + $bbu_temperature_key = "discharging"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bbu_temperature_key => $bbu_temperature_key }}); + } + + # Setup our thermal thresholds + my $high_critical = $anvil->data->{'scan-storcli'}{thresholds}{bbu}{$bbu_temperature_key}{high_critical}; + my $high_warning = $anvil->data->{'scan-storcli'}{thresholds}{bbu}{$bbu_temperature_key}{high_warning}; + my $low_warning = $anvil->data->{'scan-storcli'}{thresholds}{bbu}{$bbu_temperature_key}{low_warning}; + my $low_critical = $anvil->data->{'scan-storcli'}{thresholds}{bbu}{$bbu_temperature_key}{low_critical}; + my $jump = $anvil->data->{'scan-storcli'}{thresholds}{bbu}{$bbu_temperature_key}{jump}; + my $buffer = $anvil->data->{'scan-storcli'}{thresholds}{bbu}{$bbu_temperature_key}{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 }}); + } + + # First up, get the controller serial number and translate that to a controller_uuid. + if (not $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{host_controller_serial_number}) + { + # Error! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_error_0007", variables => { serial_number => $bbu_serial_number }}); + $anvil->nice_exit({exit_code => 7}); + } + my $host_controller_serial_number = $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{host_controller_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_controller_serial_number => $host_controller_serial_number }}); + + if (not $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$host_controller_serial_number}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_error_0008", variables => { serial_number => $host_controller_serial_number }}); + $anvil->nice_exit({exit_code => 8}); + } + my $controller_uuid = $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$host_controller_serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { controller_uuid => $controller_uuid }}); + + # These are the values for the main table. Anything else will go in the variables table. + my $new_type = ""; + my $new_model = ""; + my $new_state = ""; + my $new_manufacture_date = ""; + my $new_design_capacity = ""; + my $new_replacement_needed = ""; + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + + # Store and delete the value + if ($variable eq "type") + { + $new_type = delete $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_type => $new_type }}); + next; + } + if ($variable eq "manufacture_name") + { + $new_model = delete $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_model => $new_model }}); + next; + } + if ($variable eq "battery_state") + { + $new_state = delete $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_model => $new_model }}); + next; + } + if ($variable eq "date_of_manufacture") + { + $new_manufacture_date = delete $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_manufacture_date => $new_manufacture_date }}); + next; + } + if ($variable eq "design_capacity") + { + $new_design_capacity = delete $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_design_capacity => $new_design_capacity }}); + next; + } + if ($variable eq "replacement_required") + { + $new_replacement_needed = delete $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_replacement_needed => $new_replacement_needed }}); + next; + } + } + + # Pull out the rest of the variables now. If the BBU is new, all variables will be INSERTed. + # If the BBU 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 BBU 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 ($is_new) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bbu_uuid => $bbu_uuid, + controller_uuid => $controller_uuid, + bbu_serial_number => $bbu_serial_number, + new_type => $new_type, + new_model => $new_model, + new_state => $new_state, + new_design_capacity => $new_design_capacity, + new_manufacture_date => $new_manufacture_date, + new_replacement_needed => $new_replacement_needed, + }}); + + ### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'. + # Send an alert telling the user that we've found a new controller. + my $variables = { + on_controller => $host_controller_serial_number, + serial_number => $bbu_serial_number, + type => $new_type, + model => $new_model, + 'state' => $new_state, + design_capacity => $new_design_capacity, + manufacture_date => $new_manufacture_date, + replacement_needed => $new_replacement_needed, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_note_0003", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + message => "scan_storcli_note_0003", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_bbus +( + scan_storcli_bbu_uuid, + scan_storcli_bbu_host_uuid, + scan_storcli_bbu_controller_uuid, + scan_storcli_bbu_serial_number, + scan_storcli_bbu_type, + scan_storcli_bbu_model, + scan_storcli_bbu_state, + scan_storcli_bbu_design_capacity, + scan_storcli_bbu_manufacture_date, + scan_storcli_bbu_replacement_needed, + modified_date +) VALUES ( + ".$anvil->Database->quote($bbu_uuid).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($controller_uuid).", + ".$anvil->Database->quote($bbu_serial_number).", + ".$anvil->Database->quote($new_type).", + ".$anvil->Database->quote($new_model).", + ".$anvil->Database->quote($new_state).", + ".$anvil->Database->quote($new_design_capacity).", + ".$anvil->Database->quote($new_manufacture_date).", + ".$anvil->Database->quote($new_replacement_needed).", + ".$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-storcli'}{queries}}, $query; + + # Process the rest of the variables and temperatures now. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{bbu}{serial_number}{$bbu_serial_number}{$type}}) + { + my $value = delete $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + temperature => $temperature, + }}); + + my $message_key = "scan_storcli_note_0002"; + my $alert_level = "notice"; + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + if ($type eq "temperature") + { + # 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 ($value > $high_critical) + { + # Crossed the 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 => $bbu_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the + # critical threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0050"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($value > $high_warning) + { + # Crossed the 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 => $bbu_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the + # critical threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0051"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($value < $low_critical) + { + # Dropped below the 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 => $bbu_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the + # critical threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0052"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($value < $low_warning) + { + # Crossed the 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 => $bbu_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first time we rose above the critical + # threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0053"; + $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 = "bbu:".$bbu_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} = $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 new controller. + my $variables = { + serial_number => $bbu_serial_number, + name => $variable, + value => $value, + high_critical_temperature => $high_critical, + high_warning_temperature => $high_warning, + low_critical_temperature => $low_critical, + low_warning_temperature => $low_warning, + }; + 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, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_bbus', + ".$anvil->Database->quote($bbu_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($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-storcli'}{queries}}, $query; + } + } + } + else + { + ### NOTE: The serial number should never change (a changed SN/BBU should be picked up + ### as a new BBU), but we check/update just to be safe. + # Look for changes. + my $main_table_changed = 0; + my $old_bbu_serial_number = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_serial_number}; + my $old_controller_uuid = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_controller_uuid}; + my $old_type = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_type}; + my $old_model = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_model}; + my $old_state = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_state}; + my $old_design_capacity = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_design_capacity}; + my $old_manufacture_date = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_manufacture_date}; + my $old_replacement_needed = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_replacement_needed}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bbu_serial_number => $bbu_serial_number, + old_bbu_serial_number => $old_bbu_serial_number, + controller_uuid => $controller_uuid, + old_controller_uuid => $old_controller_uuid, + new_type => $new_type, + old_type => $old_type, + new_model => $new_model, + old_model => $old_model, + new_state => $new_state, + old_state => $old_state, + new_design_capacity => $new_design_capacity, + old_design_capacity => $old_design_capacity, + new_manufacture_date => $new_manufacture_date, + old_manufacture_date => $old_manufacture_date, + new_replacement_needed => $new_replacement_needed, + old_replacement_needed => $old_replacement_needed, + }}); + + if (($bbu_serial_number ne $old_bbu_serial_number) or + ($controller_uuid ne $old_controller_uuid) or + ($new_type ne $old_type) or + ($new_model ne $old_model) or + ($new_state ne $old_state) or + ($new_design_capacity ne $old_design_capacity) or + ($new_manufacture_date ne $old_manufacture_date) or + ($new_replacement_needed ne $old_replacement_needed)) + { + # I need the serial numbers for the controller UUIDs. + my $new_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$controller_uuid}; + my $old_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$old_controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_controller_serial_number => $new_controller_serial_number, + old_controller_serial_number => $old_controller_serial_number, + }}); + + # Send a warning level alert because the most likely change is 'state' or + # 'replacement_needed'. + my $cleared = 0; + my $message_key = "scan_storcli_warning_0010"; + if ($new_state ne $old_state) + { + if ($old_state eq "VANISHED") + { + # BBU has returned. + $message_key = "scan_storcli_warning_0011"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + if ($new_state =~ /optimal/i) + { + $cleared = 1; + } + } + my $variables = { + new_on_controller => $new_controller_serial_number, + old_on_controller => $old_controller_serial_number, + new_model => $new_model, + old_model => $old_model, + new_serial_number => $bbu_serial_number, + old_serial_number => $old_bbu_serial_number, + new_type => $new_type, + old_type => $old_type, + new_state => $new_state, + old_state => $old_state, + new_design_capacity => $new_design_capacity, + old_design_capacity => $old_design_capacity, + new_manufacture_date => $new_manufacture_date, + old_manufacture_date => $old_manufacture_date, + new_replacement_needed => $new_replacement_needed, + old_replacement_needed => $old_replacement_needed, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + clear_alert => $cleared, + message => $message_key, + variables => $variables, + show_header => 0, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + $main_table_changed = 1; + + my $query = " +UPDATE + scan_storcli_bbus +SET + scan_storcli_bbu_controller_uuid = ".$anvil->Database->quote($controller_uuid).", + scan_storcli_bbu_serial_number = ".$anvil->Database->quote($bbu_serial_number).", + scan_storcli_bbu_type = ".$anvil->Database->quote($new_type).", + scan_storcli_bbu_model = ".$anvil->Database->quote($new_model).", + scan_storcli_bbu_state = ".$anvil->Database->quote($new_state).", + scan_storcli_bbu_manufacture_date = ".$anvil->Database->quote($new_manufacture_date).", + scan_storcli_bbu_design_capacity = ".$anvil->Database->quote($new_design_capacity).", + scan_storcli_bbu_replacement_needed = ".$anvil->Database->quote($new_replacement_needed).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_bbu_uuid = ".$anvil->Database->quote($bbu_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-storcli'}{queries}}, $query; + } + + ### Process the rest of the variables now. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{bbu}{serial_number}{$bbu_serial_number}{$type}}) + { + my $new_variable_value = delete $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + temperature => $temperature, + }}); + if (exists $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_bbus'}{source_uuid}{$bbu_uuid}{$type}{$variable}{scan_storcli_variable_uuid}) + { + # Look for changes + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_bbus'}{source_uuid}{$bbu_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_bbus'}{source_uuid}{$bbu_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_variable_value => $new_variable_value, + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_bbus'}{source_uuid}{$bbu_uuid}{$type}{$variable}; + + # If there is no change, I still want to record the + # temperature (where applicable). So I setup like I will send + # an alert from the start, but will only actually send if + # something has changed. + my $cleared = 0; + my $message_key = "scan_storcli_warning_0012"; + my $alert_level = "info"; + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + if ($type eq "temperature") + { + # It's a temperature, so change the default message + # and drop the default alert level. + $message_key = "scan_storcli_note_0066"; + $alert_level = "info"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + message_key => $message_key, + alert_level => $alert_level, + }}); + if (($new_variable_value ne $old_variable_value)) + { + # If the temperature is rising, see if we + # need to set a high warning or critical, or, + # clear a low warning or critical. Check for + # the reverse if the temperature is dropping. + if ($old_variable_value eq "VANISHED") + { + ### NOTE: We don't (yet) check to see + ### if the drive is overheating + ### or freezing here. That + ### would require new logic and + ### is unlikely to be needed. + # Temperature is back. + $message_key = "scan_storcli_warning_0013"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + elsif ($new_variable_value > $old_variable_value) + { + # Rising + my $jumped = $new_variable_value - $old_variable_value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { jumped => $jumped }}); + if ($new_variable_value > $high_critical) + { + # Crossed the critical + # threshold. See if this is + # the first time. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $bbu_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0054"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + message_key => $message_key, + alert_level => $alert_level, + }}); + } + $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_variable_value > $high_warning) + { + # Crossed the warning + # threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $bbu_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0055"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + message_key => $message_key, + alert_level => $alert_level, + }}); + } + $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_variable_value > $clear_low_warning) + { + # Risen into the clear, make + # sure both warning and + # critical are cleared. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $bbu_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + my $cleared_warning = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $bbu_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared_critical => $cleared_critical, + cleared_warning => $cleared_warning, + }}); + if ($cleared_critical) + { + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0056"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + message_key => $message_key, + alert_level => $alert_level, + }}); + } + elsif ($cleared_warning) + { + # The temperature has + # dropped back down + # to safe levels. + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0056"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + message_key => $message_key, + alert_level => $alert_level, + }}); + } + } + elsif ($new_variable_value > $clear_low_critical) + { + # Risen above critical, but + # not in the clear. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $bbu_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cleared_critical => $cleared_critical }}); + if ($cleared_critical) + { + # Set the warning. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $bbu_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0057"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + message_key => $message_key, + alert_level => $alert_level, + }}); + } + $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, + }}); + } + elsif ($jumped > $jump) + { + # The temperature jumped a + # large amount. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0058"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + message_key => $message_key, + alert_level => $alert_level, + }}); + } + } + else + { + # Falling + my $jumped = $old_variable_value - $new_variable_value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { jumped => $jumped }}); + if ($new_variable_value < $low_critical) + { + # Dropped below the 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 => $bbu_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0059"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + message_key => $message_key, + alert_level => $alert_level, + }}); + } + $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_variable_value < $low_warning) + { + # Crossed the 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 => $bbu_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0060"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + message_key => $message_key, + alert_level => $alert_level, + }}); + } + $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, + }}); + } + elsif ($new_variable_value < $clear_high_warning) + { + # Dropped into the clear + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $bbu_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + my $cleared_warning = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $bbu_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared_critical => $cleared_critical, + cleared_warning => $cleared_warning, + }}); + if ($cleared_critical) + { + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0061"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + message_key => $message_key, + alert_level => $alert_level, + }}); + } + elsif ($cleared_warning) + { + # The temperature has + # dropped back down + # to safe levels. + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0061"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + message_key => $message_key, + alert_level => $alert_level, + }}); + } + } + elsif ($new_variable_value < $clear_high_critical) + { + # Dropped below critical, but + # not in the clear. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $bbu_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cleared_critical => $cleared_critical }}); + if ($cleared_critical) + { + # Set the warning. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $bbu_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0062"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + message_key => $message_key, + alert_level => $alert_level, + }}); + } + $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 ($jumped > $jump) + { + # The temperature dropped a + # large amount. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0063"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + message_key => $message_key, + alert_level => $alert_level, + }}); + } + } + } + + # Record this for later processing into the + # 'temperature' table. + my $sensor_host_key = "bbu:$bbu_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_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}, + }}); + } + + # Now actually generate an alert and save the changes if something + # changed. + if (($new_variable_value ne $old_variable_value)) + { + # Changed! If the old value was 'VANISHED', then a + # sensor or variable returned. Otherwise, for now, we + # treat everything as 'warning' and step down + # explicitely anything not of concern that proves + # noisey later (better safe than sorry). + if ($type ne "temperature") + { + if ($old_variable_value eq "VANISHED") + { + $message_key = "scan_storcli_warning_0013"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + + # Check for some important issues + if ($variable =~ /over_charged/) + { + $alert_level = "critical"; + $message_key = "scan_storcli_warning_0049"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + message_key => $message_key, + alert_level => $alert_level, + }}); + } + if ($variable =~ /over_temperature/) + { + $alert_level = "warning"; + $message_key = "scan_storcli_warning_0050"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + message_key => $message_key, + alert_level => $alert_level, + }}); + } + if ($variable =~ /pack_is_about_to_fail_and_should_be_replaced/) + { + $alert_level = "warning"; + $message_key = "scan_storcli_warning_0051"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + message_key => $message_key, + alert_level => $alert_level, + }}); + } + # Other things that might be of interest... See: SELECT a.host_name, b.scan_storcli_bbu_serial_number AS sn, b.scan_storcli_bbu_type, b.scan_storcli_bbu_model, c.scan_storcli_variable_name AS variable, c.scan_storcli_variable_value AS value, c.scan_storcli_variable_is_temperature AS temp, c.modified_date FROM hosts a, scan_storcli_bbus b, scan_storcli_variables c WHERE a.host_uuid = b.scan_storcli_bbu_host_uuid AND b.scan_storcli_bbu_uuid = c.scan_storcli_variable_source_uuid AND a.host_name = 'an-a05n01.alteeve.com'; + } + my $variables = { + serial_number => $bbu_serial_number, + name => $variable, + old_value => $old_variable_value ? $old_variable_value : "--", + new_value => $new_variable_value, + high_critical_temperature => $high_critical, + high_warning_temperature => $high_warning, + low_critical_temperature => $low_critical, + low_warning_temperature => $low_warning, + jump => $jump, + }; + my $show_header = $main_table_changed ? 0 : 1; + 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 => $show_header, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = ".$anvil->Database->quote($new_variable_value).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + else + { + # New variable, record it. This is a 'warning' level as + # variables aren't expected to spawn into existence. + my $variables = { + serial_number => $bbu_serial_number, + name => $variable, + value => $new_variable_value, + }; + my $show_header = $main_table_changed ? 0 : 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_warning_0015", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => "scan_storcli_warning_0015", + variables => $variables, + show_header => $show_header, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_bbus', + ".$anvil->Database->quote($bbu_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($new_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-storcli'}{queries}}, $query; + } + } + } + + # Now look for any variables left from the previous scan that we didn't match up (and + # delete) this pass. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_bbus'}{source_uuid}{$bbu_uuid}{$type}}) + { + # This variable has vanished + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_bbus'}{source_uuid}{$bbu_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_bbus'}{source_uuid}{$bbu_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_bbus'}{source_uuid}{$bbu_uuid}{$type}{$variable}; + + # If the old value is already 'VANISHED', ignore it. + next if $old_variable_value eq "VANISHED"; + + ### NOTE: For now, we're going to use warning level because variables + ### shouldn't vanish, but under an-cm, it did happen for + ### reasons that we never figured out. So later, we may drop + ### the alert level in some cases. + # Still here? Alert and UPDATE. + my $variables = { + serial_number => $bbu_serial_number, + name => $variable, + }; + my $show_header = $main_table_changed ? 0 : 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_storcli_warning_0014", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => "scan_storcli_warning_0014", + variables => $variables, + show_header => $show_header, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + } + + # Delete the BBU from the last scan so that we can find controllers that have been removed. + if (exists $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}) + { + delete $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}; + } + } + + # See if any BBUs have vanished. + foreach my $bbu_uuid (keys %{$anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}}) + { + # BBU vanished! + my $old_bbu_serial_number = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_serial_number}; + my $old_controller_uuid = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_controller_uuid}; + my $old_state = $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}{scan_storcli_bbu_state}; + my $old_controller_serial_number = $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$old_controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_bbu_serial_number => $old_bbu_serial_number, + old_controller_uuid => $old_controller_uuid, + old_state => $old_state, + old_controller_serial_number => $old_controller_serial_number, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$bbu_uuid}; + + # If the old alarm state is already 'VANISHED', ignore it. + next if $old_state 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 = { + bbu_serial_number => $old_bbu_serial_number, + controller_serial_number => $old_controller_serial_number, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0016", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => "scan_storcli_warning_0016", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_bbus +SET + scan_storcli_bbu_state = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_bbu_uuid = ".$anvil->Database->quote($bbu_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-storcli'}{queries}}, $query; + } + + # Now commit the changes. + $anvil->Database->write({query => $anvil->data->{'scan-storcli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-storcli'}{queries} = []; + + return(0); +} + +# Look for added, changed or deleted controllers. +sub process_controllers +{ + my ($anvil) = @_; + + # Setup our thermal thresholds + my $high_critical = $anvil->data->{'scan-storcli'}{thresholds}{raid_on_chip}{high_critical}; + my $high_warning = $anvil->data->{'scan-storcli'}{thresholds}{raid_on_chip}{high_warning}; + my $low_warning = $anvil->data->{'scan-storcli'}{thresholds}{raid_on_chip}{low_warning}; + my $low_critical = $anvil->data->{'scan-storcli'}{thresholds}{raid_on_chip}{low_critical}; + my $jump = $anvil->data->{'scan-storcli'}{thresholds}{raid_on_chip}{jump}; + my $buffer = $anvil->data->{'scan-storcli'}{thresholds}{raid_on_chip}{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 }}); + } + + # Look for new, changed or deleted controllers. + $anvil->data->{'scan-storcli'}{queries} = []; + foreach my $serial_number (sort {$a cmp $b} keys %{$anvil->data->{controller}{serial_number}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + serial_number => $serial_number, + "scan-storcli::controllers::by_serial::$serial_number" => $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$serial_number}, + }}); + + # Is this controller in the database yet? + my $controller_uuid = ""; + my $is_new = 0; + if ($anvil->data->{'scan-storcli'}{controllers}{by_serial}{$serial_number}) + { + # Yes! + $controller_uuid = $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { controller_uuid => $controller_uuid }}); + } + else + { + # No, this is a new controller. Create a new UUID for it. + $controller_uuid = $anvil->Get->uuid(); + $is_new = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + controller_uuid => $controller_uuid, + is_new => $is_new, + }}); + + # Add the keys for looking it up by UUID or serial number. + $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$serial_number} = $controller_uuid; + $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$controller_uuid} = $serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::controllers::by_serial::$serial_number" => $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$serial_number}, + "scan-storcli::controllers::by_uuid::$controller_uuid" => $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$controller_uuid}, + }}); + } + + # These are the values for the main table. Anything else will go in the variables table which + # will be processed after the controller. + my $new_model = ""; + my $new_alarm_state = ""; + my $new_cache_size = ""; + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{serial_number}{$serial_number}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + + if ($variable eq "model") + { + # Store and delete the value + $new_model = delete $anvil->data->{controller}{serial_number}{$serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_model => $new_model }}); + next; + } + elsif ($variable eq "alarm_state") + { + # Store and delete the value + $new_alarm_state = delete $anvil->data->{controller}{serial_number}{$serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_alarm_state => $new_alarm_state }}); + next; + } + elsif ($variable eq "on_board_memory_size") + { + # Store and delete the value + $new_cache_size = delete $anvil->data->{controller}{serial_number}{$serial_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_cache_size => $new_cache_size }}); + next; + } + } + + # 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 ($is_new) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + serial_number => $serial_number, + new_model => $new_model, + new_alarm_state => $new_alarm_state, + new_cache_size => $new_cache_size, + }}); + + ### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'. + # Send an alert telling the user that we've found a new controller. + my $variables = { + model => $new_model, + serial_number => $serial_number, + say_cache_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_cache_size}), + alarm_state => $new_alarm_state, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_note_0001", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + message => "scan_storcli_note_0001", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_controllers +( + scan_storcli_controller_host_uuid, + scan_storcli_controller_uuid, + scan_storcli_controller_serial_number, + scan_storcli_controller_model, + scan_storcli_controller_alarm_state, + scan_storcli_controller_cache_size, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($controller_uuid).", + ".$anvil->Database->quote($serial_number).", + ".$anvil->Database->quote($new_model).", + ".$anvil->Database->quote($new_alarm_state).", + ".$anvil->Database->quote($new_cache_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-storcli'}{queries}}, $query; + + # Process the rest of the variables and temperatures now. + foreach my $type ("variable", "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}{serial_number}{$serial_number}{$type}}) + { + my $value = delete $anvil->data->{controller}{serial_number}{$serial_number}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + temperature => $temperature, + }}); + + my $message_key = "scan_storcli_note_0002"; + my $alert_level = "notice"; + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + if ($type eq "temperature") + { + # 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 ($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 => $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_storcli_note_0022"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($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 => $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_storcli_note_0023"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($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 => $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_storcli_note_0024"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($value < $low_warning) + { + # Dropped below 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 => $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_storcli_note_0025"; + $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:".$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} = $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 new controller. + my $variables = { + serial_number => $serial_number, + name => $variable, + value => $value, + high_critical_temperature => $high_critical, + high_warning_temperature => $high_warning, + low_critical_temperature => $low_critical, + low_warning_temperature => $low_warning, + }; + 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, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_controllers', + ".$anvil->Database->quote($controller_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($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-storcli'}{queries}}, $query; + } + } + } + else + { + ### NOTE: The serial number should never change (a changed SN/controller should be + ### picked up as a new controller), but we check/update just to be safe. + # Look for changes. + my $main_table_changed = 0; + my $old_serial_number = $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$controller_uuid}{scan_storcli_controller_serial_number}; + my $old_model = $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$controller_uuid}{scan_storcli_controller_model}; + my $old_alarm_state = $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$controller_uuid}{scan_storcli_controller_alarm_state}; + my $old_cache_size = $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$controller_uuid}{scan_storcli_controller_cache_size}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + serial_number => $serial_number, + old_serial_number => $old_serial_number, + new_model => $new_model, + old_model => $old_model, + new_alarm_state => $new_alarm_state, + old_alarm_state => $old_alarm_state, + new_cache_size => $new_cache_size, + old_cache_size => $old_cache_size, + }}); + + if (($serial_number ne $old_serial_number) or + ($new_model ne $old_model) or + ($new_alarm_state ne $old_alarm_state) or + ($new_cache_size ne $old_cache_size)) + { + # Send a warning level alert because the most likely change is 'alarm_state'. + # If, however, the alarm state is now 'off', then we'll clear the alert. + my $cleared = 0; + my $message_key = "scan_storcli_warning_0002"; + if ($new_alarm_state ne $old_alarm_state) + { + if ($old_alarm_state eq "VANISHED") + { + # Controller has returned. + $message_key = "scan_storcli_warning_0009"; + } + if ($new_alarm_state =~ /off/i) + { + $cleared = 1; + } + } + my $variables = { + new_serial_number => $serial_number, + old_serial_number => $old_serial_number, + new_model => $new_model, + old_model => $old_model, + new_alarm_state => $new_alarm_state, + old_alarm_state => $old_alarm_state, + new_cache_size => $new_cache_size, + old_cache_size => $old_cache_size, + }; + $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}); + + $main_table_changed = 1; + my $query = " +UPDATE + scan_storcli_controllers +SET + scan_storcli_controller_serial_number = ".$anvil->Database->quote($serial_number).", + scan_storcli_controller_model = ".$anvil->Database->quote($new_model).", + scan_storcli_controller_alarm_state = ".$anvil->Database->quote($new_alarm_state).", + scan_storcli_controller_cache_size = ".$anvil->Database->quote($new_cache_size).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_controller_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +AND + scan_storcli_controller_uuid = ".$anvil->Database->quote($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-storcli'}{queries}}, $query; + } + + ### Process the rest of the variables now. + foreach my $type ("variable", "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}{serial_number}{$serial_number}{$type}}) + { + # Being in the 'variable' hash, 'is_temperature' is 'FALSE'. + my $new_variable_value = delete $anvil->data->{controller}{serial_number}{$serial_number}{$type}{$variable}; + my $temperature = $type eq "temperature" ? "TRUE" : "FALSE"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + temperature => $temperature, + }}); + if (exists $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_controllers'}{source_uuid}{$controller_uuid}{$type}{$variable}{scan_storcli_variable_uuid}) + { + # Look for changes + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_controllers'}{source_uuid}{$controller_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_controllers'}{source_uuid}{$controller_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_variable_value => $new_variable_value, + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_controllers'}{source_uuid}{$controller_uuid}{$type}{$variable}; + + # If there is no change, I still want to record the + # temperature (where applicable). So I setup like I will send + # an alert from the start, but will only actually send if + # something has changed. + my $message_key = "scan_storcli_warning_0003"; + my $alert_level = "info"; + my $temperature_state = "ok"; + my $temperature_is = "nominal"; + my $cleared = 0; + if ($type eq "temperature") + { + # It's a temperature, so change the default message. + $message_key = "scan_storcli_note_0067"; + if (($new_variable_value ne $old_variable_value)) + { + # If the temperature is rising, see if we + # need to set a high warning or critical, or, + # clear a low warning or critical. Check for + # the reverse if the temperature is dropping. + if ($old_variable_value eq "VANISHED") + { + ### NOTE: We don't (yet) check to see + ### if the drive is overheating + ### or freezing here. That + ### would require new logic and + ### is unlikely to be needed. + # Temperature is back. + $message_key = "scan_storcli_warning_0006"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + elsif ($old_variable_value > $new_variable_value) + { + # Rising + my $jumped = ($new_variable_value - $old_variable_value); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { jumped => $jumped }}); + if ($new_variable_value > $high_critical) + { + # Crossed the critical + # threshold. See if this is + # the first time. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0026"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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_variable_value > $high_warning) + { + # Crossed the warning + # threshold. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0027"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "alert_level" => $alert_level, + "message_key" => $message_key, + }}); + } + $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_variable_value > $clear_low_warning) + { + # Risen into the clear, make + # sure both warning and + # critical are cleared. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + my $cleared_warning = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared_critical => $cleared_critical, + cleared_warning => $cleared_warning, + }}); + if ($cleared_critical) + { + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0028"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + elsif ($cleared_warning) + { + # The temperature has + # dropped back down + # to safe levels. + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0028"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($new_variable_value > $clear_low_critical) + { + # Risen above critical, but + # not in the clear. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cleared_critical => $cleared_critical }}); + if ($cleared_critical) + { + # Set the warning. + my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0029"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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, + }}); + } + elsif ($jumped > $jump) + { + # The temperature jumped a + # large amount. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0030"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "alert_level" => $alert_level, + "message_key" => $message_key, + }}); + } + } + else + { + # Falling + my $jumped = $old_variable_value - $new_variable_value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { jumped => $jumped }}); + if ($new_variable_value < $low_critical) + { + # Dropped below the 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 => $serial_number.":".$variable."_low_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "critical"; + $message_key = "scan_storcli_note_0031"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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_variable_value < $low_warning) + { + # Crossed the 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 => $serial_number.":".$variable."_low_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }}); + if ($changed) + { + # This is the first + # time we rose above + # the critical + # threshold. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0032"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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, + }}); + } + elsif ($new_variable_value < $clear_high_warning) + { + # Dropped into the clear + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + my $cleared_warning = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared_critical => $cleared_critical, + cleared_warning => $cleared_warning, + }}); + if ($cleared_critical) + { + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0033"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + elsif ($cleared_warning) + { + # The temperature has + # dropped back down + # to safe levels. + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0033"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + } + elsif ($new_variable_value < $clear_high_critical) + { + # Dropped below critical, but + # not in the clear. + my $cleared_critical = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $serial_number.":".$variable."_high_critical", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cleared_critical => $cleared_critical }}); + if ($cleared_critical) + { + # Set the warning. + my $cleared_warning = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $serial_number.":".$variable."_high_warning", set_by => $THIS_FILE}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cleared_warning => $cleared_warning }}); + + $cleared = 1; + $alert_level = "warning"; + $message_key = "scan_storcli_note_0034"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + cleared => $cleared, + alert_level => $alert_level, + message_key => $message_key, + }}); + } + $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 ($jumped > $jump) + { + # The temperature dropped a + # large amount. + $alert_level = "warning"; + $message_key = "scan_storcli_note_0035"; + $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:$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_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}, + }}); + } + + ### TODO: Check to see if the new state of certain key + ### variables are worthy of setting a health weight. + ### We can't check just on changes. + + # Now actually generate an alert and save the changes if something + # changed. + if (($new_variable_value ne $old_variable_value)) + { + # Changed! If the old value was 'VANISHED', then a + # sensor or variable returned. Otherwise, for now, we + # treat everything as 'warning' and step down + # explicitely anything not of concern that proves + # noisey later (better safe than sorry). + + # The 'Safe ID' seems to change frequently, so we + # drop this to an 'info' level alert. + if ($variable eq "safe_id") + { + $alert_level = "info"; + $message_key = "scan_storcli_note_0070"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + + # If it is a temperature, we may want to make some + # changes to the alert level/message. + if ($type ne "temperature") + { + if ($old_variable_value eq "VANISHED") + { + $message_key = "scan_storcli_warning_0006"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }}); + } + + # Check for some important issues + if ($variable =~ /memory_correctable_errors/) + { + $alert_level = "warning"; + $message_key = "scan_storcli_warning_0046"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + elsif ($variable =~ /memory_uncorrectable_errors/) + { + $alert_level = "critical"; + $message_key = "scan_storcli_warning_0047"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + elsif ($variable =~ /controller_status/) + { + $alert_level = "critical"; + $message_key = "scan_storcli_warning_0048"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + alert_level => $alert_level, + message_key => $message_key, + }}); + } + # There more of interest... See: SELECT a.host_name, b.scan_storcli_controller_serial_number AS sn, b.scan_storcli_controller_model, c.scan_storcli_variable_name AS variable, c.scan_storcli_variable_value AS value, c.scan_storcli_variable_is_temperature AS temp, c.modified_date FROM hosts a, scan_storcli_controllers b, scan_storcli_variables c WHERE a.host_uuid = b.scan_storcli_controller_host_uuid AND b.scan_storcli_controller_uuid = c.scan_storcli_variable_source_uuid AND a.host_name = 'an-a07n01.alteeve.com'; + } + + # Send an alert telling the user that we've found a new controller. + my $variables = { + serial_number => $serial_number, + name => $variable, + old_value => $old_variable_value ? $old_variable_value : "--", + new_value => $new_variable_value, + high_critical_temperature => $high_critical, + high_warning_temperature => $high_warning, + low_critical_temperature => $low_critical, + low_warning_temperature => $low_warning, + jump => $jump, + }; + my $log_level = (($alert_level eq "warning") or ($alert_level eq "critical")) ? 1 : 2; + my $alert_header = $main_table_changed ? 0 : 1; + $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 => $alert_header, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = ".$anvil->Database->quote($new_variable_value).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + else + { + # New variable, record it. This is a 'warning' level as + # variables aren't expected to spawn into existence. + my $variables = { + serial_number => $serial_number, + name => $variable, + value => $new_variable_value, + }; + my $alert_header = $main_table_changed ? 0 : 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0004", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => "scan_storcli_warning_0004", + variables => $variables, + show_header => $alert_header, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # INSERT + my $query = " +INSERT INTO + scan_storcli_variables +( + scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date +) VALUES ( + ".$anvil->Database->quote($anvil->Get->uuid()).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + 'scan_storcli_controllers', + ".$anvil->Database->quote($controller_uuid).", + ".$anvil->Database->quote($temperature).", + ".$anvil->Database->quote($variable).", + ".$anvil->Database->quote($new_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-storcli'}{queries}}, $query; + } + } + } + + # Now look for any variables left from the previous scan that we didn't match up (and + # delete) this pass. + foreach my $type ("variable", "temperature") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_controllers'}{source_uuid}{$controller_uuid}{$type}}) + { + # This variable has vanished + my $old_variable_value = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_controllers'}{source_uuid}{$controller_uuid}{$type}{$variable}{scan_storcli_variable_value}; + my $variable_uuid = $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_controllers'}{source_uuid}{$controller_uuid}{$type}{$variable}{scan_storcli_variable_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_variable_value => $old_variable_value, + variable_uuid => $variable_uuid, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{'scan_storcli_controllers'}{source_uuid}{$controller_uuid}{$type}{$variable}; + + # If the old value is already 'VANISHED', ignore it. + next if $old_variable_value eq "VANISHED"; + + ### NOTE: For now, we're going to use warning level because variables + ### shouldn't vanish, but under an-cm, it did happen for + ### reasons that we never figured out. So later, we may drop + ### the alert level in some cases. + # Still here? Alert and UPDATE. + my $variables = { + serial_number => $serial_number, + name => $variable, + }; + my $alert_header = $main_table_changed ? 0 : 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0007", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => "scan_storcli_warning_0007", + variables => $variables, + show_header => $alert_header, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_variables +SET + scan_storcli_variable_value = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_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-storcli'}{queries}}, $query; + } + } + } + + # Delete the controller from the last scan so that we can find controllers that have been + # removed. + if (exists $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$controller_uuid}) + { + delete $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$controller_uuid}; + } + } + + # See if any controllers vanished. + foreach my $controller_uuid (keys %{$anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}}) + { + # Controller vanished! + my $old_serial_number = $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$controller_uuid}{scan_storcli_controller_serial_number}; + my $old_model = $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$controller_uuid}{scan_storcli_controller_model}; + my $old_alarm_state = $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$controller_uuid}{scan_storcli_controller_alarm_state}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + controller_uuid => $controller_uuid, + old_serial_number => $old_serial_number, + old_model => $old_model, + old_alarm_state => $old_alarm_state, + }}); + + # Delete it so that we know it has been processed. + delete $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$controller_uuid}; + + # If the old alarm state is already 'VANISHED', ignore it. + next if $old_alarm_state 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 = { + serial_number => $old_serial_number, + model => $old_model, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0008", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + message => "scan_storcli_warning_0008", + variables => $variables, + show_header => 1, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + my $query = " +UPDATE + scan_storcli_controllers +SET + scan_storcli_controller_alarm_state = 'VANISHED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_storcli_controller_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." +AND + scan_storcli_controller_uuid = ".$anvil->Database->quote($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-storcli'}{queries}}, $query; + } + + # Now commit the changes. + $anvil->Database->write({query => $anvil->data->{'scan-storcli'}{queries}, source => $THIS_FILE, line => __LINE__}); + $anvil->data->{'scan-storcli'}{queries} = []; + + return(0); +} + +# In some weird (and so far unreproducable) case, a controller will get recorded twice. If this happens, the +# system will think it keeps finding and losing controllers. So this check purges duplicates. +sub clear_duplicate_controllers +{ + my ($anvil) = @_; + + # Get a list of controllers on this host and count them by their serial numbers. + my $query = " +SELECT + scan_storcli_controller_uuid, + scan_storcli_controller_serial_number, + scan_storcli_controller_alarm_state +FROM + scan_storcli_controllers +WHERE + scan_storcli_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, + }}); + if ($count > 1) + { + ### NOTE: This works a little differently from originally intended, but it actually works + ### better. This should track 'uuid::serial_number' as the UUIDs are unique, the serial + ### numbers aren't. As it is now, only the first seen UUID is deleted. In most cases, + ### there are only two entries, so this deletes one and leaves the other, so everything + ### isn't discovered again new. When we re-do this for M3, swap the logic but skip the + ### most recently updated one. + # We'll loop through and track controllers by their serial numbers. If any controller serial + # number is seen 2 or more times, it will be purged and re-added on the next scan. + my $duplicate_controllers = {}; + foreach my $row (@{$results}) + { + my $scan_storcli_controller_uuid = $row->[0]; + my $scan_storcli_controller_serial_number = $row->[1]; + my $scan_storcli_controller_alarm_state = $row->[2]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_controller_uuid => $scan_storcli_controller_uuid, + scan_storcli_controller_serial_number => $scan_storcli_controller_serial_number, + scan_storcli_controller_alarm_state => $scan_storcli_controller_alarm_state, + }}); + + # Add this to the controllers we know about + if (not exists $duplicate_controllers->{$scan_storcli_controller_serial_number}) + { + $duplicate_controllers->{$scan_storcli_controller_serial_number}{count} = 1; + $duplicate_controllers->{$scan_storcli_controller_serial_number}{controller_uuid} = $scan_storcli_controller_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "duplicate_controllers->${scan_storcli_controller_serial_number}::count" => $duplicate_controllers->{$scan_storcli_controller_serial_number}{count}, + "duplicate_controllers->${scan_storcli_controller_serial_number}::controller_uuid" => $duplicate_controllers->{$scan_storcli_controller_serial_number}{controller_uuid}, + }}); + } + else + { + $duplicate_controllers->{$scan_storcli_controller_serial_number}{count}++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "duplicate_controllers->${scan_storcli_controller_serial_number}" => $duplicate_controllers->{$scan_storcli_controller_serial_number}, + }}); + } + } + + foreach my $scan_storcli_controller_serial_number (sort {$a cmp $b} keys %{$duplicate_controllers}) + { + my $count = $duplicate_controllers->{$scan_storcli_controller_serial_number}{count}; + my $scan_storcli_controller_uuid = $duplicate_controllers->{$scan_storcli_controller_serial_number}{controller_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_controller_serial_number => $scan_storcli_controller_serial_number, + count => $count, + scan_storcli_controller_uuid => $scan_storcli_controller_uuid, + }}); + + if ($count > 1) + { + # Duplicate. Send an alert and then purge. + my $variables = { + serial_number => $scan_storcli_controller_serial_number, + count => $count, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_warning_0052", variables => $variables}); + $anvil->Alert->register({ + alert_level => "warning", + show_header => 1, + message => "scan_storcli_warning_0052", + variables => $variables, + sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, + set_by => $THIS_FILE, + }); + + # We'll commit this batch of queries per controller + my $queries = []; + + # Delete all physical drives + my $query = "SELECT scan_storcli_physical_drive_uuid FROM scan_storcli_physical_drives WHERE scan_storcli_physical_drive_controller_uuid = ".$anvil->Database->quote($scan_storcli_controller_uuid).";"; + 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_storcli_physical_drive_uuid = $row->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_storcli_physical_drive_uuid => $scan_storcli_physical_drive_uuid }}); + + push @{$queries}, "DELETE FROM history.scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_physical_drives' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_physical_drive_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_physical_drives' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_physical_drive_uuid).";"; + + push @{$queries}, "DELETE FROM history.scan_storcli_physical_drives WHERE scan_storcli_physical_drive_uuid = ".$anvil->Database->quote($scan_storcli_physical_drive_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_physical_drives WHERE scan_storcli_physical_drive_uuid = ".$anvil->Database->quote($scan_storcli_physical_drive_uuid).";"; + } + + # The scan_storcli_drive_groups are linked to the virtual drives, so we need to + # pull up all the VDs on this controller and use their UUIDs to delete + # down-stream DGs + $query = "SELECT scan_storcli_virtual_drive_uuid FROM scan_storcli_virtual_drives WHERE scan_storcli_virtual_drive_controller_uuid = ".$anvil->Database->quote($scan_storcli_controller_uuid).";"; + $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_storcli_virtual_drive_uuid = $row->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_storcli_virtual_drive_uuid => $scan_storcli_virtual_drive_uuid }}); + + # Select the DGs under this VD. + my $query = "SELECT scan_storcli_drive_group_uuid FROM scan_storcli_drive_groups WHERE scan_storcli_drive_group_virtual_drive_uuid = ".$anvil->Database->quote($scan_storcli_virtual_drive_uuid).";"; + 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_storcli_drive_group_uuid = $row->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_storcli_drive_group_uuid => $scan_storcli_drive_group_uuid }}); + + push @{$queries}, "DELETE FROM history.scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_drive_groups' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_drive_group_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_drive_groups' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_drive_group_uuid).";"; + + push @{$queries}, "DELETE FROM history.scan_storcli_drive_groups WHERE scan_storcli_drive_group_uuid = ".$anvil->Database->quote($scan_storcli_drive_group_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_drive_groups WHERE scan_storcli_drive_group_uuid = ".$anvil->Database->quote($scan_storcli_drive_group_uuid).";"; + } + + push @{$queries}, "DELETE FROM history.scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_virtual_drives' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_virtual_drive_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_virtual_drives' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_virtual_drive_uuid).";"; + + push @{$queries}, "DELETE FROM history.scan_storcli_virtual_drives WHERE scan_storcli_virtual_drive_uuid = ".$anvil->Database->quote($scan_storcli_virtual_drive_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_virtual_drives WHERE scan_storcli_virtual_drive_uuid = ".$anvil->Database->quote($scan_storcli_virtual_drive_uuid).";"; + } + + # Delete all cachevaults (FBUs) + $query = "SELECT scan_storcli_cachevault_uuid FROM scan_storcli_cachevaults WHERE scan_storcli_cachevault_controller_uuid = ".$anvil->Database->quote($scan_storcli_controller_uuid).";"; + $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_storcli_cachevault_uuid = $row->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_storcli_cachevault_uuid => $scan_storcli_cachevault_uuid }}); + + push @{$queries}, "DELETE FROM history.scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_cachevaults' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_cachevault_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_cachevaults' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_cachevault_uuid).";"; + + push @{$queries}, "DELETE FROM history.scan_storcli_cachevaults WHERE scan_storcli_cachevault_uuid = ".$anvil->Database->quote($scan_storcli_cachevault_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_cachevaults WHERE scan_storcli_cachevault_uuid = ".$anvil->Database->quote($scan_storcli_cachevault_uuid).";"; + } + + # Delete all BBUs + $query = "SELECT scan_storcli_bbu_uuid FROM scan_storcli_bbus WHERE scan_storcli_bbu_controller_uuid = ".$anvil->Database->quote($scan_storcli_controller_uuid).";"; + $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_storcli_bbu_uuid = $row->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_storcli_bbu_uuid => $scan_storcli_bbu_uuid }}); + + push @{$queries}, "DELETE FROM history.scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_bbus' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_bbu_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_bbus' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_bbu_uuid).";"; + + push @{$queries}, "DELETE FROM history.scan_storcli_bbus WHERE scan_storcli_bbu_uuid = ".$anvil->Database->quote($scan_storcli_bbu_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_bbus WHERE scan_storcli_bbu_uuid = ".$anvil->Database->quote($scan_storcli_bbu_uuid).";"; + } + + # Finally, delete the controller. + push @{$queries}, "DELETE FROM history.scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_controllers' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_controller_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_variables WHERE scan_storcli_variable_source_table = 'scan_storcli_controllers' AND scan_storcli_variable_source_uuid = ".$anvil->Database->quote($scan_storcli_controller_uuid).";"; + + push @{$queries}, "DELETE FROM history.scan_storcli_controllers WHERE scan_storcli_controller_uuid = ".$anvil->Database->quote($scan_storcli_controller_uuid).";"; + push @{$queries}, "DELETE FROM scan_storcli_controllers WHERE scan_storcli_controller_uuid = ".$anvil->Database->quote($scan_storcli_controller_uuid).";"; + + # Commit. Because it's an array, it'll be done as a single transaction + foreach my $query (@{$queries}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + } + $anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); + } + } + } + + return(0); +} + +# This reads in the last scan's data. +sub read_last_scan +{ + my ($anvil) = @_; + + clear_duplicate_controllers($anvil); + + # Read in the controller(s) + my $query = " +SELECT + scan_storcli_controller_uuid, + scan_storcli_controller_serial_number, + scan_storcli_controller_model, + scan_storcli_controller_alarm_state, + scan_storcli_controller_cache_size +FROM + scan_storcli_controllers +WHERE + scan_storcli_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_storcli_controller_uuid = $row->[0]; + my $scan_storcli_controller_serial_number = $row->[1]; + my $scan_storcli_controller_model = $row->[2]; + my $scan_storcli_controller_alarm_state = $row->[3]; + my $scan_storcli_controller_cache_size = $row->[4]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_controller_uuid => $scan_storcli_controller_uuid, + scan_storcli_controller_serial_number => $scan_storcli_controller_serial_number, + scan_storcli_controller_model => $scan_storcli_controller_model, + scan_storcli_controller_alarm_state => $scan_storcli_controller_alarm_state, + scan_storcli_controller_cache_size => $scan_storcli_controller_cache_size, + }}); + + # Store the information about this controllers + $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$scan_storcli_controller_serial_number} = $scan_storcli_controller_uuid; + $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$scan_storcli_controller_uuid} = $scan_storcli_controller_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::controllers::by_serial::${scan_storcli_controller_serial_number}" => $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$scan_storcli_controller_serial_number}, + "scan-storcli::controllers::by_uuid::${scan_storcli_controller_uuid}" => $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$scan_storcli_controller_uuid}, + }}); + + $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$scan_storcli_controller_uuid} = { + scan_storcli_controller_serial_number => $scan_storcli_controller_serial_number, + scan_storcli_controller_model => $scan_storcli_controller_model, + scan_storcli_controller_alarm_state => $scan_storcli_controller_alarm_state, + scan_storcli_controller_cache_size => $scan_storcli_controller_cache_size, + }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::controllers::by_serial::$scan_storcli_controller_serial_number" => $anvil->data->{'scan-storcli'}{controllers}{by_serial}{$scan_storcli_controller_serial_number}, + "scan-storcli::controllers::by_uuid::$scan_storcli_controller_uuid" => $anvil->data->{'scan-storcli'}{controllers}{by_uuid}{$scan_storcli_controller_uuid}, + "sql::scan_storcli_controllers::scan_storcli_controller_uuid::${scan_storcli_controller_uuid}::scan_storcli_controller_serial_number" => $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$scan_storcli_controller_uuid}{scan_storcli_controller_serial_number}, + "sql::scan_storcli_controllers::scan_storcli_controller_uuid::${scan_storcli_controller_uuid}::scan_storcli_controller_model" => $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$scan_storcli_controller_uuid}{scan_storcli_controller_model}, + "sql::scan_storcli_controllers::scan_storcli_controller_uuid::${scan_storcli_controller_uuid}::scan_storcli_controller_alarm_state" => $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$scan_storcli_controller_uuid}{scan_storcli_controller_alarm_state}, + "sql::scan_storcli_controllers::scan_storcli_controller_uuid::${scan_storcli_controller_uuid}::scan_storcli_controller_cache_size" => $anvil->data->{sql}{scan_storcli_controllers}{scan_storcli_controller_uuid}{$scan_storcli_controller_uuid}{scan_storcli_controller_cache_size}, + }}); + } + undef $results; + + # Now load the cachevault data + $query = " +SELECT + scan_storcli_cachevault_uuid, + scan_storcli_cachevault_controller_uuid, + scan_storcli_cachevault_serial_number, + scan_storcli_cachevault_state, + scan_storcli_cachevault_design_capacity, + scan_storcli_cachevault_replacement_needed, + scan_storcli_cachevault_type, + scan_storcli_cachevault_model, + scan_storcli_cachevault_manufacture_date +FROM + scan_storcli_cachevaults +WHERE + scan_storcli_cachevault_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_storcli_cachevault_uuid = $row->[0]; + my $scan_storcli_cachevault_controller_uuid = $row->[1]; + my $scan_storcli_cachevault_serial_number = $row->[2]; + my $scan_storcli_cachevault_state = defined $row->[3] ? $row->[3] : ""; + my $scan_storcli_cachevault_design_capacity = defined $row->[4] ? $row->[4] : ""; + my $scan_storcli_cachevault_replacement_needed = defined $row->[5] ? $row->[5] : ""; + my $scan_storcli_cachevault_type = defined $row->[6] ? $row->[6] : ""; + my $scan_storcli_cachevault_model = defined $row->[7] ? $row->[7] : ""; + my $scan_storcli_cachevault_manufacture_date = defined $row->[8] ? $row->[8] : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_cachevault_uuid => $scan_storcli_cachevault_uuid, + scan_storcli_cachevault_controller_uuid => $scan_storcli_cachevault_controller_uuid, + scan_storcli_cachevault_serial_number => $scan_storcli_cachevault_serial_number, + scan_storcli_cachevault_state => $scan_storcli_cachevault_state, + scan_storcli_cachevault_design_capacity => $scan_storcli_cachevault_design_capacity, + scan_storcli_cachevault_replacement_needed => $scan_storcli_cachevault_replacement_needed, + scan_storcli_cachevault_type => $scan_storcli_cachevault_type, + scan_storcli_cachevault_model => $scan_storcli_cachevault_model, + scan_storcli_cachevault_manufacture_date => $scan_storcli_cachevault_manufacture_date, + }}); + + # Store the information about this cachevault + $anvil->data->{'scan-storcli'}{cachevaults}{by_serial}{$scan_storcli_cachevault_serial_number} = $scan_storcli_cachevault_uuid; + $anvil->data->{'scan-storcli'}{cachevaults}{by_uuid}{$scan_storcli_cachevault_uuid} = $scan_storcli_cachevault_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::cachevaults::by_serial::${scan_storcli_cachevault_serial_number}" => $anvil->data->{'scan-storcli'}{cachevaults}{by_serial}{$scan_storcli_cachevault_serial_number}, + "scan-storcli::cachevaults::by_uuid::${scan_storcli_cachevault_uuid}" => $anvil->data->{'scan-storcli'}{cachevaults}{by_uuid}{$scan_storcli_cachevault_uuid}, + }}); + + $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$scan_storcli_cachevault_uuid} = { + scan_storcli_cachevault_controller_uuid => $scan_storcli_cachevault_controller_uuid, + scan_storcli_cachevault_serial_number => $scan_storcli_cachevault_serial_number, + scan_storcli_cachevault_state => $scan_storcli_cachevault_state, + scan_storcli_cachevault_design_capacity => $scan_storcli_cachevault_design_capacity, + scan_storcli_cachevault_replacement_needed => $scan_storcli_cachevault_replacement_needed, + scan_storcli_cachevault_type => $scan_storcli_cachevault_type, + scan_storcli_cachevault_model => $scan_storcli_cachevault_model, + scan_storcli_cachevault_manufacture_date => $scan_storcli_cachevault_manufacture_date, + }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_storcli_cachevaults::scan_storcli_cachevault_uuid::${scan_storcli_cachevault_uuid}::scan_storcli_cachevault_controller_uuid" => $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$scan_storcli_cachevault_uuid}{scan_storcli_cachevault_controller_uuid}, + "sql::scan_storcli_cachevaults::scan_storcli_cachevault_uuid::${scan_storcli_cachevault_uuid}::scan_storcli_cachevault_serial_number" => $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$scan_storcli_cachevault_uuid}{scan_storcli_cachevault_serial_number}, + "sql::scan_storcli_cachevaults::scan_storcli_cachevault_uuid::${scan_storcli_cachevault_uuid}::scan_storcli_cachevault_state" => $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$scan_storcli_cachevault_uuid}{scan_storcli_cachevault_state}, + "sql::scan_storcli_cachevaults::scan_storcli_cachevault_uuid::${scan_storcli_cachevault_uuid}::scan_storcli_cachevault_design_capacity" => $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$scan_storcli_cachevault_uuid}{scan_storcli_cachevault_design_capacity}, + "sql::scan_storcli_cachevaults::scan_storcli_cachevault_uuid::${scan_storcli_cachevault_uuid}::scan_storcli_cachevault_replacement_needed" => $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$scan_storcli_cachevault_uuid}{scan_storcli_cachevault_replacement_needed}, + "sql::scan_storcli_cachevaults::scan_storcli_cachevault_uuid::${scan_storcli_cachevault_uuid}::scan_storcli_cachevault_type" => $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$scan_storcli_cachevault_uuid}{scan_storcli_cachevault_type}, + "sql::scan_storcli_cachevaults::scan_storcli_cachevault_uuid::${scan_storcli_cachevault_uuid}::scan_storcli_cachevault_model" => $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$scan_storcli_cachevault_uuid}{scan_storcli_cachevault_model}, + "sql::scan_storcli_cachevaults::scan_storcli_cachevault_uuid::${scan_storcli_cachevault_uuid}::scan_storcli_cachevault_manufacture_date" => $anvil->data->{sql}{scan_storcli_cachevaults}{scan_storcli_cachevault_uuid}{$scan_storcli_cachevault_uuid}{scan_storcli_cachevault_manufacture_date}, + }}); + } + undef $results; + + # The BBU data... + $query = " +SELECT + scan_storcli_bbu_uuid, + scan_storcli_bbu_controller_uuid, + scan_storcli_bbu_serial_number, + scan_storcli_bbu_type, + scan_storcli_bbu_model, + scan_storcli_bbu_state, + scan_storcli_bbu_manufacture_date, + scan_storcli_bbu_design_capacity, + scan_storcli_bbu_replacement_needed +FROM + scan_storcli_bbus +WHERE + scan_storcli_bbu_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_storcli_bbu_uuid = $row->[0]; + my $scan_storcli_bbu_controller_uuid = $row->[1]; + my $scan_storcli_bbu_serial_number = $row->[2]; + my $scan_storcli_bbu_type = defined $row->[3] ? $row->[3] : ""; + my $scan_storcli_bbu_model = defined $row->[4] ? $row->[4] : ""; + my $scan_storcli_bbu_state = defined $row->[5] ? $row->[5] : ""; + my $scan_storcli_bbu_manufacture_date = defined $row->[6] ? $row->[6] : ""; + my $scan_storcli_bbu_design_capacity = defined $row->[7] ? $row->[7] : ""; + my $scan_storcli_bbu_replacement_needed = defined $row->[8] ? $row->[8] : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_bbu_uuid => $scan_storcli_bbu_uuid, + scan_storcli_bbu_controller_uuid => $scan_storcli_bbu_controller_uuid, + scan_storcli_bbu_serial_number => $scan_storcli_bbu_serial_number, + scan_storcli_bbu_type => $scan_storcli_bbu_type, + scan_storcli_bbu_model => $scan_storcli_bbu_model, + scan_storcli_bbu_state => $scan_storcli_bbu_state, + scan_storcli_bbu_manufacture_date => $scan_storcli_bbu_manufacture_date, + scan_storcli_bbu_design_capacity => $scan_storcli_bbu_design_capacity, + scan_storcli_bbu_replacement_needed => $scan_storcli_bbu_replacement_needed, + }}); + + # Store the information about this BBU + $anvil->data->{'scan-storcli'}{bbus}{by_serial}{$scan_storcli_bbu_serial_number} = $scan_storcli_bbu_uuid; + $anvil->data->{'scan-storcli'}{bbus}{by_uuid}{$scan_storcli_bbu_uuid} = $scan_storcli_bbu_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::bbus::by_serial::${scan_storcli_bbu_serial_number}" => $anvil->data->{'scan-storcli'}{bbus}{by_serial}{$scan_storcli_bbu_serial_number}, + "scan-storcli::bbus::by_uuid::${scan_storcli_bbu_uuid}" => $anvil->data->{'scan-storcli'}{bbus}{by_uuid}{$scan_storcli_bbu_uuid}, + }}); + + $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$scan_storcli_bbu_uuid} = { + scan_storcli_bbu_controller_uuid => $scan_storcli_bbu_controller_uuid, + scan_storcli_bbu_serial_number => $scan_storcli_bbu_serial_number, + scan_storcli_bbu_type => $scan_storcli_bbu_type, + scan_storcli_bbu_model => $scan_storcli_bbu_model, + scan_storcli_bbu_state => $scan_storcli_bbu_state, + scan_storcli_bbu_manufacture_date => $scan_storcli_bbu_manufacture_date, + scan_storcli_bbu_design_capacity => $scan_storcli_bbu_design_capacity, + scan_storcli_bbu_replacement_needed => $scan_storcli_bbu_replacement_needed, + }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_storcli_bbus::scan_storcli_bbu_uuid::${scan_storcli_bbu_uuid}::scan_storcli_bbu_controller_uuid" => $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$scan_storcli_bbu_uuid}{scan_storcli_bbu_controller_uuid}, + "sql::scan_storcli_bbus::scan_storcli_bbu_uuid::${scan_storcli_bbu_uuid}::scan_storcli_bbu_serial_number" => $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$scan_storcli_bbu_uuid}{scan_storcli_bbu_serial_number}, + "sql::scan_storcli_bbus::scan_storcli_bbu_uuid::${scan_storcli_bbu_uuid}::scan_storcli_bbu_type" => $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$scan_storcli_bbu_uuid}{scan_storcli_bbu_type}, + "sql::scan_storcli_bbus::scan_storcli_bbu_uuid::${scan_storcli_bbu_uuid}::scan_storcli_bbu_model" => $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$scan_storcli_bbu_uuid}{scan_storcli_bbu_model}, + "sql::scan_storcli_bbus::scan_storcli_bbu_uuid::${scan_storcli_bbu_uuid}::scan_storcli_bbu_state" => $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$scan_storcli_bbu_uuid}{scan_storcli_bbu_state}, + "sql::scan_storcli_bbus::scan_storcli_bbu_uuid::${scan_storcli_bbu_uuid}::scan_storcli_bbu_manufacture_date" => $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$scan_storcli_bbu_uuid}{scan_storcli_bbu_manufacture_date}, + "sql::scan_storcli_bbus::scan_storcli_bbu_uuid::${scan_storcli_bbu_uuid}::scan_storcli_bbu_design_capacity" => $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$scan_storcli_bbu_uuid}{scan_storcli_bbu_design_capacity}, + "sql::scan_storcli_bbus::scan_storcli_bbu_uuid::${scan_storcli_bbu_uuid}::scan_storcli_bbu_replacement_needed" => $anvil->data->{sql}{scan_storcli_bbus}{scan_storcli_bbu_uuid}{$scan_storcli_bbu_uuid}{scan_storcli_bbu_replacement_needed}, + }}); + } + undef $results; + + # The virtual drives data... + $query = " +SELECT + scan_storcli_virtual_drive_uuid, + scan_storcli_virtual_drive_controller_uuid, + scan_storcli_virtual_drive_id_string, + scan_storcli_virtual_drive_creation_date, + scan_storcli_virtual_drive_data_protection, + scan_storcli_virtual_drive_disk_cache_policy, + scan_storcli_virtual_drive_emulation_type, + scan_storcli_virtual_drive_encryption, + scan_storcli_virtual_drive_blocks, + scan_storcli_virtual_drive_strip_size, + scan_storcli_virtual_drive_drives_per_span, + scan_storcli_virtual_drive_span_depth, + scan_storcli_virtual_drive_scsi_naa_id +FROM + scan_storcli_virtual_drives +WHERE + scan_storcli_virtual_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_storcli_virtual_drive_uuid = $row->[0]; + my $scan_storcli_virtual_drive_controller_uuid = $row->[1]; + my $scan_storcli_virtual_drive_id_string = $row->[2]; + my $scan_storcli_virtual_drive_creation_date = defined $row->[3] ? $row->[3] : ""; + my $scan_storcli_virtual_drive_data_protection = defined $row->[4] ? $row->[4] : ""; + my $scan_storcli_virtual_drive_disk_cache_policy = defined $row->[5] ? $row->[5] : ""; + my $scan_storcli_virtual_drive_emulation_type = defined $row->[6] ? $row->[6] : ""; + my $scan_storcli_virtual_drive_encryption = defined $row->[7] ? $row->[7] : ""; + my $scan_storcli_virtual_drive_blocks = defined $row->[8] ? $row->[8] : ""; + my $scan_storcli_virtual_drive_strip_size = defined $row->[9] ? $row->[9] : ""; + my $scan_storcli_virtual_drive_drives_per_span = defined $row->[10] ? $row->[10] : ""; + my $scan_storcli_virtual_drive_span_depth = defined $row->[11] ? $row->[11] : ""; + my $scan_storcli_virtual_drive_scsi_naa_id = defined $row->[12] ? $row->[12] : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_virtual_drive_uuid => $scan_storcli_virtual_drive_uuid, + scan_storcli_virtual_drive_controller_uuid => $scan_storcli_virtual_drive_controller_uuid, + scan_storcli_virtual_drive_id_string => $scan_storcli_virtual_drive_id_string, + scan_storcli_virtual_drive_creation_date => $scan_storcli_virtual_drive_creation_date, + scan_storcli_virtual_drive_data_protection => $scan_storcli_virtual_drive_data_protection, + scan_storcli_virtual_drive_disk_cache_policy => $scan_storcli_virtual_drive_disk_cache_policy, + scan_storcli_virtual_drive_emulation_type => $scan_storcli_virtual_drive_emulation_type, + scan_storcli_virtual_drive_encryption => $scan_storcli_virtual_drive_encryption, + scan_storcli_virtual_drive_blocks => $scan_storcli_virtual_drive_blocks, + scan_storcli_virtual_drive_strip_size => $scan_storcli_virtual_drive_strip_size, + scan_storcli_virtual_drive_drives_per_span => $scan_storcli_virtual_drive_drives_per_span, + scan_storcli_virtual_drive_span_depth => $scan_storcli_virtual_drive_span_depth, + scan_storcli_virtual_drive_scsi_naa_id => $scan_storcli_virtual_drive_scsi_naa_id, + }}); + + # Store the information about this virtual drive. + $anvil->data->{'scan-storcli'}{virtual_drives}{by_id_string}{$scan_storcli_virtual_drive_id_string} = $scan_storcli_virtual_drive_uuid; + $anvil->data->{'scan-storcli'}{virtual_drives}{by_uuid}{$scan_storcli_virtual_drive_uuid} = $scan_storcli_virtual_drive_id_string; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::virtual_drives::by_id_string::${scan_storcli_virtual_drive_id_string}" => $anvil->data->{'scan-storcli'}{virtual_drives}{by_id_string}{$scan_storcli_virtual_drive_id_string}, + "scan-storcli::virtual_drives::by_uuid::${scan_storcli_virtual_drive_uuid}" => $anvil->data->{'scan-storcli'}{virtual_drives}{by_uuid}{$scan_storcli_virtual_drive_uuid}, + }}); + + # Store the drive group data. (Drive groups have no SN) + $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid} = { + scan_storcli_virtual_drive_controller_uuid => $scan_storcli_virtual_drive_controller_uuid, + scan_storcli_virtual_drive_id_string => $scan_storcli_virtual_drive_id_string, + scan_storcli_virtual_drive_creation_date => $scan_storcli_virtual_drive_creation_date, + scan_storcli_virtual_drive_data_protection => $scan_storcli_virtual_drive_data_protection, + scan_storcli_virtual_drive_disk_cache_policy => $scan_storcli_virtual_drive_disk_cache_policy, + scan_storcli_virtual_drive_emulation_type => $scan_storcli_virtual_drive_emulation_type, + scan_storcli_virtual_drive_encryption => $scan_storcli_virtual_drive_encryption, + scan_storcli_virtual_drive_blocks => $scan_storcli_virtual_drive_blocks, + scan_storcli_virtual_drive_strip_size => $scan_storcli_virtual_drive_strip_size, + scan_storcli_virtual_drive_drives_per_span => $scan_storcli_virtual_drive_drives_per_span, + scan_storcli_virtual_drive_span_depth => $scan_storcli_virtual_drive_span_depth, + scan_storcli_virtual_drive_scsi_naa_id => $scan_storcli_virtual_drive_scsi_naa_id, + }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_controller_uuid" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_controller_uuid}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_id_string" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_id_string}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_creation_date" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_creation_date}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_data_protection" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_data_protection}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_disk_cache_policy" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_disk_cache_policy}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_emulation_type" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_emulation_type}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_encryption" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_encryption}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_blocks" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_blocks}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_strip_size" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_strip_size}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_drives_per_span" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_drives_per_span}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_span_depth" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_span_depth}, + "sql::scan_storcli_virtual_drives::scan_storcli_virtual_drive_uuid::${scan_storcli_virtual_drive_uuid}::scan_storcli_virtual_drive_scsi_naa_id" => $anvil->data->{sql}{scan_storcli_virtual_drives}{scan_storcli_virtual_drive_uuid}{$scan_storcli_virtual_drive_uuid}{scan_storcli_virtual_drive_scsi_naa_id}, + }}); + } + undef $results; + + # The drive group data... + $query = " +SELECT + scan_storcli_drive_group_uuid, + scan_storcli_drive_group_virtual_drive_uuid, + scan_storcli_drive_group_id_string, + scan_storcli_drive_group_access, + scan_storcli_drive_group_array_size, + scan_storcli_drive_group_array_state, + scan_storcli_drive_group_cache, + scan_storcli_drive_group_cachecade, + scan_storcli_drive_group_consistent, + scan_storcli_drive_group_disk_cache, + scan_storcli_drive_group_raid_type, + scan_storcli_drive_group_read_cache, + scan_storcli_drive_group_scheduled_cc, + scan_storcli_drive_group_write_cache +FROM + scan_storcli_drive_groups +WHERE + scan_storcli_drive_group_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_storcli_drive_group_uuid = $row->[0]; + my $scan_storcli_drive_group_virtual_drive_uuid = $row->[1]; + my $scan_storcli_drive_group_id_string = $row->[2]; + my $scan_storcli_drive_group_access = defined $row->[3] ? $row->[3] : ""; + my $scan_storcli_drive_group_array_size = defined $row->[4] ? $row->[4] : ""; + my $scan_storcli_drive_group_array_state = defined $row->[5] ? $row->[5] : ""; + my $scan_storcli_drive_group_cache = defined $row->[6] ? $row->[6] : ""; + my $scan_storcli_drive_group_cachecade = defined $row->[7] ? $row->[7] : ""; + my $scan_storcli_drive_group_consistent = defined $row->[8] ? $row->[8] : ""; + my $scan_storcli_drive_group_disk_cache = defined $row->[9] ? $row->[9] : ""; + my $scan_storcli_drive_group_raid_type = defined $row->[10] ? $row->[10] : ""; + my $scan_storcli_drive_group_read_cache = defined $row->[11] ? $row->[11] : ""; + my $scan_storcli_drive_group_scheduled_cc = defined $row->[12] ? $row->[12] : ""; + my $scan_storcli_drive_group_write_cache = defined $row->[13] ? $row->[13] : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_drive_group_uuid => $scan_storcli_drive_group_uuid, + scan_storcli_drive_group_virtual_drive_uuid => $scan_storcli_drive_group_virtual_drive_uuid, + scan_storcli_drive_group_id_string => $scan_storcli_drive_group_id_string, + scan_storcli_drive_group_access => $scan_storcli_drive_group_access, + scan_storcli_drive_group_array_size => $scan_storcli_drive_group_array_size, + scan_storcli_drive_group_array_state => $scan_storcli_drive_group_array_state, + scan_storcli_drive_group_cache => $scan_storcli_drive_group_cache, + scan_storcli_drive_group_cachecade => $scan_storcli_drive_group_cachecade, + scan_storcli_drive_group_consistent => $scan_storcli_drive_group_consistent, + scan_storcli_drive_group_disk_cache => $scan_storcli_drive_group_disk_cache, + scan_storcli_drive_group_raid_type => $scan_storcli_drive_group_raid_type, + scan_storcli_drive_group_read_cache => $scan_storcli_drive_group_read_cache, + scan_storcli_drive_group_scheduled_cc => $scan_storcli_drive_group_scheduled_cc, + scan_storcli_drive_group_write_cache => $scan_storcli_drive_group_write_cache, + }}); + + # Store the information about this virtual drive. + $anvil->data->{'scan-storcli'}{drive_groups}{by_id_string}{$scan_storcli_drive_group_id_string} = $scan_storcli_drive_group_uuid; + $anvil->data->{'scan-storcli'}{drive_groups}{by_uuid}{$scan_storcli_drive_group_uuid} = $scan_storcli_drive_group_id_string; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::drive_groups::by_id_string::${scan_storcli_drive_group_id_string}" => $anvil->data->{'scan-storcli'}{drive_groups}{by_id_string}{$scan_storcli_drive_group_id_string}, + "scan-storcli::drive_groups::by_uuid::${scan_storcli_drive_group_uuid}" => $anvil->data->{'scan-storcli'}{drive_groups}{by_uuid}{$scan_storcli_drive_group_uuid}, + }}); + + # Store the drive group data. (Drive groups have no SN) + $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid} = { + scan_storcli_drive_group_virtual_drive_uuid => $scan_storcli_drive_group_virtual_drive_uuid, + scan_storcli_drive_group_id_string => $scan_storcli_drive_group_id_string, + scan_storcli_drive_group_access => $scan_storcli_drive_group_access, + scan_storcli_drive_group_array_size => $scan_storcli_drive_group_array_size, + scan_storcli_drive_group_array_state => $scan_storcli_drive_group_array_state, + scan_storcli_drive_group_cache => $scan_storcli_drive_group_cache, + scan_storcli_drive_group_cachecade => $scan_storcli_drive_group_cachecade, + scan_storcli_drive_group_consistent => $scan_storcli_drive_group_consistent, + scan_storcli_drive_group_disk_cache => $scan_storcli_drive_group_disk_cache, + scan_storcli_drive_group_raid_type => $scan_storcli_drive_group_raid_type, + scan_storcli_drive_group_read_cache => $scan_storcli_drive_group_read_cache, + scan_storcli_drive_group_scheduled_cc => $scan_storcli_drive_group_scheduled_cc, + scan_storcli_drive_group_write_cache => $scan_storcli_drive_group_write_cache, + }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_virtual_drive_uuid" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_virtual_drive_uuid}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_id_string" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_id_string}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_access" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_access}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_array_size" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_array_size}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_array_state" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_array_state}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_cache" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_cache}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_cachecade" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_cachecade}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_consistent" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_consistent}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_disk_cache" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_disk_cache}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_raid_type" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_raid_type}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_read_cache" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_read_cache}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_scheduled_cc" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_scheduled_cc}, + "sql::scan_storcli_drive_groups::scan_storcli_drive_group_uuid::${scan_storcli_drive_group_uuid}::scan_storcli_drive_group_write_cache" => $anvil->data->{sql}{scan_storcli_drive_groups}{scan_storcli_drive_group_uuid}{$scan_storcli_drive_group_uuid}{scan_storcli_drive_group_write_cache}, + }}); + } + undef $results; + + # And now, the physical drives. + $query = " +SELECT + scan_storcli_physical_drive_uuid, + scan_storcli_physical_drive_controller_uuid, + scan_storcli_physical_drive_virtual_drive, + scan_storcli_physical_drive_drive_group, + scan_storcli_physical_drive_enclosure_id, + scan_storcli_physical_drive_slot_number, + scan_storcli_physical_drive_serial_number, + scan_storcli_physical_drive_size, + scan_storcli_physical_drive_sector_size, + scan_storcli_physical_drive_vendor, + scan_storcli_physical_drive_model, + scan_storcli_physical_drive_self_encrypting_drive +FROM + scan_storcli_physical_drives +WHERE + scan_storcli_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_storcli_physical_drive_uuid = $row->[0]; + my $scan_storcli_physical_drive_controller_uuid = $row->[1]; + my $scan_storcli_physical_drive_virtual_drive = defined $row->[2] ? $row->[2] : ""; + my $scan_storcli_physical_drive_drive_group = defined $row->[3] ? $row->[3] : ""; + my $scan_storcli_physical_drive_enclosure_id = defined $row->[4] ? $row->[4] : ""; + my $scan_storcli_physical_drive_slot_number = defined $row->[5] ? $row->[5] : ""; + my $scan_storcli_physical_drive_serial_number = defined $row->[6] ? $row->[6] : ""; + my $scan_storcli_physical_drive_size = defined $row->[7] ? $row->[7] : ""; + my $scan_storcli_physical_drive_sector_size = defined $row->[8] ? $row->[8] : ""; + my $scan_storcli_physical_drive_vendor = defined $row->[9] ? $row->[9] : ""; + my $scan_storcli_physical_drive_model = defined $row->[10] ? $row->[10] : ""; + my $scan_storcli_physical_drive_self_encrypting_drive = defined $row->[11] ? $row->[11] : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_physical_drive_uuid => $scan_storcli_physical_drive_uuid, + scan_storcli_physical_drive_controller_uuid => $scan_storcli_physical_drive_controller_uuid, + scan_storcli_physical_drive_virtual_drive => $scan_storcli_physical_drive_virtual_drive, + scan_storcli_physical_drive_drive_group => $scan_storcli_physical_drive_drive_group, + scan_storcli_physical_drive_enclosure_id => $scan_storcli_physical_drive_enclosure_id, + scan_storcli_physical_drive_slot_number => $scan_storcli_physical_drive_slot_number, + scan_storcli_physical_drive_serial_number => $scan_storcli_physical_drive_serial_number, + scan_storcli_physical_drive_size => $scan_storcli_physical_drive_size, + scan_storcli_physical_drive_sector_size => $scan_storcli_physical_drive_sector_size, + scan_storcli_physical_drive_vendor => $scan_storcli_physical_drive_vendor, + scan_storcli_physical_drive_model => $scan_storcli_physical_drive_model, + scan_storcli_physical_drive_self_encrypting_drive => $scan_storcli_physical_drive_self_encrypting_drive, + }}); + + # Make it so that we can look up the serial number from the drive's UUID and vice versa + $anvil->data->{'scan-storcli'}{physical_drives}{by_serial}{$scan_storcli_physical_drive_serial_number} = $scan_storcli_physical_drive_uuid; + $anvil->data->{'scan-storcli'}{physical_drives}{by_uuid}{$scan_storcli_physical_drive_uuid} = $scan_storcli_physical_drive_serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "scan-storcli::physical_drives::by_serial::${scan_storcli_physical_drive_serial_number}" => $anvil->data->{'scan-storcli'}{physical_drives}{by_serial}{$scan_storcli_physical_drive_serial_number}, + "scan-storcli::physical_drives::by_uuid::${scan_storcli_physical_drive_uuid}" => $anvil->data->{'scan-storcli'}{physical_drives}{by_uuid}{$scan_storcli_physical_drive_uuid}, + }}); + + # Store the information about this physical drive + $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid} = { + scan_storcli_physical_drive_controller_uuid => $scan_storcli_physical_drive_controller_uuid, + scan_storcli_physical_drive_virtual_drive => $scan_storcli_physical_drive_virtual_drive, + scan_storcli_physical_drive_drive_group => $scan_storcli_physical_drive_drive_group, + scan_storcli_physical_drive_enclosure_id => $scan_storcli_physical_drive_enclosure_id, + scan_storcli_physical_drive_slot_number => $scan_storcli_physical_drive_slot_number, + scan_storcli_physical_drive_serial_number => $scan_storcli_physical_drive_serial_number, + scan_storcli_physical_drive_size => $scan_storcli_physical_drive_size, + scan_storcli_physical_drive_sector_size => $scan_storcli_physical_drive_sector_size, + scan_storcli_physical_drive_vendor => $scan_storcli_physical_drive_vendor, + scan_storcli_physical_drive_model => $scan_storcli_physical_drive_model, + scan_storcli_physical_drive_self_encrypting_drive => $scan_storcli_physical_drive_self_encrypting_drive, + }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_controller_uuid" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_controller_uuid}, + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_virtual_drive" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_virtual_drive}, + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_drive_group" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_drive_group}, + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_enclosure_id" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_enclosure_id}, + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_slot_number" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_slot_number}, + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_serial_number" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_serial_number}, + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_size" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_size}, + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_sector_size" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_sector_size}, + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_vendor" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_vendor}, + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_model" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_model}, + "sql::scan_storcli_physical_drives::scan_storcli_physical_drive_uuid::${scan_storcli_physical_drive_uuid}::scan_storcli_physical_drive_self_encrypting_drive" => $anvil->data->{sql}{scan_storcli_physical_drives}{scan_storcli_physical_drive_uuid}{$scan_storcli_physical_drive_uuid}{scan_storcli_physical_drive_self_encrypting_drive}, + }}); + } + undef $results; + + # Lastly, the variables. + $query = " +SELECT + scan_storcli_variable_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value +FROM + scan_storcli_variables +WHERE + scan_storcli_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_storcli_variable_uuid = $row->[0]; + my $scan_storcli_variable_source_table = $row->[1]; + my $scan_storcli_variable_source_uuid = $row->[2]; + my $scan_storcli_variable_is_temperature = $row->[3]; + my $scan_storcli_variable_name = $row->[4]; + my $scan_storcli_variable_value = defined $row->[5] ? $row->[5] : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_storcli_variable_uuid => $scan_storcli_variable_uuid, + scan_storcli_variable_source_table => $scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid => $scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature => $scan_storcli_variable_is_temperature, + scan_storcli_variable_name => $scan_storcli_variable_name, + scan_storcli_variable_value => $scan_storcli_variable_value, + }}); + + # We store these differently for easier reference. + my $type = $scan_storcli_variable_is_temperature eq "1" ? "temperature" : "variable"; + $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{$scan_storcli_variable_source_table}{source_uuid}{$scan_storcli_variable_source_uuid}{$type}{$scan_storcli_variable_name} = { + scan_storcli_variable_uuid => $scan_storcli_variable_uuid, + scan_storcli_variable_is_temperature => $scan_storcli_variable_is_temperature, + scan_storcli_variable_value => $scan_storcli_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_storcli_variables::scan_storcli_variable_uuid::source_table::${scan_storcli_variable_source_table}::source_uuid::${scan_storcli_variable_source_uuid}::${type}::${scan_storcli_variable_name}::scan_storcli_variable_uuid" => $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{$scan_storcli_variable_source_table}{source_uuid}{$scan_storcli_variable_source_uuid}{$type}{$scan_storcli_variable_name}{scan_storcli_variable_uuid}, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_storcli_variables::scan_storcli_variable_uuid::source_table::${scan_storcli_variable_source_table}::source_uuid::${scan_storcli_variable_source_uuid}::${type}::${scan_storcli_variable_name}::scan_storcli_variable_is_temperature" => $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{$scan_storcli_variable_source_table}{source_uuid}{$scan_storcli_variable_source_uuid}{$type}{$scan_storcli_variable_name}{scan_storcli_variable_is_temperature}, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_storcli_variables::scan_storcli_variable_uuid::source_table::${scan_storcli_variable_source_table}::source_uuid::${scan_storcli_variable_source_uuid}::${type}::${scan_storcli_variable_name}::scan_storcli_variable_value" => $anvil->data->{sql}{scan_storcli_variables}{scan_storcli_variable_uuid}{source_table}{$scan_storcli_variable_source_table}{source_uuid}{$scan_storcli_variable_source_uuid}{$type}{$scan_storcli_variable_name}{scan_storcli_variable_value}, + }}); + } + undef $results; + + # Return the number + 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 + ### 'storcli64 show all' and parse 'System Overview'. + # Loops through reach found controller. + foreach my $controller (1..$anvil->data->{'scan-storcli'}{adapter_count}) + { + # We drop the number by 1 because the '/cX' starts at '0' where the controller count starts + # at '1'. + my $adapter = ($controller - 1); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + controller => $controller, + adapter => $adapter, + }}); + + # Read in controller data. + my $serial_number = get_controller_info($anvil, $adapter); + + # We use dummy VDs and DGs to store drives not allocated to either yet. The drives will + # reference their parent controller, but the VDs and DGs won't. To deal with this, we need to + # allocate the pseudo DG and VG to something, so we'll use the first controller's SN that we + # see. + if ($controller eq "1") + { + my $scan_storcli_virtual_drive_id_string = $serial_number."-vd9999"; + $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{on_controller} = $serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${scan_storcli_virtual_drive_id_string}::variable::on_controller" => $anvil->data->{virtual_drive}{$scan_storcli_virtual_drive_id_string}{variable}{on_controller}, + }}); + } + + # Read in cachevault (FBU) data (if it exists). + get_cachevault_data($anvil, $adapter, $serial_number); + + # Read in BBU data (if it exists). + get_bbu_data($anvil, $adapter, $serial_number); + + # Read in virtual drive information. + get_virtual_drive_data($anvil, $adapter, $serial_number); + + # Read in the physical disk information. + get_physical_disk_data($anvil, $adapter, $serial_number); + } + + return(0); +} + +# This looks for physical disks on the controller. +sub get_physical_disk_data +{ + my ($anvil, $adapter, $serial_number) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + adapter => $adapter, + serial_number => $serial_number, + }}); + + my $virtual_drive = $serial_number."-vd9999"; + my $drive_group = 9999; + my $enclosure_id = ""; + my $slot_number = ""; + my $device_id = ""; + my $state = ""; + my $drive_size = ""; + my $interface = ""; + my $drive_media = ""; + my $self_encrypting_drive = ""; + my $protection_info = ""; + my $drive_model = ""; + my $spun_up = ""; + my $in_drive_header = 0; + my $in_port_status = 0; + my $start_break = 0; + my $sector_size = 0; + my $sector_variables = []; + my $shell_call = $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{physical_disk_data}; + 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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + ### TODO: Make sure we don't hit a case where we don't find the virtual drive ID string + ### before we start recording data. If we do, we'll have to artificially create the ID + ### from the controller's serial number (which is pretty safe). + # If I am in the drive header, look for this drive data + # EID :Slt DID State DG Size Intf Med SED PI SeSz Model Sp + # 252 :0 9 Onln 0 136.218 GB SAS HDD N N 512B MK1401GRRB U + if (($in_drive_header) && ($line =~ /^$enclosure_id:$slot_number\s+(\d+)\s+(.*?)\s+(.*?)\s+(.*?B)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?B)\s+(.*?)\s+(.*)$/)) + { + $device_id = $1; + $state = $2; + $drive_group = $3; + $drive_size = $4; + $interface = $5; + $drive_media = $6; + $self_encrypting_drive = $7; + $protection_info = $8; + $sector_size = $9; + $drive_model = $10; + $spun_up = $11; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + enclosure_id => $enclosure_id, + slot_number => $slot_number, + device_id => $device_id, + 'state' => $state, + drive_group => $drive_group, + drive_size => $drive_size, + interface => $interface, + drive_media => $drive_media, + self_encrypting_drive => $self_encrypting_drive, + protection_info => $protection_info, + sector_size => $sector_size, + drive_model => $drive_model, + spun_up => $spun_up, + }}); + + # If it isn't in a drive group, it also won't be in a virtual drive. + if ($drive_group eq "-") + { + $drive_group = 9999 ; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drive_group => $drive_group }}); + } + elsif ($drive_group =~ /^\d+$/) + { + # Find the virtual drive this drive is connected to, if any. + foreach my $this_virtual_drive (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}}) + { + # This avoids auto-vivication of the drive group under the virtual drive + next if not exists $anvil->data->{virtual_drive}{$this_virtual_drive}{drive_group}{$drive_group}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${this_virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::drive_size" => $anvil->data->{virtual_drive}{$this_virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_size}, + }}); + if ($anvil->data->{virtual_drive}{$this_virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_size}) + { + # Found it. + $virtual_drive = $this_virtual_drive; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { virtual_drive => $virtual_drive }}); + last; + } + } + } + else + { + # Not sure that this should ever happen... + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1 , key => "scan_storcli_warning_0005", variables => { + line => $line, + drive_group => $drive_group, + }}); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { virtual_drive => $virtual_drive }}); + + # We need to record this here because drives not in a drive group will be missed + # later in process_vg_pd_list_data(). Drives processed there may overwrite this data, + # which is fine. + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{device_id} = $device_id; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{'state'} = $state; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_size} = $drive_size; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{interface} = $interface; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_media} = $drive_media; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{self_encrypting_drive} = $self_encrypting_drive; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{protection_info} = $protection_info; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sector_size} = $sector_size; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_model} = $drive_model; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{spun_up} = $spun_up; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{on_controller} = $serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::device_id" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{device_id}, + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::state" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{'state'}, + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::drive_size" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_size}, + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::interface" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{interface}, + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::drive_media" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_media}, + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::self_encrypting_drive" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{self_encrypting_drive}, + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::protection_info" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{protection_info}, + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::sector_size" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sector_size}, + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::drive_model" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_model}, + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::spun_up" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{spun_up}, + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::on_controller" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{on_controller}, + }}); + next; + } + + # See if I am entering or exiting a section. + if ($line =~ /Drive \/c$adapter\/e(\d+)\/s(\d+):/i) + { + $enclosure_id = $1; + $slot_number = $2; + #$slot_number = sprintf("%02d", $slot_number); + $in_drive_header = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + enclosure_id => $enclosure_id, + slot_number => $slot_number, + in_drive_header => $in_drive_header, + }}); + next; + } + if ($line =~ /Drive \/c$adapter\/e(\d+)\/s(\d+) State/i) + { + $enclosure_id = $1; + $slot_number = $2; + #$slot_number = sprintf("%02d", $slot_number); + $in_drive_header = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + enclosure_id => $enclosure_id, + slot_number => $slot_number, + in_drive_header => $in_drive_header, + }}); + next; + } + if ($line =~ /^Port Status /) + { + $in_port_status = 1; + $start_break = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + in_port_status => $in_port_status, + start_break => $start_break, + }}); + } + if (($line =~ /^--------/) && ($in_port_status)) + { + if (not $start_break) + { + # Split point set, must be the start break + $start_break = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { start_break => $start_break }}); + next; + } + else + { + # In 'port status' and start break set, must be end break. + $in_port_status = 0; + $start_break = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + in_port_status => $in_port_status, + start_break => $start_break, + }}); + + ### NOTE: So far as I can tell, there is only ever two SAS ports on hard + ### drives. The way the system parses them handles N-number of ports, + ### though. For now, we'll squeeze these into the top layer variables + ### to save having to have another table to process. + my $sas_port_0_port_status = $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{0}{port_status}; + my $sas_port_0_link_speed = $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{0}{link_speed}; + my $sas_port_0_sas_address = $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{0}{sas_address}; + my $sas_port_1_port_status = $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{1}{port_status}; + my $sas_port_1_link_speed = $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{1}{link_speed}; + my $sas_port_1_sas_address = $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{1}{sas_address}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + sas_port_0_port_status => $sas_port_0_port_status, + sas_port_0_link_speed => $sas_port_0_link_speed, + sas_port_0_sas_address => $sas_port_0_sas_address, + sas_port_1_port_status => $sas_port_1_port_status, + sas_port_1_link_speed => $sas_port_1_link_speed, + sas_port_1_sas_address => $sas_port_1_sas_address, + }}); + + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sas_port_0_port_status} = $sas_port_0_port_status; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sas_port_0_link_speed} = $sas_port_0_link_speed; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sas_port_0_sas_address} = $sas_port_0_sas_address; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sas_port_1_port_status} = $sas_port_1_port_status; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sas_port_1_link_speed} = $sas_port_1_link_speed; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sas_port_1_sas_address} = $sas_port_1_sas_address; + next; + } + } + + # We stop processing a given drive when we see 'Inquiry Data'. + if ($line =~ /^Inquiry Data =/) + { + # Process and variables that need their size calculated from sectors to bytes. + # These are always variables. + foreach my $variable (sort {$a cmp $b} @{$sector_variables}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + next if not $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}; + + my $value = $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + if ($value =~ /^(\d+) bytes, (\d+) sectors/) + { + my $size = $1; + my $sectors = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + size => $size, + sectors => $sectors, + sector_size => $sector_size, + }}); + if ($sector_size) + { + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = ($sectors * $sector_size); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + else + { + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = $size; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + } + } + + # Record the drive as being on this controller. + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{on_controller} = $serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::on_controller" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{on_controller}, + }}); + + $virtual_drive = $serial_number."-vd9999"; + $drive_group = 9999; + $enclosure_id = ""; + $slot_number = ""; + $in_drive_header = 0; + $in_port_status = 0; + $start_break = 0; + $sector_size = 0; + $sector_variables = []; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { virtual_drive => $virtual_drive }}); + } + next if $enclosure_id eq ""; + + # If I am in the port status, parse the port info. + if (($in_port_status) && ($line =~ /^(\d+)\s+(.*?)\s+(\d.*?)Gb\/s\s+(0x.*)$/)) + { + my $sas_port = $1; + my $port_status = $2; + my $link_speed = $3." #!variable!scan_storcli_unit_0013!#"; + my $sas_address = $4; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + sas_port => $sas_port, + port_status => $port_status, + link_speed => $link_speed, + sas_address => $sas_address, + }}); + + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{$sas_port}{port_status} = $port_status; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{$sas_port}{link_speed} = $link_speed; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{$sas_port}{sas_address} = $sas_address; + # These are so flipping long that we print them as three separate log entries so that + # they're easier to read in the logs. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::sas_port::${sas_port}::port_status" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{$sas_port}{port_status}, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::sas_port::${sas_port}::link_speed" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{$sas_port}{link_speed}, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::sas_port::${sas_port}::sas_address" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{sas_port}{$sas_port}{sas_address}, + }}); + next; + } + + ### If I have a 'variable = value' pair split and parse. + # The 'Drive position' isn't set for drives not in an array/drive group. + if ($line =~ /^Drive position = DriveGroup:(\d+), Span:(\d+), Row:(\d+)/i) + { + my $this_drive_group = $1; + my $span = $2; + my $row = $3; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + this_drive_group => $this_drive_group, + span => $span, + row => $row, + }}); + + # I don't pick up this until well into the scan, but the drive group should match + # what we found earlier. Just to be safe though, if not, throw a warning. + if ($this_drive_group ne $drive_group) + { + # Report this error + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1 , key => "scan_storcli_warning_0001", variables => { + adapter => $adapter, + serial_number => $serial_number, + virtual_drive => $virtual_drive, + enclosure_id => $enclosure_id, + slot_number => $slot_number, + span => $span, + row => $row, + old_drive_group => $drive_group, + new_drive_group => $this_drive_group, + shell_call => $shell_call, + }}); + $drive_group = $this_drive_group; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drive_group => $drive_group }}); + } + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{span} = $span; + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{row} = $row; + + # These are so flipping long that we print them as three separate log entries so that + # they're easier to read in the logs. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::span" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{span}, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::row" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{row}, + }}); + next; + } + + # Split and process all 'variable = value' lines we've not already handled. + if ($line =~ /^(.*?)\s+=\s+(.*)$/) + { + my $variable = $1; + my $value = $2; + my $type = "variable"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + + # Process some variable names. + if ($variable =~ /^SN$/i) + { + $variable = "Serial Number"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + if ($variable =~ /^WWN$/i) + { + $variable = "World Wide Name"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + if ($variable =~ /^PI /i) + { + $variable =~ s/^PI /Protection Information /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + if ($variable =~ / Id$/i) + { + $variable =~ s/ Id$/ Identification/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + if ($variable =~ /^Sector Size$/i) + { + # Convert to bytes and record. + $value = $anvil->Convert->human_readable_to_bytes({base2 => 1, size => $value})." #!string!scan_storcli_unit_0001!#"; + $sector_size = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + value => $value, + sector_size => $sector_size, + }}); + } + if ($variable =~ / EKM/i) + { + # De-TLA it + $variable =~ s/ EKM/ External Key Management/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + if ($variable =~ /S\.M\.A\.R\.T\./i) + { + $variable =~ s/S\.M\.A\.R\.T\./SMART/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + if ($variable =~ /S\.M\.A\.R\.T/i) + { + $variable =~ s/S\.M\.A\.R\.T/SMART/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + + # Process some values. + if ($value =~ /^(\d.*?B) \[(0x.*?) Sectors\]/) + { + my $size = $1; + my $hex_sectors = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + size => $size, + hex_sectors => $hex_sectors, + }}); + + my $sectors = Math::BigInt->new($hex_sectors); + my $bytes = $anvil->Convert->human_readable_to_bytes({base2 => 1, size => $size}); + $value = $bytes." #!variable!scan_storcli_unit_0001!#, ".$sectors." #!variable!scan_storcli_unit_0012!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + size => $size, + 'bytes' => $bytes, + hex_sectors => $hex_sectors, + value => $value, + variable => $variable, + }}); + + # Mark this for sector size calculation later. + push @{$sector_variables}, $variable; + } + if (($value =~ /^(\d+\s*[A-Za-z]+B)$/i) or ($value =~ /^(\d+\.\d+\s*[A-Za-z]+B)$/i)) + { + my $size = $1; + $value = $anvil->Convert->human_readable_to_bytes({base2 => 1, size => $size})." #!string!scan_storcli_unit_0001!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + size => $size, + value => $value, + }}); + } + if ($value =~ /^(\d.*?)C \(\d.*? F\)/i) + { + $value = $1; + $type = "temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + value => $value, + type => $type, + }}); + } + if (($value =~ /^(\d+)C$/i) or ($value =~ /^(\d+\.\d+)C$/i)) + { + $value = $1; + $type = "temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + value => $value, + type => $type, + }}); + } + if (($value =~ /^(\d+)F$/i) or ($value =~ /^(\d+\.\d+)F$/i)) + { + $value = $anvil->Convert->fahrenheit_to_celsius({temperature => $1}); + $type = "temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + value => $value, + type => $type, + }}); + } + if ($value =~ /^(\d.*?)Gb\/s$/) + { + $value = $1." #!variable!scan_storcli_unit_0013!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + if ($value eq "NA") + { + $value = "N/A"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + + # Process/standardize the variable. + $variable = process_variable_name($anvil, $variable); + + # Record + $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{$type}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${virtual_drive}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::${type}::$variable" => $anvil->data->{virtual_drive}{$virtual_drive}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{$type}{$variable}, + }}); + } + } + + return(0); +} + +# This looks for virtual drives on the controller. +sub get_virtual_drive_data +{ + my ($anvil, $adapter, $serial_number) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + adapter => $adapter, + serial_number => $serial_number, + }}); + + my $virtual_drive = ""; + my $id_string = ""; + my $in_overview = 0; + my $in_pd_list = 0; + my $in_vd_data = 0; + my $start_break = 0; + my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{virtual_drive_data}}); + $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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + if ($line =~ /\/c$adapter\/v(\d+):/) + { + $virtual_drive = $1; + $id_string = $serial_number."-vd".$virtual_drive; + $anvil->data->{virtual_drive}{$id_string}{variable}{on_controller} = $serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + virtual_drive => $virtual_drive, + id_string => $id_string, + "virtual_drive::${id_string}::variable::on_controller" => $anvil->data->{virtual_drive}{$id_string}{variable}{on_controller}, + }}); + + # We set the VD '9999' to the same SN so that we can find unallocated disks later. + my $unallocated_id_string = $serial_number."-vd9999"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { unallocated_id_string => $unallocated_id_string }}); + if (not $anvil->data->{virtual_drive}{$unallocated_id_string}{variable}{on_controller}) + { + $anvil->data->{virtual_drive}{$unallocated_id_string}{variable}{on_controller} = $serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${unallocated_id_string}::variable::on_controller" => $anvil->data->{virtual_drive}{$unallocated_id_string}{variable}{on_controller}, + }}); + } + } + if ($line =~ /PDs for VD (\d+) :/) + { + $virtual_drive = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { virtual_drive => $virtual_drive }}); + } + if ($line =~ /VD(\d+) Properties/) + { + $virtual_drive = $1; + $in_vd_data = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + virtual_drive => $virtual_drive, + in_vd_data => $in_vd_data, + }}); + } + + next if $virtual_drive eq ""; + + # See if I am entering or exiting the overview chunk. + if ($line =~ /^DG\/VD/) + { + $in_overview = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_overview => $in_overview }}); + next; + } + if (($line =~ /^--------/) && ($in_overview)) + { + if (not $start_break) + { + # Split point set, must be the start break + $start_break = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { start_break => $start_break }}); + next; + } + else + { + # Split point and start break set, must be end break. + $in_overview = 0; + $start_break = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + in_overview => $in_overview, + start_break => $start_break, + }}); + next; + } + } + if ($in_overview) + { + process_vg_overview_data($anvil, $line, $serial_number); + } + + # See if I am entering or exiting the physical drive chunk. + if ($line =~ /^EID:Slt/) + { + $in_pd_list = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_pd_list => $in_pd_list }}); + next; + } + if (($line =~ /^--------/) && ($in_pd_list)) + { + if (not $start_break) + { + # Split point set, must be the start break + $start_break = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { start_break => $start_break }}); + next; + } + else + { + # Split point and start break set, must be end break. + $in_pd_list = 0; + $start_break = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + in_pd_list => $in_pd_list, + start_break => $start_break, + }}); + next; + } + } + if ($in_pd_list) + { + process_vg_pd_list_data($anvil, $line, $virtual_drive, $serial_number, $id_string); + } + + if ($in_vd_data) + { + if ($line =~ /^(.*?) = (.*)$/) + { + my $variable = $1; + my $value = $2; + my $type = "variable"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + + # Convert some formatting. + if (($value =~ /^(\d+\s*[A-Za-z]+B)$/i) or ($value =~ /^(\d+\.\d+\s*[A-Za-z]+B)$/i)) + { + # Convert to bytes + $value = $anvil->Convert->human_readable_to_bytes({base2 => 1, size => $value})." #!string!scan_storcli_unit_0001!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + elsif ($value =~ /^(\d\d)-(\d\d)-(\d\d\d\d)$/) + { + # Convert dd-mm-yyyy to yyyy/mm/dd + $value = $3."/".$2."/".$1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + elsif ($value =~ /^(\d\d):(\d\d):(\d\d) (\wM)$/) + { + # Convert AM/PM -> 24h + my $hour = $1; + my $minute = $2; + my $second = $3; + my $suffix = $4; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + hour => $hour, + minute => $minute, + second => $second, + suffix => $suffix, + }}); + if ($suffix eq "PM") + { + $hour += 12; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { hour => $hour }}); + } + $value = "$hour:$minute:$second"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + + # Record + $variable = process_variable_name($anvil, $variable); + $anvil->data->{virtual_drive}{$id_string}{$type}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::${type}::$variable" => $anvil->data->{virtual_drive}{$id_string}{$type}{$variable}, + }}); + } + } + } + + return(0); +} + +# This parses a virtual drive's physical disk overview line +sub process_vg_pd_list_data +{ + my ($anvil, $line, $virtual_drive, $serial_number, $id_string) = @_; + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "line" => $line, + }}); + ### Sector size is either '512B' or '4 KB' + # EID:Slt DID State DG Size Intf Med SED PI SeSz Model Sp + # 252:0 9 Onln 0 136.218 GB SAS HDD N N 512B MK1401GRRB U + if ($line =~ /^(\d+):(\d+)\s+(\d+)\s+(.*?)\s+(.*?)\s+(.*?B)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?)\s+(.*?B)\s+(.*?)\s+(.*)$/) + { + my $enclosure_id = $1; + my $slot_number = $2; + my $device_id = $3; + my $state = $4; + my $drive_group = $5; + my $drive_size = $6; + my $interface = $7; + my $drive_media = $8; + my $self_encrypting_drive = $9; + my $protection_info = $10; + my $sector_size = $11; + my $drive_model = $12; + my $spun_up = $13; + $drive_group = 9999 if $drive_group eq "-"; + $protection_info = $protection_info =~ /n/i ? "No" : "Yes"; + $self_encrypting_drive = $self_encrypting_drive =~ /n/i ? "No" : "Yes"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "enclosure_id" => $enclosure_id, + "slot_number" => $slot_number, + "device_id" => $device_id, + "state" => $state, + "drive_group" => $drive_group, + "drive_size" => $drive_size, + "interface" => $interface, + "drive_media" => $drive_media, + "self_encrypting_drive" => $self_encrypting_drive, + "protection_info" => $protection_info, + "sector_size" => $sector_size, + "drive_model" => $drive_model, + "spun_up" => $spun_up, + }}); + + # Convert the sector and drive sizes into bytes. The controller uses 'xB' but uses base2 values. + $sector_size = $anvil->Convert->human_readable_to_bytes({base2 => 1, size => $sector_size})." #!string!scan_storcli_unit_0001!#"; + $drive_size = $anvil->Convert->human_readable_to_bytes({base2 => 1, size => $drive_size})." #!string!scan_storcli_unit_0001!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sector_size" => $sector_size, + "drive_size" => $drive_size, + }}); + + ### Long hashes are long... x_x + # Store the data (we'll convert it in a minute. + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{device_id} = $device_id; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{'state'} = $state; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_size} = $drive_size; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{interface} = $interface; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_media} = $drive_media; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{self_encrypting_drive} = $self_encrypting_drive; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{protection_info} = $protection_info; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sector_size} = $sector_size; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_model} = $drive_model; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{spun_up} = $spun_up; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::device_id" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{device_id}, + "virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::state" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{'state'}, + "virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::drive_size" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_size}, + "virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::interface" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{interface}, + "virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::drive_media" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_media}, + "virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::self_encrypting_drive" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{self_encrypting_drive}, + "virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::protection_info" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{protection_info}, + "virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::sector_size" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{sector_size}, + "virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::drive_model" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{drive_model}, + "virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::spun_up" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{spun_up}, + }}); + + ### WARNING: The strings we set here will be parsed later, so don't change them without also + ### changing where they're checked for elsewhere in this agent. + ### NOTE: We don't use a function for this because the glossary for the block of data is + ### specific for the table above (it would appear). + # Translate the weird short form to useable strings + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}}) + { + my $value = $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ">> virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + + if ($value =~ /^DHS$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Dedicated Hot Spare"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^UGood$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Unconfigured Good"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^GHS$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Global Hotspare"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^UBad$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Unconfigured Bad"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^Onln$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Online"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^Offln$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Offline"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^U$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Spun Up"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^D$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Spun Down"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^T$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Transition"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^F$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Foreign"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^UGUnsp$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Unsupported"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^UGShld$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Unconfigured shielded"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^HSPShld$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Hotspare shielded"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^CFShld$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Configured shielded"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^Cpybck$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Copyback"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + if ($value =~ /^CBShld$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable} = "Copyback Shielded"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::enclosure_id::${enclosure_id}::slot_number::${slot_number}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{enclosure_id}{$enclosure_id}{slot_number}{$slot_number}{variable}{$variable}, + }}); + } + } + } + else + { + # Unparsed line + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "? line" => $line, + }}); + } + + return(0); +} + +# This parses a virtual drive overview line +sub process_vg_overview_data +{ + my ($anvil, $line, $serial_number) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + line => $line, + serial_number => $serial_number, + }}); + + my $drive_group = ""; + my $virtual_drive = ""; + my $raid_type = ""; + my $array_state = ""; + my $access = ""; + my $consistent = ""; + my $cache = ""; + my $cachecade = ""; + my $scheduled_consistency_check = ""; + my $array_size = ""; + my $name = ""; + my $id_string = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "line" => $line, + }}); + # Get the line when there is no name + # 0 / 0 RAID5 Optl RW Yes NRWBD - OFF 953.531 GB + if ($line =~ /^(\d+)\/(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+ \wB)$/i) + { + $drive_group = $1; + $virtual_drive = $2; + $raid_type = $3; + $array_state = $4; + $access = $5; + $consistent = $6; + $cache = $7; + $cachecade = $8; + $scheduled_consistency_check = $9; + $array_size = $10; + $id_string = $serial_number."-vd".$virtual_drive; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "drive_group" => $drive_group, + "virtual_drive" => $virtual_drive, + "raid_type" => $raid_type, + "array_state" => $array_state, + "access" => $access, + "consistent" => $consistent, + "cache" => $cache, + "cachecade" => $cachecade, + "scheduled_consistency_check" => $scheduled_consistency_check, + "array_size" => $array_size, + "id_string" => $id_string, + }}); + } + # Get the line when there is a name + # 0 / 0 RAID5 Optl RW Yes RWBD - OFF 3.271 TB VD0 + # 1 / 1 RAID5 Optl RW Yes RWBD - OFF 744.187 GB VD1 + # 2 / 2 RAID0 Optl RW Yes RWBD - OFF 1.636 TB VD2 + elsif ($line =~ /^(\d+)\/(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+ \wB)\s+(.*)$/i) + { + $drive_group = $1; + $virtual_drive = $2; + $raid_type = $3; + $array_state = $4; + $access = $5; + $consistent = $6; + $cache = $7; + $cachecade = $8; + $scheduled_consistency_check = $9; + $array_size = $10; + $name = $11; + $id_string = $serial_number."-vd".$virtual_drive; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "drive_group" => $drive_group, + "virtual_drive" => $virtual_drive, + "raid_type" => $raid_type, + "array_state" => $array_state, + "access" => $access, + "consistent" => $consistent, + "cache" => $cache, + "cachecade" => $cachecade, + "scheduled_consistency_check" => $scheduled_consistency_check, + "array_size" => $array_size, + "name" => $name, + "id_string" => $id_string, + }}); + } + else + { + # Unmatched line... + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "? line" => $line, + }}); + next; + } + + # Convert the array size into bytes. The controller uses 'xB' but uses base2 values. + $array_size = $anvil->Convert->human_readable_to_bytes({base2 => 1, size => $array_size})." #!string!scan_storcli_unit_0001!#"; + + # Store the data. + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{on_controller} = $serial_number; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{raid_type} = $raid_type; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{array_state} = $array_state; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{access} = $access; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{consistent} = $consistent; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{cache} = $cache; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{cachecade} = $cachecade; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{scheduled_consistency_check} = $scheduled_consistency_check; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{array_size} = $array_size; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{name} = $name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::on_controller" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{on_controller}, + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::raid_type" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{raid_type}, + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::array_state" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{array_state}, + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::access" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{access}, + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::consistent" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{consistent}, + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::cache" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{cache}, + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::cachecade" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{cachecade}, + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::scheduled_consistency_check" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{scheduled_consistency_check}, + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::array_size" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{array_size}, + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::name" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{name}, + }}); + + ### WARNING: The strings we set here will be parsed later, so don't change them without also changing + ### where they're checked for elsewhere in this agent. + ### NOTE: We don't use a function for this because the glossary for the block of data is specific for + ### the table above (it would appear). + # Translate the weird short form to useable strings + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ">> virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + + if ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} eq "-") + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "No"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^Cac$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "CacheCade"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^Rec$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Recovery"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^OfLn$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "OffLine"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^Pdgd$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Partially Degraded"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^dgrd$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Degraded"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^Optl$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Optimal"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^RO$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Read Only"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^RW$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Read Write"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^HD$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Hidden"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^TRANS$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Transport Ready"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^B$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Blocked"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^Consist$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Consistent"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + elsif ($anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} =~ /^sCC$/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable} = "Scheduled Check Consistency"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "<< virtual_drive::${id_string}::drive_group::${drive_group}::variable::$variable" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}, + }}); + } + + # Because they hate programmers, the cache is a combination of a few of the + # above strings. + if ($variable eq "cache") + { + my $cache = $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{$variable}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cache" => $cache, + }}); + + # Prep some blanks + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{read_cache} = ""; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{write_cache} = ""; + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{disk_cache} = ""; + + # Read cache + if ($cache =~ /NR/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{read_cache} = "No Read-Ahead"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::read_cache" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{read_cache}, + }}); + } + elsif ($cache =~ /R/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{read_cache} = "Always Read-Ahead"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::read_cache" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{read_cache}, + }}); + } + + # Write cache + if ($cache =~ /AWB/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{write_cache} = "Always Write-Back"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::write_cache" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{write_cache}, + }}); + } + elsif ($cache =~ /WB/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{write_cache} = "Write-Back"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::write_cache" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{write_cache}, + }}); + } + elsif ($cache =~ /WT/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{write_cache} = "Write-Through"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::write_cache" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{write_cache}, + }}); + } + + # Disk cache + if ($cache =~ /C/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{disk_cache} = "Cached IO"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::disk_cache" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{disk_cache}, + }}); + } + elsif ($cache =~ /D/i) + { + $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{disk_cache} = "Direct IO"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "virtual_drive::${id_string}::drive_group::${drive_group}::variable::disk_cache" => $anvil->data->{virtual_drive}{$id_string}{drive_group}{$drive_group}{variable}{disk_cache}, + }}); + } + } + } + + return(0); +} + +# This looks for a BBU and, if it finds one, parses the output for it. +sub get_bbu_data +{ + my ($anvil, $adapter, $serial_number) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + adapter => $adapter, + serial_number => $serial_number, + }}); + + my $bbu_serial_number = ""; + my $bbu_data = []; + my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{bbu_data}}); + $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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + last if $line =~ /$adapter Failed /i; + + if ($line =~ /^Serial Number\s+(\S.*)?/i) + { + $bbu_serial_number = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bbu_serial_number => $bbu_serial_number }}); + next; + } + push @{$bbu_data}, $line; + } + + # If I didn't find a serial number, then I probably don't have an FBU. + return(0) if not $bbu_serial_number; + + # Record the controller the bbu is on. + $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{host_controller_serial_number} = $serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "bbu::serial_number::${bbu_serial_number}::host_controller_serial_number" => $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{host_controller_serial_number}, + }}); + + # Still alive? Good, time to parse the most annoying output ever... >_< + my $split_point = 0; + my $start_break = 0; + my $end_break = 0; + foreach my $line (@{$bbu_data}) + { + next if not $line; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /Property(\s+)Value/) + { + $split_point = length($1) + 8; + $start_break = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { split_point => $split_point }}); + next; + } + + # See if I am entering or exiting a data chunk. + if (($line =~ /^--------/) && ($split_point)) + { + if (not $start_break) + { + # Split point set, must be the start break + $start_break = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { start_break => $start_break }}); + next; + } + else + { + # Split point and start break set, must be end break. + $split_point = 0; + $start_break = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + split_point => $split_point, + start_break => $start_break, + }}); + next; + } + } + + # If I have a split point, break the string. + if ($split_point) + { + # Elegant? I think not! + my $variable = ""; + my $value = ""; + my $type = "variable"; + if ($split_point >= length($line)) + { + # Variable with no value + $variable = $line; + $variable =~ s/\s+$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + else + { + ($variable, $value) = ($line =~ /^(.{$split_point})(.*)$/); + $variable =~ s/\s+$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + + # Because LSI is either evil or amazingly incompetent, we have the variable + # "Absolute State of charge" listed twice, but once with 'State' and the + # other with 'state' (capital versus small 'S'). We fix it because it is the + # same data and we don't want two records, so the second copy will now just + # overwrite the first one. + if ($variable eq "Absolute State of charge") + { + $variable = "Absolute state of charge"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + + # They use 'Temperature' twice; once for the temperature and once to show if + # it is OK or not. We'll avoid one clobbering the other by renaming the + # status one. + if (($variable eq "Temperature") && ($value !~ /^\d/)) + { + $variable = "Temperature Status"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + if (($variable eq "Temperature") && ($value =~ /^\d/)) + { + $variable = "BBU Temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + + # *sigh* - Typo on their part, but also a re-use of the variable name + # "Remaining Time Alarm". The Status one we will rename the variable and the + # later we'll fix the type. + if ((lc($variable) eq "remaining time alarm") && ($value !~ /\d/)) + { + # No digit in the value, so this is the status. + $variable = "Remaining Time Alarm Status"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + if ($variable =~ /remining /) + { + $variable =~ s/emining /emaining /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + + if ($variable =~ /\(initial setting\)/i) + { + $variable =~ s/\(initial setting\)//i; + $variable = "Initial ".$variable." Setting"; + $variable =~ s/\s+//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + } + + # Is this a temperature or something else we want to pre-process? + if ($value =~ /^(\d+) C$/i) + { + # Yup + $value = $1; + $type = "temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($value =~ /^(\d+) F$/i) + { + # Yup, but translate + $value = $anvil->Convert->fahrenheit_to_celsius({temperature => $1}); + $type = "temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($value =~ /\d+d \((\d+) seconds\)$/i) + { + # This is a static time span (like the time between learn cycles. + $value = $1; + $value .= " #!variable!scan_storcli_unit_0006!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($value =~ /^(\d\d\d\d)\/(\d\d)\/(\d\d)\s+(\d\d:\d\d:\d\d)\s+\(\d+ seconds\)$/i) + { + ### NOTE: The 'X seconds' seems to not change and be a useless number... + # This is a specific time in the future, properly formatted + $value = $1."/".$2."/".$3.", ".$4; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($value =~ /^(\d\d)\/(\d\d)\/(\d\d\d\d)$/i) + { + # 'Murica! mm/dd/yyyy -> yyyy/mm/dd + $value = $3."/".$2."/".$1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($value =~ /^(\d+) hour\(s\)$/i) + { + # 'Murica! mm/dd/yyyy -> yyyy/mm/dd + $value = $1 * 3600; + $value .= " #!variable!scan_storcli_unit_0006!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + + # Record + $variable = process_variable_name($anvil, $variable); + + # 'Auto-Learn' and 'Auto_Learn' are both used because screw consistency, right? + $variable =~ s/auto-learn/auto_learn/; + + $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{$type}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "bbu:serial_number::${bbu_serial_number}::${type}::$variable" => $anvil->data->{bbu}{serial_number}{$bbu_serial_number}{$type}{$variable}, + }}); + } + } + + return(0); +} + +# This looks for a cachevault (flash-backup unit) and, if one is found, parses the output. +sub get_cachevault_data +{ + my ($anvil, $adapter, $serial_number) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + adapter => $adapter, + serial_number => $serial_number, + }}); + + my $cachevault_serial_number = ""; + my $cachevault_data = []; + my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{cachevault_data}}); + $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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + last if $line =~ /Cachevault doesn't exist/i; + + if ($line =~ /^Serial Number\s+(\S.*)?/i) + { + $cachevault_serial_number = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cachevault_serial_number => $cachevault_serial_number }}); + next; + } + push @{$cachevault_data}, $line; + } + + # If I didn't find a serial number, then I probably don't have an FBU. + return(0) if not $cachevault_serial_number; + + # Record the controller the cachevault is on. + $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{host_controller_serial_number} = $serial_number; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cachevault::serial_number::${cachevault_serial_number}::host_controller_serial_number" => $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{host_controller_serial_number}, + }}); + + # Still alive? Good, time to parse the most annoying output ever... >_< + my $split_point = 0; + my $start_break = 0; + my $end_break = 0; + foreach my $line (@{$cachevault_data}) + { + next if not $line; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /Property(\s+)Value/) + { + $split_point = length($1) + 8; + $start_break = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { split_point => $split_point }}); + next; + } + + # See if I am entering or exiting a data chunk. + if (($line =~ /^--------/) && ($split_point)) + { + if (not $start_break) + { + # Split point set, must be the start break + $start_break = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { start_break => $start_break }}); + next; + } + else + { + # Split point and start break set, must be end break. + $split_point = 0; + $start_break = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + split_point => $split_point, + start_break => $start_break, + }}); + next; + } + } + + # If I have a split point, break the string. + if ($split_point) + { + my $variable = ""; + my $value = ""; + my $type = "variable"; + if ($split_point >= length($line)) + { + # Variable with no value + $variable = $line; + $variable =~ s/\s+$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + else + { + ($variable, $value) = ($line =~ /^(.{$split_point})(.*)$/); + $variable =~ s/\s+$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + + # With BBUs, they use 'Temperature' twice; once for status and once for the current + # temperature. They don't currently do this with Cachevaults, but in case they do + # later, we'll rename the temperature variable. + if (($variable eq "Temperature") && ($value =~ /^\d/)) + { + $variable = "Cachevault Temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + } + + # Is this a temperature or something else we want to pre-process? + if ($value =~ /^(\d+) C$/i) + { + # Yup + $value = $1; + $type = "temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($value =~ /^(\d+) F$/i) + { + # Yup, but translate + $value = $anvil->Convert->fahrenheit_to_celsius({temperature => $1}); + $type = "temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($value =~ /\d+d \((\d+) seconds\)$/i) + { + # This is a static time span (like the time between learn cycles. + $value = $1; + $value .= " #!variable!scan_storcli_unit_0006!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($value =~ /^(\d\d\d\d)\/(\d\d)\/(\d\d)\s+(\d\d:\d\d:\d\d)\s+\(\d+ seconds\)$/i) + { + ### NOTE: The 'X seconds' seems to not change and be a useless number... + # This is a specific time in the future, properly formatted + # yyyy/mm/dd -> + $value = $1."/".$2."/".$3.", ".$4; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($value =~ /^(\d\d)\/(\d\d)\/(\d\d\d\d)$/i) + { + # 'Murica! mm/dd/yyyy -> yyyy/mm/dd + $value = $3."/".$2."/".$1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($value =~ /^(\d+) hour\(s\)$/i) + { + # 'Murica! mm/dd/yyyy -> yyyy/mm/dd + $value = $1 * 3600; + $value .= " #!variable!scan_storcli_unit_0006!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + + # Record + $variable = process_variable_name($anvil, $variable); + + # 'Auto-Learn' and 'Auto_Learn' are both used because screw consistency, right? + $variable =~ s/auto-learn/auto_learn/; + + $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{$type}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cachevault:serial_number::${cachevault_serial_number}::${type}::$variable" => $anvil->data->{cachevault}{serial_number}{$cachevault_serial_number}{$type}{$variable}, + }}); + } + } + + return(0); +} + +# This gets the basic information about the controller. +sub get_controller_info +{ + my ($anvil, $adapter) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { adapter => $adapter }}); + + my $in_raid_level_supported = 0; + my $multiline_value = ""; + my $in_header = 1; + my $in_basics = 0; + my $in_supported_ops = 0; + my $in_supported_pd_ops = 0; + my $in_supported_vd_ops = 0; + my $in_hardware_config = 0; + my $in_capabilities = 0; + my $in_policies = 0; + my $in_defaults = 0; + my $serial_number = ""; + my $controller_data = []; + my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{controller_info}}); + $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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + next if not $line; + last if $line =~ /^TOPOLOGY:$/i; + + # The time changes constantly, so ignore it. + if ($line =~ /Date\/Time/i) + { + next; + } + + # RAID Level Supported can be multi-line because $reasons. + if ($line =~ /RAID Level Supported = (.*)$/) + { + $multiline_value = $1; + $in_raid_level_supported = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + multiline_value => $multiline_value, + in_raid_level_supported => $in_raid_level_supported, + }}); + } + if ($in_raid_level_supported) + { + if ($line =~ / = /) + { + # Found the next line, close up RAID Level Supported. + push @{$controller_data}, "RAID Level Supported = ".$multiline_value; + $multiline_value = ""; + $in_raid_level_supported = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + multiline_value => $multiline_value, + in_raid_level_supported => $in_raid_level_supported, + }}); + } + else + { + $multiline_value .= " $line"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { multiline_value => $multiline_value }}); + next; + } + } + + if ($line =~ /^Serial Number = (.*)?/i) + { + $serial_number = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { serial_number => $serial_number }}); + next; + } + + ### LSI reuses the save variable names in different sections. This tries to catch and rename + ### them + # Ignore stuff in the header + if ($line =~ /^Basics/) + { + $in_header = 0; + $in_basics = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + in_header => $in_header, + in_basics => $in_basics, + }}); + } + if ($in_basics) + { + if ($line =~ /^Version/) + { + $in_basics = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_basics => $in_basics }}); + } + } + elsif ($line =~ /^Controller\s+=/) + { + # This is the header data, which we don't care about. + next; + } + if ($in_header) + { + next; + } + + # Mangle supported adapter operation variables. + if ($line =~ /^Supported Adapter Operations/) + { + $in_supported_ops = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_supported_ops => $in_supported_ops }}); + } + if ($in_supported_ops) + { + if ($line =~ /^Supported PD Operations/) + { + $in_supported_ops = 0; + $in_supported_pd_ops = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + in_supported_ops => $in_supported_ops, + in_supported_pd_ops => $in_supported_pd_ops, + }}); + } + + if ($line =~ /^BBU /) + { + $line =~ s/^BBU /BBU Supported /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Rebuild Rate /) + { + $line =~ s/^Rebuild Rate /Configurable Rebuild Rate /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^CC Rate /) + { + $line =~ s/^CC Rate /Configurable Consistency Check Rate /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^BGI Rate /) + { + $line =~ s/^BGI Rate /Configurable background Initialization Rate /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Reconstruct Rate /) + { + $line =~ s/^Reconstruct Rate /Configurable Reconstruct Rate /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Patrol Read Rate /) + { + $line =~ s/^Patrol Read Rate /Configurable Patrol Read Rate /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Alarm Control /) + { + $line =~ s/^Alarm Control /Configurable Alarm Control /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Spanning /) + { + $line =~ s/^Spanning /Spanning Supported /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /Hot Spare /) + { + $line =~ s/Hot Spare /Hot Spare Supported /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Foreign Config Import /) + { + $line =~ s/^Foreign Config Import /Foreign Config Import Supported /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Self Diagnostic /) + { + $line =~ s/^Self Diagnostic /Self Diagnostic Supported /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Abort CC on Error /) + { + $line =~ s/^Abort CC on Error /Configurable Abort CC on Error /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Block SSD Write Disk Cache Change /) + { + $line =~ s/^Block SSD Write Disk Cache Change /Configurable Block SSD Write Disk Cache Change /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + } + + # Mangle supported adapter physical disk operation variables. + if ($in_supported_pd_ops) + { + if ($line =~ /^Supported VD Operations/) + { + $in_supported_pd_ops = 0; + $in_supported_vd_ops = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + in_supported_pd_ops => $in_supported_pd_ops, + in_supported_vd_ops => $in_supported_vd_ops, + }}); + } + if ($line =~ /^Deny Locate /) + { + $line =~ s/^Deny Locate /Deny Physical Disk Locate /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Read Policy /) + { + $line =~ s/^Read Policy /Physical Disk Read Policy /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Write Policy /) + { + $line =~ s/^Write Policy /Physical Disk Write Policy /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + } + + # Mangle supported adapter virtual drive operation variables. + if ($in_supported_vd_ops) + { + if ($line =~ /^Advanced Software Option/) + { + $in_supported_vd_ops = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_supported_vd_ops => $in_supported_vd_ops }}); + } + if ($line =~ /^Deny Locate /) + { + $line =~ s/^Deny Locate /Deny Virtual Disk Locate /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Read Policy /) + { + $line =~ s/^Read Policy /Virtual Disk Read Policy /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Write Policy /) + { + $line =~ s/^Write Policy /Virtual Disk Write Policy /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + } + + # Mangle hardware config variables. + if ($line =~ /^HwCfg/) + { + $in_hardware_config = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "in_hardware_config" => $in_hardware_config }}); + } + if ($in_hardware_config) + { + if ($line =~ /^Policies/) + { + $in_hardware_config = 0; + $in_policies = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + in_hardware_config => $in_hardware_config, + in_policies => $in_policies, + }}); + } + if ($line =~ /^BBU /) + { + $line =~ s/^BBU /BBU Connected /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + } + + # Mangle policy variables. + if ($in_policies) + { + if ($line =~ /^Boot/) + { + $in_policies = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_policies => $in_policies }}); + } + if ($line =~ /^Disable Online Controller Reset /) + { + $line =~ s/^Disable Online Controller Reset /Disable Online Controller Reset Policy /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Expose Enclosure Devices /) + { + $line =~ s/^Expose Enclosure Devices /Expose Enclosure Devices Policy /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Maintain PD Fail History /) + { + $line =~ s/^Maintain PD Fail History /Maintain PD Fail History Policy /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + } + + # Mangle defaults variables + if ($line =~ /^Defaults/) + { + $in_defaults = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_defaults => $in_defaults }}); + } + if ($in_defaults) + { + if ($line =~ /^Capabilities/) + { + $in_defaults = 0; + $in_capabilities = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + in_defaults => $in_defaults, + in_capabilities => $in_capabilities, + }}); + } + if ($line =~ /^Disable Online Controller Reset /) + { + $line =~ s/^Disable Online Controller Reset /Disable Online Controller Reset Default /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Expose Enclosure Devices /) + { + $line =~ s/^Expose Enclosure Devices /Expose Enclosure Devices Default /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + if ($line =~ /^Maintain PD Fail History /) + { + $line =~ s/^Maintain PD Fail History /Maintain PD Fail History Default /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + + # Many of the variables in the 'Defaults' section are also used for their current + # values. So to help differentiate them, we're going to prefix the variables with + # 'Default '. + if (($in_defaults) && ($line =~ / = /)) + { + $line = "Default ".$line if $line !~ /^Default /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + } + } + + # Mangle capability variables. + if ($in_capabilities) + { + if ($line =~ /^Scheduled Tasks/) + { + $in_capabilities = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_capabilities => $in_capabilities }}); + } + if ($line =~ /^Boot Volume Supported /) + { + $line =~ s/^Boot Volume Supported /Boot Volume Capable /; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + } + } + + # T10-PI (T10 working group, Protection Information) has three levels (Taken from the Seagate + # PDF listed below): + # Type 0 - Describes a drive that is not formatted with PI information bytes. This allows + # for legacy support in non-PI systems. + # Type 1 - Provides support of PI protection using 10- and 16-byte commands. The RDPROTECT + # and WRTPROTECT bits allow for checking control through the CDB. Eight bytes of + # Protection Information are transmitted at sector boundaries across the interface + # if RDPROTECT and WRTPROTECT bits are non-zero values. Type I does not allow the + # use of 32-byte commands. + # Type 2 - Provides checking control and additional expected fields within the 32-byte CDBs. + # Eight bytes of Protection Information are transmitted at sector boundaries across + # the interface if RDPROTECT and WRTPROTECT bits are non-zero values. Type II does + # allow the use of 10- and 16-byte commands with zero values in the RDPROTECT and + # WRTPROTECT fields. The drive will generate a dummy (for example, 0xFFFF) eight + # bytes of Protection Information in the media, but these eight bytes will not be + # transferred to the host during read. + # Type 3 - ? (GUARD tag, reference tag and app tag are combined) + # - http://www.snia.org/sites/default/education/tutorials/2008/fall/storage/RichardVanderbilt_Why_Data_Integrity_rev2.pdf + # Protection is enabled and the 32-byte commands are not valid. The Reference Tag is + # not defined and may be used as an extension of the Application Tag. The drive will + # not check the Reference Tag. + # - https://www.hgst.com/sites/default/files/resources/End-to-end_Data_Protection.pdf + # Type 3 does not define the ref tag. + # - http://lxr.free-electrons.com/source/block/t10-pi.c + # + + # LSI loves to randomly sticking things together... + $line =~ s/BatteryFRU/Battery FRU/; + $line =~ s/ChipRevision/Chip Revision/; + $line =~ s/DisableHII/Disable HII/; + $line =~ s/EnableCrashDump/Enable Crash-Dump/; + $line =~ s/EnableLDBBM/Enable LD_BBM/; + $line =~ s/elementcount/element_count/i; + $line =~ s/perio/per_io/i; + + ### NOTE: ROC is RAID on Chip, which is what they call their controller's ASIC + # and they love their weird short forms + $line =~ s/Ctrl/Controller/i; + $line =~ s/Mfg/Manufacture/i; + $line =~ s/Cfg/Config/i; + $line =~ s/Perf /Performance /i; + $line =~ s/ Ext / External /i; + $line =~ s/ VD/ Virtual Disk/i; + $line =~ s/ VDs/ Virtual Disks/i; + $line =~ s/VD /Virtual Disk /i; + $line =~ s/ PD/ Physical Disk/i; + $line =~ s/ PI/ Protection Information/i; + $line =~ s/ LDPI/ Logical Disk Protection Information/i; # https://www.seagate.com/files/staticfiles/docs/pdf/whitepaper/safeguarding-data-from-corruption-technology-paper-tp621us.pdf + $line =~ s/ CC/ Consistency Check/i; + $line =~ s/ BGI/ Background Initialization/i; + $line =~ s/ BGI/ Background/i; + $line =~ s/ LD/ Logical Device/i; + $line =~ s/ FW/ Firmware/i; + $line =~ s/ HII/ Human Interface Infrastructure/i; + $line =~ s/ PFK/ Premium Feature Key/i; + $line =~ s/ WB/ Write-Back/i; + $line =~ s/SSC /Security Subsystem Class /i; # https://en.wikipedia.org/wiki/Opal_Storage_Specification + $line =~ s/ SMP/ Serial Management Protocol/i; # https://en.wikipedia.org/wiki/Serial_Attached_SCSI#Characteristics + $line =~ s/ STP/ Serial ATA Tunneling Protocol/i; # https://en.wikipedia.org/wiki/Serial_Attached_SCSI#Characteristics + $line =~ s/Phys /Physical Layers /i; # 12Gps MegaRAID SAS Software User Guide, March 14, 2016, 4.14.8, https://en.wikipedia.org/wiki/PHY_(chip) + $line =~ s/Phy /Physical Layer /i; # 12Gps MegaRAID SAS Software User Guide, March 14, 2016, 4.14.8, https://en.wikipedia.org/wiki/PHY_(chip) + $line =~ s/ OCE/ Online Capacity Expansion/i; # 12Gps MegaRAID SAS Software User Guide, March 14, 2016, 5.5.14 -> 5 + $line =~ s/ RLM/ RAID Level Migration/i; # 12Gps MegaRAID SAS Software User Guide, March 14, 2016, 5.5.14 -> 5 + $line =~ s/ EKM/ External Key Management/i; + $line =~ s/ BBM/ Bad Block Management/i; + $line =~ s/ QD/ Queue Depth/i; + $line =~ s/NCQ/Native Command Queuing/i; # https://en.wikipedia.org/wiki/Native_Command_Queuing + $line =~ s/ LDBBM/ Logical Disk Bad Block Management/i; + $line =~ s/TPM/Trusted Platform Module/i; # https://en.wikipedia.org/wiki/Trusted_Platform_Module + $line =~ s/\(hrs\)/\(#!variable!scan_storcli_unit_0002!#\)/i; + $line =~ s/ hrs/ #!variable!scan_storcli_unit_0002!#/i; + $line =~ s/ZCR /Zero-Channel RAID /i; + $line =~ s/R1E /RAID 1E /i; + $line =~ s/ R10/ RAID 10/i; + $line =~ s/RAID(\d+)/RAID $1/gi; + $line =~ s/TTY /Terminal /i; + $line =~ s/CME /Continuous Media Error/i; + $line =~ s/SGE /Scatter-Gather Element/i; # https://en.wikipedia.org/wiki/Vectored_I/O + + # Standardize some random strings with the same meaning + $line =~ s/Id /ID /; + $line =~ s/ NA/ N\/A/; + $line =~ s/Bios/BIOS/; + $line =~ s/S\.M\.A\.R\.T\./SMART/i; + $line =~ s/S\.M\.A\.R\.T/SMART/i; + + # And randomly using sentances... + $line =~ s/A rollback operation is in progress/Roll-back operation in progress/i; + $line =~ s/must be rebooted to complete security operation/Reboot Required for Security Operation/i; + $line =~ s/Maximum number of direct attached drives to spin up in 1 min/direct attached drives spun-up per minute/i; + + # And things that break variables when they change + $line =~ s/\(Default\)//; + $line =~ s/Sesmonitoring/SCSI Enclosure Service Monitoring/i; # https://en.wikipedia.org/wiki/SES-2_Enclosure_Management + $line =~ s/SecurityonJBOD/Security on JBOD/i; + $line =~ s/ForceFlash/Force Flash/i; + $line =~ s/DisableImmediateIO/Disable Immediate IO/i; + $line =~ s/LargeIOSupport/Large IO Support/i; + $line =~ s/DrvActivityLEDSetting/Drive Activity LED Setting/i; + $line =~ s/FlushWriteVerify/Flush Write Verify/i; + $line =~ s/CPLDUpdate/Complex Programmable Logic Device Update/i; # https://en.wikipedia.org/wiki/Complex_programmable_logic_device + $line =~ s/ForceTo512e/Force to 512e/i; # 512-byte sector size emulation + $line =~ s/discardCacheDuringLDDelete/Discard Cache During Logical Disk Delete/; + $line =~ s/Breakmirror/Break Mirror/i; # 12Gps MegaRAID SAS Software User Guide, March 14, 2016, 4.14.16 + $line =~ s/Cachebypass/Cache Bypass/i; + $line =~ s/PolaritySplit/Polarity Split/i; + $line =~ s/EnableCrashDump/Enable Crash Dump/i; + $line =~ s/PowerSave/Power Save/i; + + push @{$controller_data}, $line; + } + + # If I didn't find a serial number, something went wrong. + if (not $serial_number) + { + # Error out. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1 , key => "scan_storcli_error_0006", variables => { adapter => $adapter }}); + $anvil->nice_exit({exit_code => 6}); + } + + # Get the current alarm state. + undef $output; + undef $return_code; + ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{alarm_state}}); + $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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + if ($line =~ /^Alarm\s+(.*)$/i) + { + my $state = $1; + $line = "Alarm State = ".$state; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + push @{$controller_data}, $line; + } + } + + # Get the rebuild rate + undef $output; + undef $return_code; + ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{rebuild_rate}}); + $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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + if ($line =~ /^Rebuildrate\s+(\d+)%$/i) + { + my $rate = $1; + $line = "Rebuild Rate % = ".$rate; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + push @{$controller_data}, $line; + } + } + + # Get the background initialization rate + undef $output; + undef $return_code; + ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{bgi_rate}}); + $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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + if ($line =~ /^BGI Rate\s+(\d+)%$/i) + { + my $rate = $1; + $line = "Background Initialization Rate % = ".$rate; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + push @{$controller_data}, $line; + } + } + + # Get the consistency check rate + undef $output; + undef $return_code; + ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{cc_rate}}); + $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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + if ($line =~ /^CC Rate\s+(\d+)%$/i) + { + my $rate = $1; + $line = "Consistency Check Rate % = ".$rate; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + push @{$controller_data}, $line; + } + } + + # Get the patrol read rate + undef $output; + undef $return_code; + ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{pr_rate}}); + $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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + if ($line =~ /^Patrol Read Rate\s+(\d+)%$/i) + { + my $rate = $1; + $line = "Patrol Read Rate % = ".$rate; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + push @{$controller_data}, $line; + } + } + + # Get the performance mode + undef $output; + undef $return_code; + ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." /c".$adapter." ".$anvil->data->{'scan-storcli'}{arguments}{performance_mode}}); + $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}); + $line =~ s/\s+:/:/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + if ($line =~ /^Perf Mode\s+(.*)$/i) + { + my $mode = $1; + $line = "Performance Mode = ".$mode; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< line" => $line }}); + push @{$controller_data}, $line; + } + } + + # If we're alive, we're ready to proceed. + foreach my $line (@{$controller_data}) + { + my $type = "variable"; + if ($line =~ /^(.*?)\s+=\s+(.*)$/) + { + 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 =~ /\((\w+B)\)$/i) + { + my $units = $1; + $variable =~ s/\($units\)//i; + $variable =~ s/^\s+//; + $variable =~ s/\s+$//; + my $size = $anvil->Convert->human_readable_to_bytes({size => $value, type => $units, base2 => 1})." #!string!scan_storcli_unit_0001!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + units => $units, + size => $size, + }}); + } + elsif ($variable =~ /\(Degree Celsius\)/i) + { +# $variable =~ s/\(Degree Celsius\)/ C/i; + $variable =~ s/^\s+//; + $variable =~ s/\s+$//; + $variable =~ s/\s+/ /; + $type = "temperature"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + type => $type, + }}); + } + elsif ($variable =~ /\(Degree Fahrenheit\)/i) + { + # Covert to °C + $variable =~ s/\(Degree Fahrenheit\)//i; + $variable =~ s/^\s+//; + $variable =~ s/\s+$//; + $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 ($variable =~ /\(hours\)/i) + { + # THis will get translated when generating an alert + $variable =~ s/\(hours\)//; + $variable =~ s/^\s+//; + $variable =~ s/^\s+//; + $variable =~ s/\s+/ /g; + $value .= " #!variable!scan_storcli_unit_0002!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($variable =~ /\(hour\)/i) + { + # THis will get translated when generating an alert + $variable =~ s/\(min\)//; + $variable =~ s/^\s+//; + $variable =~ s/^\s+//; + $variable =~ s/\s+/ /g; + $value .= " #!variable!scan_storcli_unit_0003!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($variable =~ /\(mins\)/i) + { + # THis will get translated when generating an alert + $variable =~ s/\(mins\)//; + $variable =~ s/^\s+//; + $variable =~ s/^\s+//; + $variable =~ s/\s+/ /g; + $value .= " #!variable!scan_storcli_unit_0004!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($variable =~ /\(min\)/i) + { + # THis will get translated when generating an alert + $variable =~ s/\(min\)//; + $variable =~ s/^\s+//; + $variable =~ s/^\s+//; + $variable =~ s/\s+/ /g; + $value .= " #!variable!scan_storcli_unit_0005!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($variable =~ /\(secs\)/i) + { + # THis will get translated when generating an alert + $variable =~ s/\(secs\)//; + $variable =~ s/^\s+//; + $variable =~ s/^\s+//; + $variable =~ s/\s+/ /g; + $value .= " #!variable!scan_storcli_unit_0006!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + elsif ($variable =~ /\(sec\)/i) + { + # THis will get translated when generating an alert + $variable =~ s/\(sec\)//; + $variable =~ s/^\s+//; + $variable =~ s/^\s+//; + $variable =~ s/\s+/ /g; + $value .= " #!variable!scan_storcli_unit_0007!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + variable => $variable, + value => $value, + }}); + } + + # Convert some values. + if ($value =~ /(\d\d)\/(\d\d)\/(\d\d\d\d), (\d\d:\d\d:\d\d)/) + { + # mm/dd/yyyy -> yyyy/mm/dd + $value = $3."/".$1."/".$2.", ".$4; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + if ($value =~ /(\d+) hrs/) + { + $value = $1." #!variable!scan_storcli_unit_0002!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + if ($value =~ /\(hrs\)/) + { + $value =~ s/\(hrs\)/\(#!variable!scan_storcli_unit_0002!#\)/; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + if ($value =~ /^(\d+)s/) + { + $value = $1." #!variable!scan_storcli_unit_0006!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + if ($value =~ /^0x\w+$/) + { + # Hex value, leave it alone + $anvil->data->{controller}{serial_number}{$serial_number}{$type}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::serial_number::${serial_number}::${type}::${variable}" => $anvil->data->{controller}{serial_number}{$serial_number}{$type}{$variable}, + }}); + next; + } + if (($value =~ /^(\d+\s*[A-Za-z]+B)$/i) or ($value =~ /^(\d+\.\d+\s*[A-Za-z]+B)$/i)) + { + my $size = $1; + $value = $anvil->Convert->human_readable_to_bytes({base2 => 1, size => $size}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + size => $size, + value => $value, + }}); + } + if ($value =~ /^00\/00\/00$/i) + { + # N/A + $value = "#!variable!scan_storcli_unit_0008!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + + if ($value =~ /^AWB$/i) + { + $value = "#!variable!scan_storcli_unit_0009!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + if ($value =~ /^WB$/i) + { + $value = "#!variable!scan_storcli_unit_0010!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + if ($value =~ /^WT$/i) + { + $value = "#!variable!scan_storcli_unit_0011!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + if ($value =~ /^(\d+) sectors/i) + { + $value = $1." #!variable!scan_storcli_unit_0012!#"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + + # Store it + if (exists $anvil->data->{controller}{serial_number}{$serial_number}{$type}{$variable}) + { + # Conflict! This is a dirty way to keep them separate + $variable .= " 2"; + } + + $variable = process_variable_name($anvil, $variable); + $anvil->data->{controller}{serial_number}{$serial_number}{$type}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "controller::serial_number::${serial_number}::${type}::${variable}" => $anvil->data->{controller}{serial_number}{$serial_number}{$type}{$variable}, + }}); + } + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { serial_number => $serial_number }}); + return($serial_number); +} + +# 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; + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< variable" => $variable }}); + return($variable); +} + +# This does two things; It checks to see if storcli64 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_lsi_controllers +{ + my ($anvil) = @_; + + # This will keep track of how many controllers we find. + my $adapter_count = 0; + + # Vendor-specific copies of storcli replace it. So first, check to see if that is the case on this + # node. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "path::exe::perccli64" => $anvil->data->{path}{exe}{perccli64} }}); + if (-e $anvil->data->{path}{exe}{perccli64}) + { + # It does, replace the 'storcli64' path. + $anvil->data->{path}{exe}{storcli64} = $anvil->data->{path}{exe}{perccli64}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "path::exe::storcli64" => $anvil->data->{path}{exe}{storcli64} }}); + } + + # First, do we have storcli64 installed? + if (not -e $anvil->data->{path}{exe}{storcli64}) + { + # Nope, exit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "scan_storcli_error_0001", variables => { path => $anvil->data->{path}{exe}{storcli64} }}); + $anvil->nice_exit({exit_code => 1}); + } + + # Make sure it is executable + if (not -x $anvil->data->{path}{exe}{storcli64}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "scan_storcli_error_0002", variables => { path => $anvil->data->{path}{exe}{storcli64} }}); + $anvil->nice_exit({exit_code => 2}); + } + + # Still alive? Good! Look for controllers now. + my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{storcli64}." ".$anvil->data->{'scan-storcli'}{arguments}{adapter_count}}); + $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 =~ /Controller Count = (\d+)/i) + { + $adapter_count = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { adapter_count => $adapter_count }}); + } + } + + # Have we any adapters? + if ($adapter_count > 0) + { + $anvil->data->{'scan-storcli'}{adapter_count} = $adapter_count; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 2, key => "scan_storcli_log_0001", variables => { + count => $anvil->data->{'scan-storcli'}{adapter_count}, + }}); + } + else + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "scan_storcli_error_0003", variables => { + path => $anvil->data->{path}{exe}{storcli64}, + }}); + + $anvil->nice_exit({exit_code => 3}); + } + + return(0); +} diff --git a/scancore-agents/scan-storcli/scan-storcli.sql b/scancore-agents/scan-storcli/scan-storcli.sql new file mode 100644 index 00000000..d9bb240f --- /dev/null +++ b/scancore-agents/scan-storcli/scan-storcli.sql @@ -0,0 +1,640 @@ +-- This is the database schema for the 'storcli 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 -- +-- ------------------------------------------------------------------------------------------------------- -- + +-- Here is the basic controller information. All connected devices will reference back to this table's +-- 'storcli_controller_serial_number' column. + +-- Key variables; +-- - "ROC temperature" +CREATE TABLE scan_storcli_controllers ( + scan_storcli_controller_uuid uuid not null primary key, + scan_storcli_controller_host_uuid uuid not null, + scan_storcli_controller_serial_number text not null, -- This is the core identifier + scan_storcli_controller_model text not null, -- "model" + scan_storcli_controller_alarm_state text not null, -- "alarm_state" + scan_storcli_controller_cache_size numeric not null, -- "on_board_memory_size" + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_storcli_controller_host_uuid) REFERENCES hosts(host_uuid) +); +ALTER TABLE scan_storcli_controllers OWNER TO admin; + +CREATE TABLE history.scan_storcli_controllers ( + history_id bigserial, + scan_storcli_controller_uuid uuid, + scan_storcli_controller_host_uuid uuid, + scan_storcli_controller_serial_number text, + scan_storcli_controller_model text, + scan_storcli_controller_alarm_state text, + scan_storcli_controller_cache_size numeric, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_storcli_controllers OWNER TO admin; + +CREATE FUNCTION history_scan_storcli_controllers() RETURNS trigger +AS $$ +DECLARE + history_scan_storcli_controllers RECORD; +BEGIN + SELECT INTO history_scan_storcli_controllers * FROM scan_storcli_controllers WHERE scan_storcli_controller_uuid=new.scan_storcli_controller_uuid; + INSERT INTO history.scan_storcli_controllers + (scan_storcli_controller_uuid, + scan_storcli_controller_host_uuid, + scan_storcli_controller_serial_number, + scan_storcli_controller_model, + scan_storcli_controller_alarm_state, + scan_storcli_controller_cache_size, + modified_date) + VALUES + (history_scan_storcli_controllers.scan_storcli_controller_uuid, + history_scan_storcli_controllers.scan_storcli_controller_host_uuid, + history_scan_storcli_controllers.scan_storcli_controller_serial_number, + history_scan_storcli_controllers.scan_storcli_controller_model, + history_scan_storcli_controllers.scan_storcli_controller_alarm_state, + history_scan_storcli_controllers.scan_storcli_controller_cache_size, + history_scan_storcli_controllers.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_storcli_controllers() OWNER TO admin; + +CREATE TRIGGER trigger_scan_storcli_controllers + AFTER INSERT OR UPDATE ON scan_storcli_controllers + FOR EACH ROW EXECUTE PROCEDURE history_scan_storcli_controllers(); + + +-- ------------------------------------------------------------------------------------------------------- -- +-- Cachevault -- +-- ------------------------------------------------------------------------------------------------------- -- + +-- Key variables; +-- - "Temperature" +-- - "Capacitance" +-- - "Pack Energy" +-- - "Next Learn time" +-- This records the basic information about the cachevault (FBU) unit. +CREATE TABLE scan_storcli_cachevaults ( + scan_storcli_cachevault_uuid uuid not null primary key, + scan_storcli_cachevault_host_uuid uuid not null, + scan_storcli_cachevault_controller_uuid uuid not null, + scan_storcli_cachevault_serial_number text not null, -- "Serial Number" + scan_storcli_cachevault_state text not null, -- "State" + scan_storcli_cachevault_design_capacity text not null, -- "Design Capacity" + scan_storcli_cachevault_replacement_needed text not null, -- "Replacement required" + scan_storcli_cachevault_type text not null, -- "Type" + scan_storcli_cachevault_model text not null, -- "Device Name" + scan_storcli_cachevault_manufacture_date text not null, -- "Date of Manufacture" + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_storcli_cachevault_host_uuid) REFERENCES hosts(host_uuid), + FOREIGN KEY(scan_storcli_cachevault_controller_uuid) REFERENCES scan_storcli_controllers(scan_storcli_controller_uuid) +); +ALTER TABLE scan_storcli_cachevaults OWNER TO admin; + +CREATE TABLE history.scan_storcli_cachevaults ( + history_id bigserial, + scan_storcli_cachevault_uuid uuid, + scan_storcli_cachevault_host_uuid uuid, + scan_storcli_cachevault_controller_uuid uuid, + scan_storcli_cachevault_serial_number text, + scan_storcli_cachevault_state text, + scan_storcli_cachevault_design_capacity text, + scan_storcli_cachevault_replacement_needed text, + scan_storcli_cachevault_type text, + scan_storcli_cachevault_model text, + scan_storcli_cachevault_manufacture_date text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_storcli_cachevaults OWNER TO admin; + +CREATE FUNCTION history_scan_storcli_cachevaults() RETURNS trigger +AS $$ +DECLARE + history_scan_storcli_cachevaults RECORD; +BEGIN + SELECT INTO history_scan_storcli_cachevaults * FROM scan_storcli_cachevaults WHERE scan_storcli_cachevault_uuid=new.scan_storcli_cachevault_uuid; + INSERT INTO history.scan_storcli_cachevaults + (scan_storcli_cachevault_uuid, + scan_storcli_cachevault_host_uuid, + scan_storcli_cachevault_controller_uuid, + scan_storcli_cachevault_serial_number, + scan_storcli_cachevault_state, + scan_storcli_cachevault_design_capacity, + scan_storcli_cachevault_replacement_needed, + scan_storcli_cachevault_type, + scan_storcli_cachevault_model, + scan_storcli_cachevault_manufacture_date, + modified_date) + VALUES + (history_scan_storcli_cachevaults.scan_storcli_cachevault_uuid, + history_scan_storcli_cachevaults.scan_storcli_cachevault_host_uuid, + history_scan_storcli_cachevaults.scan_storcli_cachevault_controller_uuid, + history_scan_storcli_cachevaults.scan_storcli_cachevault_serial_number, + history_scan_storcli_cachevaults.scan_storcli_cachevault_state, + history_scan_storcli_cachevaults.scan_storcli_cachevault_design_capacity, + history_scan_storcli_cachevaults.scan_storcli_cachevault_replacement_needed, + history_scan_storcli_cachevaults.scan_storcli_cachevault_type, + history_scan_storcli_cachevaults.scan_storcli_cachevault_model, + history_scan_storcli_cachevaults.scan_storcli_cachevault_manufacture_date, + history_scan_storcli_cachevaults.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_storcli_cachevaults() OWNER TO admin; + +CREATE TRIGGER trigger_scan_storcli_cachevaults + AFTER INSERT OR UPDATE ON scan_storcli_cachevaults + FOR EACH ROW EXECUTE PROCEDURE history_scan_storcli_cachevaults(); + + +-- ------------------------------------------------------------------------------------------------------- -- +-- Battery Backup Units -- +-- ------------------------------------------------------------------------------------------------------- -- + +-- Key variables; +-- - "Temperature" +-- - "Absolute state of charge" +-- - "Cycle Count" +-- - "Full Charge Capacity" +-- - "Fully Charged" +-- - "Learn Cycle Active" +-- - "Next Learn time" +-- - "Over Charged" +-- - "Over Temperature" +-- This records the basic information about the cachevault (FBU) unit. +CREATE TABLE scan_storcli_bbus ( + scan_storcli_bbu_uuid uuid not null primary key, + scan_storcli_bbu_host_uuid uuid not null, + scan_storcli_bbu_controller_uuid uuid not null, + scan_storcli_bbu_serial_number text not null, -- "Serial Number" + scan_storcli_bbu_type text not null, -- "Type" + scan_storcli_bbu_model text not null, -- "Manufacture Name" + scan_storcli_bbu_state text not null, -- "Battery State" + scan_storcli_bbu_manufacture_date text not null, -- "Date of Manufacture" + scan_storcli_bbu_design_capacity text not null, -- "Design Capacity" + scan_storcli_bbu_replacement_needed text not null, -- "Pack is about to fail & should be replaced" + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_storcli_bbu_host_uuid) REFERENCES hosts(host_uuid), + FOREIGN KEY(scan_storcli_bbu_controller_uuid) REFERENCES scan_storcli_controllers(scan_storcli_controller_uuid) +); +ALTER TABLE scan_storcli_bbus OWNER TO admin; + +CREATE TABLE history.scan_storcli_bbus ( + history_id bigserial, + scan_storcli_bbu_uuid uuid, + scan_storcli_bbu_host_uuid uuid, + scan_storcli_bbu_controller_uuid uuid, + scan_storcli_bbu_serial_number text, + scan_storcli_bbu_type text, + scan_storcli_bbu_model text, + scan_storcli_bbu_state text, + scan_storcli_bbu_manufacture_date text, + scan_storcli_bbu_design_capacity text, + scan_storcli_bbu_replacement_needed text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_storcli_bbus OWNER TO admin; + +CREATE FUNCTION history_scan_storcli_bbus() RETURNS trigger +AS $$ +DECLARE + history_scan_storcli_bbus RECORD; +BEGIN + SELECT INTO history_scan_storcli_bbus * FROM scan_storcli_bbus WHERE scan_storcli_bbu_uuid=new.scan_storcli_bbu_uuid; + INSERT INTO history.scan_storcli_bbus + (scan_storcli_bbu_uuid, + scan_storcli_bbu_host_uuid, + scan_storcli_bbu_controller_uuid, + scan_storcli_bbu_serial_number, + scan_storcli_bbu_type, + scan_storcli_bbu_model, + scan_storcli_bbu_state, + scan_storcli_bbu_manufacture_date, + scan_storcli_bbu_design_capacity, + scan_storcli_bbu_replacement_needed, + modified_date) + VALUES + (history_scan_storcli_bbus.scan_storcli_bbu_uuid, + history_scan_storcli_bbus.scan_storcli_bbu_host_uuid, + history_scan_storcli_bbus.scan_storcli_bbu_controller_uuid, + history_scan_storcli_bbus.scan_storcli_bbu_serial_number, + history_scan_storcli_bbus.scan_storcli_bbu_type, + history_scan_storcli_bbus.scan_storcli_bbu_model, + history_scan_storcli_bbus.scan_storcli_bbu_state, + history_scan_storcli_bbus.scan_storcli_bbu_manufacture_date, + history_scan_storcli_bbus.scan_storcli_bbu_design_capacity, + history_scan_storcli_bbus.scan_storcli_bbu_replacement_needed, + history_scan_storcli_bbus.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_storcli_bbus() OWNER TO admin; + +CREATE TRIGGER trigger_scan_storcli_bbus + AFTER INSERT OR UPDATE ON scan_storcli_bbus + FOR EACH ROW EXECUTE PROCEDURE history_scan_storcli_bbus(); + + +-- ------------------------------------------------------------------------------------------------------- -- +-- Virtual Drives -- +-- ------------------------------------------------------------------------------------------------------- -- + +-- This records the basic virtual drives. These contain one or more drive groups to form an array +CREATE TABLE scan_storcli_virtual_drives ( + scan_storcli_virtual_drive_uuid uuid not null primary key, + scan_storcli_virtual_drive_host_uuid uuid not null, + scan_storcli_virtual_drive_controller_uuid uuid not null, + scan_storcli_virtual_drive_id_string text not null, -- This is '-vd' where 'x' is the virtual drive number. + scan_storcli_virtual_drive_creation_date text not null, -- "Creation Date" and "Creation Time" + scan_storcli_virtual_drive_data_protection text not null, -- "Data Protection" + scan_storcli_virtual_drive_disk_cache_policy text not null, -- "Disk Cache Policy" + scan_storcli_virtual_drive_emulation_type text not null, -- "Emulation type" + scan_storcli_virtual_drive_encryption text not null, -- "Encryption" + scan_storcli_virtual_drive_blocks numeric not null, -- "Number of Blocks" + scan_storcli_virtual_drive_strip_size text not null, -- "Strip Size" (has the suffix 'Bytes', so not numeric) + scan_storcli_virtual_drive_drives_per_span numeric not null, -- "Number of Drives Per Span" + scan_storcli_virtual_drive_span_depth numeric not null, -- "Span Depth" + scan_storcli_virtual_drive_scsi_naa_id text not null, -- "SCSI NAA Id" - https://en.wikipedia.org/wiki/ISCSI#Addressing + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_storcli_virtual_drive_host_uuid) REFERENCES hosts(host_uuid), + FOREIGN KEY(scan_storcli_virtual_drive_controller_uuid) REFERENCES scan_storcli_controllers(scan_storcli_controller_uuid) +); +ALTER TABLE scan_storcli_virtual_drives OWNER TO admin; + +CREATE TABLE history.scan_storcli_virtual_drives ( + history_id bigserial, + scan_storcli_virtual_drive_uuid uuid, + scan_storcli_virtual_drive_host_uuid uuid, + scan_storcli_virtual_drive_controller_uuid uuid, + scan_storcli_virtual_drive_id_string text, + scan_storcli_virtual_drive_creation_date text, + scan_storcli_virtual_drive_data_protection text, + scan_storcli_virtual_drive_disk_cache_policy text, + scan_storcli_virtual_drive_emulation_type text, + scan_storcli_virtual_drive_encryption text, + scan_storcli_virtual_drive_blocks numeric, + scan_storcli_virtual_drive_strip_size text, + scan_storcli_virtual_drive_drives_per_span numeric, + scan_storcli_virtual_drive_span_depth numeric, + scan_storcli_virtual_drive_scsi_naa_id text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_storcli_virtual_drives OWNER TO admin; + +CREATE FUNCTION history_scan_storcli_virtual_drives() RETURNS trigger +AS $$ +DECLARE + history_scan_storcli_virtual_drives RECORD; +BEGIN + SELECT INTO history_scan_storcli_virtual_drives * FROM scan_storcli_virtual_drives WHERE scan_storcli_virtual_drive_uuid=new.scan_storcli_virtual_drive_uuid; + INSERT INTO history.scan_storcli_virtual_drives + (scan_storcli_virtual_drive_uuid, + scan_storcli_virtual_drive_host_uuid, + scan_storcli_virtual_drive_controller_uuid, + scan_storcli_virtual_drive_id_string, + scan_storcli_virtual_drive_creation_date, + scan_storcli_virtual_drive_data_protection, + scan_storcli_virtual_drive_disk_cache_policy, + scan_storcli_virtual_drive_emulation_type, + scan_storcli_virtual_drive_encryption, + scan_storcli_virtual_drive_blocks, + scan_storcli_virtual_drive_strip_size, + scan_storcli_virtual_drive_drives_per_span, + scan_storcli_virtual_drive_span_depth, + scan_storcli_virtual_drive_scsi_naa_id, + modified_date) + VALUES + (history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_uuid, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_host_uuid, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_controller_uuid, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_id_string, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_creation_date, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_data_protection, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_disk_cache_policy, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_emulation_type, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_encryption, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_blocks, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_strip_size, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_drives_per_span, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_span_depth, + history_scan_storcli_virtual_drives.scan_storcli_virtual_drive_scsi_naa_id, + history_scan_storcli_virtual_drives.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_storcli_virtual_drives() OWNER TO admin; + +CREATE TRIGGER trigger_scan_storcli_virtual_drives + AFTER INSERT OR UPDATE ON scan_storcli_virtual_drives + FOR EACH ROW EXECUTE PROCEDURE history_scan_storcli_virtual_drives(); + + +-- ------------------------------------------------------------------------------------------------------- -- +-- Drive Groups -- +-- ------------------------------------------------------------------------------------------------------- -- + +-- This records the basic drive group information. +CREATE TABLE scan_storcli_drive_groups ( + scan_storcli_drive_group_uuid uuid not null primary key, + scan_storcli_drive_group_host_uuid uuid not null, + scan_storcli_drive_group_virtual_drive_uuid uuid not null, + scan_storcli_drive_group_id_string text not null, -- This is '-vd-dg' where 'x' is the virtual drive number and 'y' is the drive group number. + scan_storcli_drive_group_access text not null, -- "access" + scan_storcli_drive_group_array_size text not null, -- "array_size" + scan_storcli_drive_group_array_state text not null, -- "array_state" + scan_storcli_drive_group_cache text not null, -- "cache" + scan_storcli_drive_group_cachecade text not null, -- "cachecade" + scan_storcli_drive_group_consistent text not null, -- "consistent" + scan_storcli_drive_group_disk_cache text not null, -- "disk_cache" + scan_storcli_drive_group_raid_type text not null, -- "raid_type" + scan_storcli_drive_group_read_cache text not null, -- "read_cache" + scan_storcli_drive_group_scheduled_cc text not null, -- "scheduled_consistency_check" + scan_storcli_drive_group_write_cache text not null, -- "write_cache" + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_storcli_drive_group_host_uuid) REFERENCES hosts(host_uuid), + FOREIGN KEY(scan_storcli_drive_group_virtual_drive_uuid) REFERENCES scan_storcli_virtual_drives(scan_storcli_virtual_drive_uuid) +); +ALTER TABLE scan_storcli_drive_groups OWNER TO admin; + +CREATE TABLE history.scan_storcli_drive_groups ( + history_id bigserial, + scan_storcli_drive_group_uuid uuid, + scan_storcli_drive_group_host_uuid uuid, + scan_storcli_drive_group_virtual_drive_uuid uuid, + scan_storcli_drive_group_id_string text, + scan_storcli_drive_group_access text, + scan_storcli_drive_group_array_size text, + scan_storcli_drive_group_array_state text, + scan_storcli_drive_group_cache text, + scan_storcli_drive_group_cachecade text, + scan_storcli_drive_group_consistent text, + scan_storcli_drive_group_disk_cache text, + scan_storcli_drive_group_raid_type text, + scan_storcli_drive_group_read_cache text, + scan_storcli_drive_group_scheduled_cc text, + scan_storcli_drive_group_write_cache text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_storcli_drive_groups OWNER TO admin; + +CREATE FUNCTION history_scan_storcli_drive_groups() RETURNS trigger +AS $$ +DECLARE + history_scan_storcli_drive_groups RECORD; +BEGIN + SELECT INTO history_scan_storcli_drive_groups * FROM scan_storcli_drive_groups WHERE scan_storcli_drive_group_uuid=new.scan_storcli_drive_group_uuid; + INSERT INTO history.scan_storcli_drive_groups + (scan_storcli_drive_group_uuid, + scan_storcli_drive_group_host_uuid, + scan_storcli_drive_group_virtual_drive_uuid, + scan_storcli_drive_group_id_string, + scan_storcli_drive_group_access, + scan_storcli_drive_group_array_size, + scan_storcli_drive_group_array_state, + scan_storcli_drive_group_cache, + scan_storcli_drive_group_cachecade, + scan_storcli_drive_group_consistent, + scan_storcli_drive_group_disk_cache, + scan_storcli_drive_group_raid_type, + scan_storcli_drive_group_read_cache, + scan_storcli_drive_group_scheduled_cc, + scan_storcli_drive_group_write_cache, + modified_date) + VALUES + (history_scan_storcli_drive_groups.scan_storcli_drive_group_uuid, + history_scan_storcli_drive_groups.scan_storcli_drive_group_host_uuid, + history_scan_storcli_drive_groups.scan_storcli_drive_group_virtual_drive_uuid, + history_scan_storcli_drive_groups.scan_storcli_drive_group_id_string, + history_scan_storcli_drive_groups.scan_storcli_drive_group_access, + history_scan_storcli_drive_groups.scan_storcli_drive_group_array_size, + history_scan_storcli_drive_groups.scan_storcli_drive_group_array_state, + history_scan_storcli_drive_groups.scan_storcli_drive_group_cache, + history_scan_storcli_drive_groups.scan_storcli_drive_group_cachecade, + history_scan_storcli_drive_groups.scan_storcli_drive_group_consistent, + history_scan_storcli_drive_groups.scan_storcli_drive_group_disk_cache, + history_scan_storcli_drive_groups.scan_storcli_drive_group_raid_type, + history_scan_storcli_drive_groups.scan_storcli_drive_group_read_cache, + history_scan_storcli_drive_groups.scan_storcli_drive_group_scheduled_cc, + history_scan_storcli_drive_groups.scan_storcli_drive_group_write_cache, + history_scan_storcli_drive_groups.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_storcli_drive_groups() OWNER TO admin; + +CREATE TRIGGER trigger_scan_storcli_drive_groups + AFTER INSERT OR UPDATE ON scan_storcli_drive_groups + FOR EACH ROW EXECUTE PROCEDURE history_scan_storcli_drive_groups(); + + +-- ------------------------------------------------------------------------------------------------------- -- +-- Physical Drives -- +-- ------------------------------------------------------------------------------------------------------- -- + +-- NOTE: More information to T10-PI (protection information) is available here: +-- https://www.seagate.com/files/staticfiles/docs/pdf/whitepaper/safeguarding-data-from-corruption-technology-paper-tp621us.pdf + +-- This records the basic drive group information. +-- Key variables; +-- - "Drive Temperature" +-- - "spun_up" +-- - "state" +-- - "Certified" +-- - "Device Speed" +-- - "Link Speed" +-- - "sas_port_0_link_speed" +-- - "sas_port_0_port_status" +-- - "sas_port_0_sas_address" +-- - "sas_port_1_link_speed" +-- - "sas_port_1_port_status" +-- - "sas_port_1_sas_address" +-- - "drive_media" +-- - "interface" +-- - "NAND Vendor" +-- - "Firmware Revision" +-- - "World Wide Name" +-- - "device_id" +-- - "SED Enabled" +-- - "Secured" +-- - "Locked" +-- - "Needs External Key Management Attention" +-- - "protection_info", "Protection Information Eligible" +-- - "Emergency Spare" +-- - "Commissioned Spare" +-- - "S.M.A.R.T alert flagged by drive" +-- - "Media Error Count" +-- - "Other Error Count" +-- - "Predictive Failure Count" +CREATE TABLE scan_storcli_physical_drives ( + scan_storcli_physical_drive_uuid uuid not null primary key, + scan_storcli_physical_drive_host_uuid uuid not null, + scan_storcli_physical_drive_controller_uuid uuid not null, + scan_storcli_physical_drive_virtual_drive text not null, + scan_storcli_physical_drive_drive_group text not null, + scan_storcli_physical_drive_enclosure_id text not null, + scan_storcli_physical_drive_slot_number text not null, + scan_storcli_physical_drive_serial_number text not null, -- "Serial Number" + scan_storcli_physical_drive_size text not null, -- In 'text' because of 'Bytes' suffix - "drive_size" but also; "Raw size", "Non Coerced size" and "Coerced size" + scan_storcli_physical_drive_sector_size text not null, -- In 'text' because of 'Bytes' suffix - "sector_size", "Sector Size" + scan_storcli_physical_drive_vendor text not null, -- "Manufacturer Identification" + scan_storcli_physical_drive_model text not null, -- "drive_model", "Model Number" + scan_storcli_physical_drive_self_encrypting_drive text not null, -- "self_encrypting_drive", "SED Capable" + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_storcli_physical_drive_host_uuid) REFERENCES hosts(host_uuid), + FOREIGN KEY(scan_storcli_physical_drive_controller_uuid) REFERENCES scan_storcli_controllers(scan_storcli_controller_uuid) +); +ALTER TABLE scan_storcli_physical_drives OWNER TO admin; + +CREATE TABLE history.scan_storcli_physical_drives ( + history_id bigserial, + scan_storcli_physical_drive_uuid uuid, + scan_storcli_physical_drive_host_uuid uuid, + scan_storcli_physical_drive_controller_uuid uuid, + scan_storcli_physical_drive_serial_number text, + scan_storcli_physical_drive_virtual_drive text, + scan_storcli_physical_drive_drive_group text, + scan_storcli_physical_drive_enclosure_id text, + scan_storcli_physical_drive_slot_number text, + scan_storcli_physical_drive_size text, + scan_storcli_physical_drive_sector_size text, + scan_storcli_physical_drive_vendor text, + scan_storcli_physical_drive_model text, + scan_storcli_physical_drive_self_encrypting_drive text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_storcli_physical_drives OWNER TO admin; + +CREATE FUNCTION history_scan_storcli_physical_drives() RETURNS trigger +AS $$ +DECLARE + history_scan_storcli_physical_drives RECORD; +BEGIN + SELECT INTO history_scan_storcli_physical_drives * FROM scan_storcli_physical_drives WHERE scan_storcli_physical_drive_uuid=new.scan_storcli_physical_drive_uuid; + INSERT INTO history.scan_storcli_physical_drives + (scan_storcli_physical_drive_uuid, + scan_storcli_physical_drive_host_uuid, + scan_storcli_physical_drive_controller_uuid, + scan_storcli_physical_drive_virtual_drive, + scan_storcli_physical_drive_drive_group, + scan_storcli_physical_drive_enclosure_id, + scan_storcli_physical_drive_slot_number, + scan_storcli_physical_drive_serial_number, + scan_storcli_physical_drive_size, + scan_storcli_physical_drive_sector_size, + scan_storcli_physical_drive_vendor, + scan_storcli_physical_drive_model, + scan_storcli_physical_drive_self_encrypting_drive, + modified_date) + VALUES + (history_scan_storcli_physical_drives.scan_storcli_physical_drive_uuid, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_host_uuid, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_controller_uuid, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_virtual_drive, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_drive_group, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_enclosure_id, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_slot_number, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_serial_number, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_size, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_sector_size, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_vendor, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_model, + history_scan_storcli_physical_drives.scan_storcli_physical_drive_self_encrypting_drive, + history_scan_storcli_physical_drives.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_storcli_physical_drives() OWNER TO admin; + +CREATE TRIGGER trigger_scan_storcli_physical_drives + AFTER INSERT OR UPDATE ON scan_storcli_physical_drives + FOR EACH ROW EXECUTE PROCEDURE history_scan_storcli_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 -- + +-- 'storcli_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_storcli_variables ( + scan_storcli_variable_uuid uuid not null primary key, + scan_storcli_variable_host_uuid uuid not null, + scan_storcli_variable_source_table text not null, + scan_storcli_variable_source_uuid uuid not null, + scan_storcli_variable_is_temperature boolean not null default FALSE, + scan_storcli_variable_name text not null, + scan_storcli_variable_value text not null, + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_storcli_variable_host_uuid) REFERENCES hosts(host_uuid) +); +ALTER TABLE scan_storcli_variables OWNER TO admin; + +CREATE TABLE history.scan_storcli_variables ( + history_id bigserial, + scan_storcli_variable_uuid uuid, + scan_storcli_variable_host_uuid uuid, + scan_storcli_variable_source_table text, + scan_storcli_variable_source_uuid uuid, + scan_storcli_variable_is_temperature boolean, + scan_storcli_variable_name text, + scan_storcli_variable_value text, + modified_date timestamp with time zone +); +ALTER TABLE history.scan_storcli_variables OWNER TO admin; + +CREATE FUNCTION history_scan_storcli_variables() RETURNS trigger +AS $$ +DECLARE + history_scan_storcli_variables RECORD; +BEGIN + SELECT INTO history_scan_storcli_variables * FROM scan_storcli_variables WHERE scan_storcli_variable_uuid=new.scan_storcli_variable_uuid; + INSERT INTO history.scan_storcli_variables + (scan_storcli_variable_uuid, + scan_storcli_variable_host_uuid, + scan_storcli_variable_source_table, + scan_storcli_variable_source_uuid, + scan_storcli_variable_is_temperature, + scan_storcli_variable_name, + scan_storcli_variable_value, + modified_date) + VALUES + (history_scan_storcli_variables.scan_storcli_variable_uuid, + history_scan_storcli_variables.scan_storcli_variable_host_uuid, + history_scan_storcli_variables.scan_storcli_variable_source_table, + history_scan_storcli_variables.scan_storcli_variable_source_uuid, + history_scan_storcli_variables.scan_storcli_variable_is_temperature, + history_scan_storcli_variables.scan_storcli_variable_name, + history_scan_storcli_variables.scan_storcli_variable_value, + history_scan_storcli_variables.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_storcli_variables() OWNER TO admin; + +CREATE TRIGGER trigger_scan_storcli_variables + AFTER INSERT OR UPDATE ON scan_storcli_variables + FOR EACH ROW EXECUTE PROCEDURE history_scan_storcli_variables(); diff --git a/scancore-agents/scan-storcli/scan-storcli.xml b/scancore-agents/scan-storcli/scan-storcli.xml new file mode 100644 index 00000000..6117c89b --- /dev/null +++ b/scancore-agents/scan-storcli/scan-storcli.xml @@ -0,0 +1,1011 @@ + + + + + + + + + + + Broadcom (LSI) RAID controller scan agent using the 'storcli64' or 'perccli64' tool. + + + Found: [#!variable!count!#] controller(s). + The thermal sensor named: [#!variable!sensor_name!#], on: [#!variable!sensor_host!#] has not changed. + + + A new Broadcom (AVAGO/LSI) Storage controller has been found. +- Model: ....... [#!variable!model!#] +- Serial Number: [#!variable!serial_number!#] +- Cache Size: .. [#!variable!say_cache_size!#] +- Alarm State: . [#!variable!alarm_state!#] + +Other detected variables: + + - #!variable!name!#: [#!variable!value!#] + A new Broadcom (AVAGO/LSI) Storage controller Battery Backup Unit (BBU) has been found. +- On Controller: .... [#!variable!on_controller!#] +- Model: ............ [#!variable!model!#] +- Serial Number: .... [#!variable!serial_number!#] +- Type: ............. [#!variable!type!#] +- State: ............ [#!variable!state!#] +- Design Capacity: .. [#!variable!design_capacity!#] +- Manufacture Date: . [#!variable!manufacture_date!#] (yyyy/mm/dd) +- Replacement Needed? [#!variable!replacement_needed!#] + +Other detected variables: + + A new Broadcom (AVAGO/LSI) Storage controller Virtual Drive (VD) has been found. +- On Controller: .... [#!variable!on_controller!#] +- ID String: ........ [#!variable!id_string!#] +- Creation Date: .... [#!variable!creation_date!#] +- Data Protection: .. [#!variable!data_protection!#] +- Disk Cache Policy: [#!variable!disk_cache_policy!#] +- Emulation Type: ... [#!variable!emulation_type!#] +- Encryption: ....... [#!variable!encryption!#] +- Blocks: ........... [#!variable!blocks!#] +- Strip Size: ....... [#!variable!strip_size!#] +- Drives Per Span: .. [#!variable!drives_per_span!#] +- Span Depth: ....... [#!variable!span_depth!#] +- SCSI NAA ID: ...... [#!variable!scsi_naa_id!#] (https://en.wikipedia.org/wiki/ISCSI#Addressing) + +Other detected variables: + + A new Broadcom (AVAGO/LSI) Storage controller Drive Group (DG) has been found. +- On Controller: ............. [#!variable!on_controller!#] +- ID String: ................. [#!variable!id_string!#] +- Access: .................... [#!variable!access!#] +- RAID Level: ................ [#!variable!raid_type!#] +- Array Size: ................ [#!variable!array_size!#] +- Array State: ............... [#!variable!array_state!#] +- Consistent: ................ [#!variable!consistent!#] +- Write Cache: ............... [#!variable!write_cache!#] +- Read Cache: ................ [#!variable!read_cache!#] +- Disk Cache: ................ [#!variable!disk_cache!#] +- CacheCade: ................. [#!variable!cachecade!#] +- Scheduled Consistency Check: [#!variable!scheduled_cc!#] +- Raw Cache String: .......... [#!variable!cache!#] + +Other detected variables: + + A new Physical Drive, connected to a Broadcom (AVAGO/LSI) Storage controller, has been found. +- On Controller: ....... [#!variable!on_controller!#] +- Virtual Drive: ....... [#!variable!virtual_drive!#] +- Drive Group: ......... [#!variable!drive_group!#] +- Vendor: .............. [#!variable!vendor!#] +- Model: ............... [#!variable!model!#] +- Serial Number: ....... [#!variable!serial_number!#] +- Capacity: ............ [#!variable!size!#] +- Sector Size: ......... [#!variable!sector_size!#] +- Self-Encrypting Drive? [#!variable!self_encrypting_drive!#] + +Other detected variables: + + A new Broadcom (AVAGO/LSI) Storage controller Cachevault (FBU) has been found. +- On Controller: .... [#!variable!on_controller!#] +- Model: ............ [#!variable!model!#] +- Serial Number: .... [#!variable!serial_number!#] +- Type: ............. [#!variable!type!#] +- State: ............ [#!variable!state!#] +- Design Capacity: .. [#!variable!design_capacity!#] +- Manufacture Date: . [#!variable!manufacture_date!#] +- Replacement Needed? [#!variable!replacement_needed!#] + +Other detected variables: + + +The temperature of the physical drive: [#!variable!serial_number!#] has risen above the critical temperature of: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] has risen above the warning temperature of: [#!variable!high_warning_temperature!# °C]. It will go critical at: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] has dropped below the critical temperature of: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] has dropped the warning temperature of: [#!variable!low_warning_temperature!# °C]. It will go critical at: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] is above the critical temperature of: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] is above the warning temperature of: [#!variable!high_warning_temperature!# °C]. It will go critical at: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] is below the critical temperature of: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] is below the warning temperature of: [#!variable!low_warning_temperature!# °C]. It will go critical at: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] has risen back into a safe temperature range. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] has risen back above the critical low threshold, but it is still in a warning state. It will be marked clear when it rises above: [#!variable!low_warning_temperature!#]. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] has jumped more than: [#!variable!jump!# °C] since the last scan. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] has fallen back into a safe temperature range. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] has dropped back below the critical high threshold, but it is still in a warning state. It will be marked clear when it drops below: [#!variable!high_warning_temperature!#]. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the physical drive: [#!variable!serial_number!#] has dropped more than: [#!variable!jump!# °C] since the last scan. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] is above the high critical temperature of: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] is above the high warning temperature of: [#!variable!high_warning_temperature!# °C]. It will go critical at: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] is below the low critical temperature of: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] is below the low warning temperature of: [#!variable!low_warning_temperature!# °C]. It will go critical at: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] has risen above the high critical temperature of: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] has risen above the high warning temperature of: [#!variable!high_warning_temperature!# °C]. It will go critical at: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] has risen back into a safe temperature range. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] has risen back above the critical low threshold, but it is still in a warning state. It will be marked clear when it rises above: [#!variable!low_warning_temperature!#]. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] has jumped more than: [#!variable!jump!# °C] since the last scan. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] has dropped below the critical temperature of: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] has dropped the warning temperature of: [#!variable!low_warning_temperature!# °C]. It will go critical at: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] has fallen back into a safe temperature range. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] has dropped back below the critical high threshold, but it is still in a warning state. It will be marked clear when it drops below: [#!variable!high_warning_temperature!#]. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the RAID controller: [#!variable!serial_number!#] has dropped more than: [#!variable!jump!# °C] since the last scan. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] is above the critical temperature of: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] is above the warning temperature of: [#!variable!high_warning_temperature!# °C]. It will go critical at: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] is below the critical temperature of: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] is below the warning temperature of: [#!variable!low_warning_temperature!# °C]. It will go critical at: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has risen above the critical temperature of: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has risen above the warning temperature of: [#!variable!high_warning_temperature!# °C]. It will go critical at: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has risen back into a safe temperature range. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has risen back above the critical low threshold, but it is still in a warning state. It will be marked clear when it rises above: [#!variable!low_warning_temperature!#]. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has jumped more than: [#!variable!jump!# °C] since the last scan. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has dropped below the critical temperature of: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has dropped the warning temperature of: [#!variable!low_warning_temperature!# °C]. It will go critical at: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has fallen back into a safe temperature range. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has dropped back below the critical high threshold, but it is still in a warning state. It will be marked clear when it drops below: [#!variable!high_warning_temperature!#]. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has dropped more than: [#!variable!jump!# °C] since the last scan. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] is above the critical temperature of: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] is above the warning temperature of: [#!variable!high_warning_temperature!# °C]. It will go critical at: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] is below the critical temperature of: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] is below the warning temperature of: [#!variable!low_warning_temperature!# °C]. It will go critical at: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] has risen above the critical temperature of: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] has risen above the warning temperature of: [#!variable!high_warning_temperature!# °C]. It will go critical at: [#!variable!high_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] has risen back into a safe temperature range. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] has risen back above the critical low threshold, but it is still in a warning state. It will be marked clear when it rises above: [#!variable!low_warning_temperature!#]. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] has jumped more than: [#!variable!jump!# °C] since the last scan. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] has dropped below the critical temperature of: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] has dropped the warning temperature of: [#!variable!low_warning_temperature!# °C]. It will go critical at: [#!variable!low_critical_temperature!# °C]!: +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] has fallen back into a safe temperature range. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] has dropped back below the critical high threshold, but it is still in a warning state. It will be marked clear when it drops below: [#!variable!high_warning_temperature!#]. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + +The temperature of the Battery Backup Unit (BBU): [#!variable!serial_number!#] has dropped more than: [#!variable!jump!# °C] since the last scan. +- #!variable!name!#: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + + - The temperature of the physical drive: [#!variable!serial_number!#] has changed: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + - The temperature of the Cachevault (FBU): [#!variable!serial_number!#] has changed: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + - The temperature of the BBU: [#!variable!serial_number!#] has changed: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + - The temperature of the controller: [#!variable!serial_number!#] has changed: [#!variable!old_value!# °C] -> [#!variable!new_value!# °C] + - The Virtual Drive: [#!variable!id_string!#]: is performing a background initialization, which is now: [#!variable!new_value!#] complete. + - The Virtual Drive: [#!variable!id_string!#]: has completed its background initialization operation. + +- Controller: [#!variable!serial_number!#]: '#!variable!name!#' has changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + NOTE: This is expected and is no reason for concern. + + + + + While processing data from adapter: [#!variable!adapter!#], which has the serial number: [#!variable!serial_number!#], the drive in virtual drive: [#!variable!virtual_disk!#] in the enclosure: [#!variable!enclosure_id!#] at slot number: [#!variable!slot_number!#] in span: [#!variable!span!#] at row: [#!variable!row!#] initially was found in drive group: [#!variable!old_drive_group!#] but the variable 'Drive position' reports it as being in drive group: [#!variable!new_drive_group!#]. This might be a program error in parsing the output of: [#!variable!shell_call!#]. Please report this error along with the output of that shell call so that we can improve this scan agent. + The RAID controller's properties have changed: +- Model: ....... [#!variable!old_model!#] -> [#!variable!new_model!#] +- Serial Number: [#!variable!old_serial_number!#] -> [#!variable!new_serial_number!#] +- Cache Size: .. [#!variable!old_say_cache_size!#] -> [#!variable!new_say_cache_size!#] +- Alarm State: . [#!variable!old_alarm_state!#] -> [#!variable!new_alarm_state!#] + + - Controller: [#!variable!serial_number!#]: '#!variable!name!#' has changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + - Controller: [#!variable!serial_number!#]: New variable found; #!variable!name!#: [#!variable!value!#] + Processed an invalid drive group: [#!variable!drive_group!#] from the line: [#!variable!line!#]! + - Controller: [#!variable!serial_number!#]: '#!variable!name!#' has returned: [#!variable!new_value!#] + - Controller: [#!variable!serial_number!#]: '#!variable!name!#' has vanished! + The controller: [#!variable!model!#] with the serial number: [#!variable!serial_number!#] has vanished! + The RAID controller has returned: +- Model: ....... [#!variable!new_model!#] +- Serial Number: [#!variable!new_serial_number!#] +- Cache Size: .. [#!variable!new_say_cache_size!#] +- Alarm State: . [#!variable!new_alarm_state!#] + + The RAID controller's Battery Backup Unit (BBU) properties have changed: +- On Controller: .... [#!variable!old_on_controller!#] -> [#!variable!new_on_controller!#] +- Model: ............ [#!variable!old_model!#] -> [#!variable!new_model!#] +- Serial Number: .... [#!variable!old_serial_number!#] -> [#!variable!new_serial_number!#] +- Type: ............. [#!variable!old_type!#] -> [#!variable!new_type!#] +- State: ............ [#!variable!old_state!#] -> [#!variable!new_state!#] +- Design Capacity: .. [#!variable!old_design_capacity!#] -> [#!variable!new_design_capacity!#] +- Manufacture Date: . [#!variable!old_manufacture_date!#] -> [#!variable!new_manufacture_date!#] (yyyy/mm/dd) +- Replacement Needed? [#!variable!old_replacement_needed!#] -> [#!variable!new_replacement_needed!#] + + The RAID controller's Battery Backup Unit (BBU) has returned: +- On Controller: .... [#!variable!old_on_controller!#] -> [#!variable!new_on_controller!#] +- Model: ............ [#!variable!old_model!#] -> [#!variable!new_model!#] +- Serial Number: .... [#!variable!old_serial_number!#] -> [#!variable!new_serial_number!#] +- Type: ............. [#!variable!old_type!#] -> [#!variable!new_type!#] +- State: ............ [#!variable!old_state!#] -> [#!variable!new_state!#] +- Design Capacity: .. [#!variable!old_design_capacity!#] -> [#!variable!new_design_capacity!#] +- Manufacture Date: . [#!variable!old_manufacture_date!#] -> [#!variable!new_manufacture_date!#] (yyyy/mm/dd) +- Replacement Needed? [#!variable!old_replacement_needed!#] -> [#!variable!new_replacement_needed!#] + + - The BBU: [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + - The BBU: [#!variable!serial_number!#]: '#!variable!name!#' has returned: [#!variable!new_value!#] + - The BBU: [#!variable!serial_number!#]: '#!variable!name!#' has vanished! + - A new variable was found on the BBU: [#!variable!serial_number!#] = [#!variable!value!#] + - The BBU: [#!variable!bbu_serial_number!#] on the RAID controller: [#!variable!controller_serial_number!#] has vanished! + The RAID controller's Virtual Drive (VD) properties have changed: +- On Controller: .... [#!variable!old_on_controller!#] -> [#!variable!new_on_controller!#] +- ID String: ........ [#!variable!old_id_string!#] -> [#!variable!new_id_string!#] +- Creation Date: .... [#!variable!old_creation_date!#] -> [#!variable!new_creation_date!#] +- Data Protection: .. [#!variable!old_data_protection!#] -> [#!variable!new_data_protection!#] +- Disk Cache Policy: [#!variable!old_disk_cache_policy!#] -> [#!variable!new_disk_cache_policy!#] +- Emulation Type: ... [#!variable!old_emulation_type!#] -> [#!variable!new_emulation_type!#] +- Encryption: ....... [#!variable!old_encryption!#] -> [#!variable!new_encryption!#] +- Blocks: ........... [#!variable!old_blocks!#] -> [#!variable!new_blocks!#] +- Strip Size: ....... [#!variable!old_strip_size!#] -> [#!variable!new_strip_size!#] +- Drives Per Span: .. [#!variable!old_drives_per_span!#] -> [#!variable!new_drives_per_span!#] +- Span Depth: ....... [#!variable!old_span_depth!#] -> [#!variable!new_span_depth!#] +- SCSI NAA ID: ...... [#!variable!old_scsi_naa_id!#] -> [#!variable!new_scsi_naa_id!#] + + The RAID controller's Virtual Drive (VD) has returned: +- On Controller: .... [#!variable!old_on_controller!#] -> [#!variable!new_on_controller!#] +- ID String: ........ [#!variable!old_id_string!#] -> [#!variable!new_id_string!#] +- Creation Date: .... [#!variable!old_creation_date!#] -> [#!variable!new_creation_date!#] +- Data Protection: .. [#!variable!old_data_protection!#] -> [#!variable!new_data_protection!#] +- Disk Cache Policy: [#!variable!old_disk_cache_policy!#] -> [#!variable!new_disk_cache_policy!#] +- Emulation Type: ... [#!variable!old_emulation_type!#] -> [#!variable!new_emulation_type!#] +- Encryption: ....... [#!variable!old_encryption!#] -> [#!variable!new_encryption!#] +- Blocks: ........... [#!variable!old_blocks!#] -> [#!variable!new_blocks!#] +- Strip Size: ....... [#!variable!old_strip_size!#] -> [#!variable!new_strip_size!#] +- Drives Per Span: .. [#!variable!old_drives_per_span!#] -> [#!variable!new_drives_per_span!#] +- Span Depth: ....... [#!variable!old_span_depth!#] -> [#!variable!new_span_depth!#] +- SCSI NAA ID: ...... [#!variable!old_scsi_naa_id!#] -> [#!variable!new_scsi_naa_id!#] + + - The Virtual Drive: [#!variable!id_string!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + - The Virtual Drive: [#!variable!id_string!#]: '#!variable!name!#' has returned: [#!variable!new_value!#] + - The Virtual Drive: [#!variable!id_string!#]: '#!variable!name!#' has vanished! + - A new variable was found on the Virtual Drive: [#!variable!id_string!#] = [#!variable!value!#] + The Virtual Drive: [#!variable!id_string!#] on the RAID controller: [#!variable!controller_serial_number!#] has vanished! + The RAID controller's Drive Group (DG) properties have changed: +- ID String: ................. [#!variable!old_id_string!#] -> [#!variable!new_id_string!#] +- Access: .................... [#!variable!old_access!#] -> [#!variable!new_access!#] +- RAID Level: ................ [#!variable!old_raid_type!#] -> [#!variable!new_raid_type!#] +- Array Size: ................ [#!variable!old_array_size!#] -> [#!variable!new_array_size!#] +- Array State: ............... [#!variable!old_array_state!#] -> [#!variable!new_array_state!#] +- Consistent: ................ [#!variable!old_consistent!#] -> [#!variable!new_consistent!#] +- Write Cache: ............... [#!variable!old_write_cache!#] -> [#!variable!new_write_cache!#] +- Read Cache: ................ [#!variable!old_read_cache!#] -> [#!variable!new_read_cache!#] +- Disk Cache: ................ [#!variable!old_disk_cache!#] -> [#!variable!new_disk_cache!#] +- CacheCade: ................. [#!variable!old_cachecade!#] -> [#!variable!new_cachecade!#] +- Scheduled Consistency Check: [#!variable!old_scheduled_cc!#] -> [#!variable!new_scheduled_cc!#] +- Raw Cache String: .......... [#!variable!old_cache!#] -> [#!variable!new_cache!#] + + The RAID controller's Drive Group (DG) has returned: +- ID String: ................. [#!variable!old_id_string!#] -> [#!variable!new_id_string!#] +- Access: .................... [#!variable!old_access!#] -> [#!variable!new_access!#] +- RAID Level: ................ [#!variable!old_raid_type!#] -> [#!variable!new_raid_type!#] +- Array Size: ................ [#!variable!old_array_size!#] -> [#!variable!new_array_size!#] +- Array State: ............... [#!variable!old_array_state!#] -> [#!variable!new_array_state!#] +- Consistent: ................ [#!variable!old_consistent!#] -> [#!variable!new_consistent!#] +- Write Cache: ............... [#!variable!old_write_cache!#] -> [#!variable!new_write_cache!#] +- Read Cache: ................ [#!variable!old_read_cache!#] -> [#!variable!new_read_cache!#] +- Disk Cache: ................ [#!variable!old_disk_cache!#] -> [#!variable!new_disk_cache!#] +- CacheCade: ................. [#!variable!old_cachecade!#] -> [#!variable!new_cachecade!#] +- Scheduled Consistency Check: [#!variable!old_scheduled_cc!#] -> [#!variable!new_scheduled_cc!#] +- Raw Cache String: .......... [#!variable!old_cache!#] -> [#!variable!new_cache!#] + + - The Drive Group: [#!variable!id_string!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + - The Drive Group: [#!variable!id_string!#]: '#!variable!name!#' has returned: [#!variable!new_value!#] + - The Drive Group: [#!variable!id_string!#]: '#!variable!name!#' has vanished! + The Physical Drive (PD) properties have changed: +- On Controller: ....... [#!variable!old_on_controller!#] -> [#!variable!new_on_controller!#] +- Virtual Drive: ....... [#!variable!old_virtual_drive!#] -> [#!variable!new_virtual_drive!#] +- Drive Group: ......... [#!variable!old_drive_group!#] -> [#!variable!new_drive_group!#] +- Enclosure ID: ........ [#!variable!old_enclosure_id!#] -> [#!variable!new_enclosure_id!#] +- Slot Number: ......... [#!variable!old_slot_number!#] -> [#!variable!new_slot_number!#] +- Vendor: .............. [#!variable!old_vendor!#] -> [#!variable!new_vendor!#] +- Model: ............... [#!variable!old_model!#] -> [#!variable!new_model!#] +- Serial Number: ....... [#!variable!old_serial_number!#] -> [#!variable!new_serial_number!#] +- Capacity: ............ [#!variable!old_size!#] -> [#!variable!new_size!#] +- Sector Size: ......... [#!variable!old_sector_size!#] -> [#!variable!new_sector_size!#] +- Self-Encrypting Drive? [#!variable!old_self_encrypting_drive!#] -> [#!variable!new_self_encrypting_drive!#] + + The Physical Drive (PD) has returned: +- On Controller: ....... [#!variable!old_on_controller!#] -> [#!variable!new_on_controller!#] +- Virtual Drive: ....... [#!variable!old_virtual_drive!#] -> [#!variable!new_virtual_drive!#] +- Drive Group: ......... [#!variable!old_drive_group!#] -> [#!variable!new_drive_group!#] +- Enclosure ID: ........ [#!variable!old_enclosure_id!#] -> [#!variable!new_enclosure_id!#] +- Slot Number: ......... [#!variable!old_slot_number!#] -> [#!variable!new_slot_number!#] +- Vendor: .............. [#!variable!old_vendor!#] -> [#!variable!new_vendor!#] +- Model: ............... [#!variable!old_model!#] -> [#!variable!new_model!#] +- Serial Number: ....... [#!variable!old_serial_number!#] -> [#!variable!new_serial_number!#] +- Capacity: ............ [#!variable!old_size!#] -> [#!variable!new_size!#] +- Sector Size: ......... [#!variable!old_sector_size!#] -> [#!variable!new_sector_size!#] +- Self-Encrypting Drive? [#!variable!old_self_encrypting_drive!#] -> [#!variable!new_self_encrypting_drive!#] + + - The Physical Drive (PD): [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + - The Physical Drive (PD): [#!variable!serial_number!#]: '#!variable!name!#' has returned: [#!variable!new_value!#] + - A new variable was found on the Physical Drive (PD): [#!variable!serial_number!#] = [#!variable!value!#] + - Physical Drive: [#!variable!serial_number!#]: '#!variable!name!#' has vanished! + - The Physical Drive: [#!variable!physical_disk_serial_number!#] on the RAID controller: [#!variable!controller_serial_number!#] has vanished! + The RAID controller's Cachevault (FBU) properties have changed: +- On Controller: .... [#!variable!old_on_controller!#] -> [#!variable!new_on_controller!#] +- Model: ............ [#!variable!old_model!#] -> [#!variable!new_model!#] +- Serial Number: .... [#!variable!old_serial_number!#] -> [#!variable!new_serial_number!#] +- Type: ............. [#!variable!old_type!#] -> [#!variable!new_type!#] +- State: ............ [#!variable!old_state!#] -> [#!variable!new_state!#] +- Design Capacity: .. [#!variable!old_design_capacity!#] -> [#!variable!new_design_capacity!#] +- Manufacture Date: . [#!variable!old_manufacture_date!#] -> [#!variable!new_manufacture_date!#] (yyyy/mm/dd) +- Replacement Needed? [#!variable!old_replacement_needed!#] -> [#!variable!new_replacement_needed!#] + + The RAID controller's Cachevault (FBU) has returned: +- On Controller: .... [#!variable!old_on_controller!#] -> [#!variable!new_on_controller!#] +- Model: ............ [#!variable!old_model!#] -> [#!variable!new_model!#] +- Serial Number: .... [#!variable!old_serial_number!#] -> [#!variable!new_serial_number!#] +- Type: ............. [#!variable!old_type!#] -> [#!variable!new_type!#] +- State: ............ [#!variable!old_state!#] -> [#!variable!new_state!#] +- Design Capacity: .. [#!variable!old_design_capacity!#] -> [#!variable!new_design_capacity!#] +- Manufacture Date: . [#!variable!old_manufacture_date!#] -> [#!variable!new_manufacture_date!#] (yyyy/mm/dd) +- Replacement Needed? [#!variable!old_replacement_needed!#] -> [#!variable!new_replacement_needed!#] + + - The Cachevault (FBU): [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + - The Cachevault (FBU): [#!variable!serial_number!#]: '#!variable!name!#' has returned: [#!variable!new_value!#] + - The Cachevault (FBU): [#!variable!serial_number!#]: '#!variable!name!#' has vanished! + - A new variable was found on the Cachevault (FBU): [#!variable!serial_number!#] = [#!variable!value!#] + - The Cachevault (FBU): [#!variable!cachevault_serial_number!#] on the RAID controller: [#!variable!controller_serial_number!#] has vanished! + - The Drive Group: [#!variable!id_string!#]: '#!variable!name!#' has been found: [#!variable!new_value!#] + +- The Physical Drive (PD): [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + If this ticks up by '1', and this hasn't changed recently before, it is generally safe to ignore. + However, if the error count jumps by more than one, or increments more than once a month, or climbs above 5 or 6, then the drive may be in the early stages of failing. + If this is the case and your hardware vendor allows for pre-failure replacement, you may with to request a replacement. + + +- The Physical Drive (PD): [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + The error counters generally shouldn't change. Please investigate the cause of the error and replace the drive, if necessary. + NOTE: Unless another alert indicates otherwise, the drive has *not* failed. + + +- The RAID controller: [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + Correctable errors should be very rare, and though they don't pose an immediate threat, should be investigated as soon as possible. + + +- The RAID controller: [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + Uncorrectable errors are likely an indication that the controller is failing. + Please contact your hardware vendor and plan to replace the controller at your earliest opportunity. + Servers should be migrated to the peer as soon as possible. + + +- The RAID controller: [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + The severity of this alert depends on the new state. if the new state is 'Optimal', then there is no cause for concern. + Most other states are likely worth investigating as soon as possible as the controller state should never change under normal conditions. + + +- The BBU: [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + The battery should never go into an over-charge state. This may indicate the pack is about to fail. + Please investigate and replace, if necessary, at your earliest convenience. + NOTE: If the pack fails, write performance will be impacted! + + +- The BBU: [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + If there is a known over temperature event, then this may indicate that the battery has heated up along with other components. + If the battery pack is the only device to get hot, then it may indicate that the pack is failing. + Please investigate and replace, if necessary, at your earliest convenience. + NOTE: If the pack fails, write performance will be impacted! + + +- The BBU: [#!variable!serial_number!#]: '#!variable!name!#' changed: [#!variable!old_value!#] -> [#!variable!new_value!#] + Please investigate and replace, if necessary, at your earliest convenience. + NOTE: If the pack fails, write performance will be impacted! + + +- The RAID controller: [#!variable!serial_number!#] is in the database: [#!variable!count!#] times. This shouldn't happen. + NOTE: Existing controller information will be purged. The installed controller (if it still exists) will be in detected + and recorded in the comming scan. + + + + The 'storcli64' program was not found at: [#!variable!path!#], exiting. + The 'storcli64' program was found at: [#!variable!path!#], but it is not executable. exiting. + No LSI-based RAID controllers were found, exiting. + #!free!# + #!free!# + Failed to find the serial number for the adapter: [#!variable!adapter!#]. Please check the output of '#!data!path::storcli64!# #!data!sys::arguments::controller_info!#' and look for the 'Serial Number = X' string. Exiting. + The battery backup unit (BBU) with the serial number: [#!variable!serial_number!#] didn't have a reported host controller serial number. This is probably a program error, sorry about that. + The controller with serial number: [#!variable!serial_number!#] could not be converted to a controller UUID. This is probably a program error, sorry about that. + The Cachevault (FBU) with the serial number: [#!variable!serial_number!#] didn't have a reported host controller serial number. This is probably a program error, sorry about that. + The virtual drive (VD) with the ID string: [#!variable!id_string!#] didn't have a reported host controller serial number. This is probably a program error, sorry about that. + The drive group (DG) with the ID string: [#!variable!id_string!#] didn't have a reported host controller serial number. This is probably a program error, sorry about that. + The physical drive (PV) with the serial number: [#!variable!serial_number!#] didn't have a reported host controller serial number. This is probably a program error, sorry about that. + Failed to find the serial number for the physical drive (PV) in the virtual drive: [#!variable!virtual_drive!#] and drive group: [#!variable!drive_group!#] in enclosure: [#!variable!enclosure_id!#] in slot: [#!variable!slot_number!#]. This is probably a program error, sorry about that. + Old UUID for drive group: [#!variable!drive_group!#] found. This is likely a program error. + Controller UUID for the drive group with UUID: [#!variable!drive_group_uuid!#] not found. This is likely a program error. + Non-numeric value in a numeric variable; virtual drive blocks: [#!variable!virtual_drive_blocks!#], drives per span: [#!variable!drives_per_span!#], or span depth: [#!variable!span_depth!#]. This is likely a program error. + + + Starting #!string!scan_storcli_brand_0001!#: + + + Bytes + Hours + Hour + Minutes + Minute + Seconds + Second + N/A + Always Write-Back + Write-Back + Write-Through + Sectors + Gbps + + + + Access Policy + Alarm + Allow Boot With Preserved Cache? + Allow Controller Encryption? + Allow Mixed Redundancy On An Array? + Any Offline VD Cache Preserved? + One Or More Premium Features Enabled? + Autodetect Backplane + Automatic Rebuild + Backend Port Count + Background Initialization Rate (Percent) + Battery Relearn Interval + Battery Warning Enabled + BBU/FBU Connected? + BBU/FBU Status + BBU/FBU Supported? + Virtual Drives Presented to BIOS + Controller BIOS Version + Failed To Detect Controller BIOS At Boot? + Controller Boot Block Version + Boot Volume Capable? + Boot Volume Supported? + Controller Boot Loader Version + Mainboard BUS Number + Cachevault (FBU) Flash Size + Controller ASIC Revision + Controller Cluster Active? + Controller Cluster Permitted? + Controller Cluster Supported? + User Configurable "Abort Consistency Check on Error"? + User Configurable "Alarm Control"? + User Configurable "Background Initialization Rate"? + User Configurable "Block SSD Write Disk Cache Change"? + User Configurable "Consistency Check Rate"? + User Configurable "Patrol Read Rate"? + User Configurable "Rebuild Rate"? + User Configurable "Reconstruction Rate"? + Consistency Check Rate (Percent) + Consistency Check Interval + Controller Number + Controller Has Booted Into Safe-Mode? + Controller Reboot Required For Security Operation? + Controller Status + Cachecade Size + Current Size Of Firmware Cache + Dedicated Hot-Spare Supported? + Dedicated Hot-Spare Limited? + Automatic Enhanced Import Default Setting + Break Mirror RAID Support Default Setting + Write-Back Caching With Bad BBU/FBU Default Setting + Cached IO Enabled By Default + Default Coercion Mode Setting + Direct Physical Disk Mapping Default Setting + Dirty Activity LED Default Setting + Disable "Human Interface Infrastructure (HII)" Default Setting + Disable "Join Mirror" Default Setting + Disable "Online Reset Controller To Defaults" Default Setting + Disable "Puncturing" Default Setting + "Enable Crash Dump" Default Setting + "Enable LED Header" Default Setting + Logical Device Bad Block Management Enabled By Default + Enable Shield State Default Setting + Expose Enclosure Device Default Setting + Drive Activity LED Enabled By Default + Maintain Physical Disk Fail History Default Setting + Maximum Chained Enclosures Default Setting + Physical Layer Polarity Default Setting + Physical Layer Polarity Split Default Setting + Power Saving Option Default Setting + Default Read Policy + Restore Hot-Spare On Physical Disk Insertion Default Setting + Default SMART Mode + Default Disk Spin-Down Time + Default Strip Size + "Terminal Log In Flash" Default Setting + "Treat Single Span RAID 1E As RAID 10" Default Setting + Default Uncertified Hard Disk Drive Policy + Default Virtual Drive Power Save Policy + Default Write Cache Policy + Default "Zero-Based Enclosure Enumeration" Policy + Default Zero-Channel RAID Configuration + Delay Between Spin-Up Groups + Delay during POST (seconds) + Deny "Clear"? + Deny "Consistency Check"? + Deny "Force Failed"? + Deny "Force Good/Bad"? + Deny "Missing Replace"? + Deny "Physical Disk Locate"? + Deny "SCSI Pass-Through"? + Deny "SATA Tunneling Protocol Pass-Through"? + Deny "Serial Management Protocol Pass-Through"? + Deny "Virtual Drive Locate"? + Controller Interface + Controller Device Number + Direct-Connect Drives Spun-Up Per Minute + Disable "Online Controller Reset Policy"? + Disable "Premium Feature Key (PFK) Change"? + Virtual Drive Cache Policy Supported? + Drive Coercion Mode + Number Of Drive Groups + Linux Driver + Linux Driver Version + ECC Bucket Count + ECC Bucket Leak Rate + ECC Bucket Size + Enable BIOS? + Enable 'Ctrl + R' Utility? + Enable JBOD Arrays? + Enable Pre-boot Command Line Interface? + Enable WebBIOS Utility? + Expose Enclosure Device Policy? + Extended Logical Device Supported? + Failed To Get Lock Key On Bootup? + Firmware Package Build + Firmware Version + Flash Size + Flush Time + Force Offline Supported? + Force Online Supported? + Force Rebuild Supported? + Foreign Config Import Supported? + Front-End (External) Port Count + Function Number + Timestamps in GMT? + Global Hot Spares Supported? + Headless Mode Supported? + Controller to Mainboard Interface + Image Name Pending Write + User-Configurable IO Policy? + Load Balancing Mode + Lock Key Assigned? + Lock Key Has Not Been Backed Up? + Maintain Physical Disk Fail History Policy + Controller Manufacture Date + Maximum Arms Per Virtual Drive + Maximum Number Of Arrays + Maximum Configurable Cachecade Size + Maximum Data Transfer Size + Maximum Number of Drives To Spin-Up At A Time + Maximum Number Of Virtual Drives + Maximum Number Of Parallel Commands + Maximum Scatter-Gather Element Count + Maximum Spans Per Virtual Drive + Maximum Strip Size + Maximum Strips Per IO + Maximum Transportable Virtual Drives + Maximum Virtual Drives Per Array + Memory Correctable Error Count + Memory Uncorrectable Error Count + Minimum Strip Size + Mix Drive Types In Enclosure? + Mixing SAS and SATA Platter-Based Drives In Virtual Drive? + Mixing SAS and SATA Solid State Drives In Virtual Drive? + Mixing SSDs And HDDs In Virtual Drive + Controller Model + Physical Disk Native Command Queuing Supported? + Next Schedule Battery Learn Cycle Start + Next Consistency Check Start + Next Patrol Read Start + NV Data Version + NV RAM Size + Controller OEM Identification + On-Board Expander? + On-Board RAM Size + Patrol Read Rate (Percent) + Patrol Read Interval + PCI Bus Address + Virtual Drive Performance Metrics Supported? + Performance Mode + Point In Time Progress? + Power Saving? + Preboot Command Line Interface Utility Version + RAID Levels Supported + Real-Time Scheduler? + Rebuild Rate (Percent) + Virtual Drive Reconstruction Supported? + Optimize/Reorder Host Requests? + Restore Hot-Spare on Insertion? + Hot-Spares Can Be Reverted? + Controller Rework Date + Roll-Back Operation In Progress + Safe ID + SAS Address + SAS Disabled? + Security Key Assigned? + Security Subsystem Class Policy Is Write-Back? + Self-Diagnostics Supported? + Serial Debugger? + Set Power State For Configuration? + Snapshot Enabled? + Spanning Supported? + Spin-Down Mode + Stop BIOS On Error? + Sub-Device ID + Sub-Vendor ID + Support Allowed Operations? + Boot-Time Premium Feature Key Change Supported? + Break Mirror Supported? + Support Complex Programmable Logic Device (CPLD) Update? + Support Configure Auto-Balance? + Support Configure Page Model? + Support Diagnostics Results? + Support Disable Immediate IO? + Support Discard Cache During Logical Disk Delete? + Support Drive Activity LED Settings? + Support Emergency Spares? + Support Emulated Spares? + Support Enclosure Enumeration? + Support Enhanced Foreign Configuration Import? + Support External Enclosures? + Support External Security Key Management? + Support "Fast Path" Premium Feature? + Support "Flush Write Verify"? + Support Force Flash? + Support Forcing 512-Byte Emulated Sector Sizes? + Support JBOD Arrays? + Support JBOD Write-Cache? + Large IO Supported? + Large Queue Depth Supported? + Support Logical Device Bad Block Management Information? + Support Logical Disk Protection Information, Type 1 + Support Logical Disk Protection Information, Type 2 + Support Logical Disk Protection Information, Type 3 + "Maintenance Mode" Supported? + Support "Maximum Rate SATA"? + Support More Than 8 Physical Layers? + Support Multipath? + Support Odd And Even Drive Count In RAID 1E? + Performance Tuning Supported? + Physical Disk Firmware Download Supported? + Maximum Power Save With Cache Supported? + Power Save Supported? + Premium Feature Keys Supported? + Support "Protection Information"? + Support "Reset Now"? + Support SCSI Enclosure Service Monitoring? + Support Security? + Support Security On JBOD? + Support Security Subsystem Class Association? + Support Security Subsystem Class Write-Back? + Support Setting Link Speed? + Support Shield State? + Support SSD Patrol Read? + Support Suspect/Resume of Background Operations? + Support T10 Power States? + Temperature Supported? + Support Online Capacity Expansion Without Adding Drives? + Support Uneven Spans? + Support Virtual Drive Cache Bypass? + Support Virtual Drive Discard Cache During Logical Disk Deletion? + Support "Virtual Drive Hide"? + Supported Drive Types? + Temperature Sensor For Controller? + Temperature Sensor For "RAID On Chip" (ROC) Processor? + Topology Type + Trusted Platform Module (TPM) + Upgradable Complex Programmable Logic Device (CPLD) + Upgrade Key + Use Drive Activity LED For Locate? + Vendor ID + Virtual Drive Read Policy + Virtual Drive Write Policy + WebBIOS Version + RAID On Chip (ROC) Temperature + + + Absolute State Of Charge (Percent) + Application Data + Automatic Learning Mode + Automatic Learning Interval + Average Time To Empty + Average Time To Full + Battery Backup Charge (Hold-Up) Time + Battery Field Replaceable Unit (FRU) Number + Battery Missing? + Battery State + "Cache Offload" Premium Feature Required? + Charger System Controller + Charger System State + Charging Current + Charging Status + Charging Terminated? + Current + Charge/Discharge Cycle Count + Date Manufactured + Design Capacity + Design Voltage + Battery Chemistry + Device Name + Discharging? + Full Charge Capacity + Fully Charged? + Fully Discharged? + i2c Errors Detected? + Initialized? + Learn Cycle Active? + Learn Cycle Requested? + Learn Cycle Status + Learn Cycle Timeout? + Learn Cycle Delay Interval + Manufacturer Model Name + Maximum Errors + Module Microcode Update Required? + Next Scheduled Learn Cycle + No Space To Cache Offload? + Over Charged? + Over Temperature? + Battery Unit Is About To Fail? + Battery Unit Statistics Configuration + Learn Cycle Required? + Relative State Of Charge + Remaining Capacity + Remaining Capacity Alarm + Remaining Capacity Low? + Remaining Time Alarm? + Remaining Time Alarm Threshold + Replacement Required? + Runtime To Empty + Specification Information + Temperature Status + Terminate Discharge Alarm? + Transparent Learn + Type + Voltage Status + + + Capacitance (Percent) + Cachevault Pack Energy + Remaining Reserve Space + TMM Field Replaceable Unit Number + + + Active Operations + Creation Date + Creation Time + Data Protection? + Emulation Type + Encryption + Exposed To The Operating System? + Logical Disk Is Ready For Operating System Requests? + Number Of Blocks + Number Of Drives Per Span + On Controller With Serial Number + SCSI Network Address Authority (NAA) ID + Span Depth + Strip Size + Initial Write-Cache Setting + + + Access + Array Size + Array State + Raw Cache Value String + Cachecade Enabled? + Consistent? + Disk Cache + RAID Type + Read Cache + Scheduled Consistency Check? + Write Cache + + + Bad Block Management (BBM) Error Count + Vendor Certified Drive? + Coerced Size + Commissioned Spare? + Connected Port Number + Connector Name + Device ID + Drive Link Speed + Drive Type + Drive Model Number + Drive Capacity + Emergency Spare? + Enclosure Position + Firmware Release Number + Firmware Revision + Interface Type + Last "Predictive Failure" Event Sequence Number + Interface Link Speed + Drive Is Locked? + Drive Manufacturer + Media Error Count + Drive Model Number + Flash (NAND) Vendor + Needs External Key Management Attention? + Non-Coerced Size + "Other" Error Count + Predictive Failure Count + Protection Information + Protection Information Eligible? + Raw Size + Row + SAS Port #0 Interface Speed + SAS Port #0 Port Status + SAS Port #0 SAS Address + SAS Port #1 Interface Speed + SAS Port #1 Port Status + SAS Port #1 SAS Address + Sector Size + Drive Encrypted? + Self-Encrypting Drive (SED) Capable? + Self-Encrypting Drive (SED) Enabled? + Self-Encrypting Drive (SED)? + Sequence Number + Drive Serial Number + Shield Counter + SMART Alert Flagged By Drive? + Span + Spun-Up? + State + Successful Diagnostics Completion On Date? + Wide Port Capable? + World Wide Name (WWN) + Drive's Temperature + + + diff --git a/tools/test.pl b/tools/test.pl index cc0e8f39..ed6a6103 100755 --- a/tools/test.pl +++ b/tools/test.pl @@ -1,43 +1,37 @@ #!/usr/bin/perl # - -use strict; + use warnings; -use Anvil::Tools; -use Data::Dumper; -use String::ShellQuote; -use utf8; -binmode(STDERR, ':encoding(utf-8)'); -binmode(STDOUT, ':encoding(utf-8)'); +use strict; -my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; -my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; -if (($running_directory =~ /^\./) && ($ENV{PWD})) -{ - $running_directory =~ s/^\./$ENV{PWD}/; -} - -# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. -$| = 1; - -my $anvil = Anvil::Tools->new(); -$anvil->Log->level({set => 2}); -$anvil->Log->secure({set => 1}); - -$anvil->data->{switches}{'shutdown'} = ""; -$anvil->data->{switches}{boot} = ""; -$anvil->data->{switches}{server} = ""; -$anvil->Get->switches; - -print "Connecting to the database(s);\n"; -$anvil->Database->connect({debug => 3}); -$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, secure => 0, key => "log_0132"}); - -my $agent = "scan-apc-ups"; -my $schema_file = $anvil->data->{path}{directories}{scan_agents}."/".$agent."/".$agent.".sql"; -my $tables = $anvil->Database->get_tables_from_schema({debug => 2, schema_file => $schema_file}); -print "Schema file: [".$schema_file."]\n"; -foreach my $table (@{$tables}) +my $sysstat_directory = "/var/log/sa/"; +my $hostname = `hostname | cut -f 1 -d .`; + +opendir(my $directory_handle, $sysstat_directory) || die "Can't locate ".$sysstat_directory."\n"; + +my @file_list = grep { /^sa[0-9]./ } readdir($directory_handle); + +printf "Hostname is ... ".$hostname."\n"; +foreach my $filename (sort {$a cmp $b} @file_list) { - print "- ".$table."\n"; -} + #printf "Filepath: ....".$sysstat_directory.$filepath."\n" + my $shell_call = "sadf -dht ".$sysstat_directory.$filename." -- -S -u -r -p -q -n DEV"; + printf "Shell Call - ... ".$shell_call."\n"; + open(my $file_handle, "$shell_call 2>&1 |") || die "Failed to parse output of [".$shell_call."].\n"; + while (<$file_handle>) + { + chomp; + my $csv_line = $_; + + if ($csv_line =~ /$hostname/) + { + #printf "CSV Line... ".$csv_line."\n"; + printf "Variable Match!\n"; + } + if ($csv_line =~ 'thinkpad-06HCV0') + { + printf "String Match!\n"; + } + } + +} \ No newline at end of file