Local modifications to ClusterLabs/Anvil by Alteeve
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

10185 lines
516 KiB

#!/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();
# 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 => 2, 'print' => 1, key => "log_0115", variables => { program => $THIS_FILE }});
# Read switches
$anvil->data->{switches}{force} = 0;
$anvil->data->{switches}{purge} = 0;
$anvil->Get->switches;
# If we're disabled and '--force' wasn't used, exit.
if (($anvil->data->{scancore}{'scan-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 => 2, 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);
# Shut down.
$anvil->ScanCore->agent_shutdown({agent => $THIS_FILE});
#############################################################################################################
# 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") && (lc($value) ne "absent"))
{
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-storcli'}{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-storcli'}{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},
}});
}
# Store
my $temperature_uuid = "";
if (exists $anvil->data->{old}{temperature}{$variable}{$serial_number})
{
$temperature_uuid = $anvil->data->{old}{temperature}{$variable}{$serial_number}{temperature_uuid};
delete $anvil->data->{old}{temperature}{$variable}{$serial_number};
}
$temperature_uuid = $anvil->Database->insert_or_update_temperature({
cache => $anvil->data->{'scan-storcli'}{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 }});
}
}
# Now, if any undeleted old entries remain, delete them from the database.
* Created Database->get_bridges() that, surprise, loads data from the 'bridges' table. * Started work on Get->available_resources() that will take an 'anvil_uuid' and figure out what resources are still available for use by new servers or that can be added to existing servers. * Fixed a bug in ScanCore->agent_startup() where tables weren't being generated properly from the agent's SQL file. * Made Storage->change_mode() return silently if it's called without a mode being passed. This happens frequently and is harmless so it's not worth filling the logs with errors. * Renamed the 'start_time' key to 'at_start' when recording files' MD5 sums in Storage->record_md5sums and ->check_md5sums. * When we moved the directory scan logic out of the 'scancore' daemon and into 'Storage->scan_directory', the logic to record scan agent names in 'scancore::agent::<file>' was removed. This broke a few things and, so, it was restored when it was found that a file starts with 'scan-' and the directory matches the scancore agent directory. * Moved the 'scancore' daemon's 'load_agent_strings' to 'Words' * Updated Words->parse_banged_string() to look for variables in the format 'value=X:units=Y' and translate it properly. * Fixed a bug in scan-ipmitool where discovered sensor INSERT SQL queries were queued, but not committed. * Fixed a bug in scan-storcli where a while loop was broken, preventing execution. * Fixed a bug in the 'scancore' daemon where it wouldn't exit if sums changed. Fixed a bug where alerts weren't being sent between loops. Fixed a bug where command-line log level wasn't surviving inside the main loop. Signed-off-by: Digimer <digimer@alteeve.ca>
4 years ago
foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{old}{temperature}})
{
* Created Database->get_bridges() that, surprise, loads data from the 'bridges' table. * Started work on Get->available_resources() that will take an 'anvil_uuid' and figure out what resources are still available for use by new servers or that can be added to existing servers. * Fixed a bug in ScanCore->agent_startup() where tables weren't being generated properly from the agent's SQL file. * Made Storage->change_mode() return silently if it's called without a mode being passed. This happens frequently and is harmless so it's not worth filling the logs with errors. * Renamed the 'start_time' key to 'at_start' when recording files' MD5 sums in Storage->record_md5sums and ->check_md5sums. * When we moved the directory scan logic out of the 'scancore' daemon and into 'Storage->scan_directory', the logic to record scan agent names in 'scancore::agent::<file>' was removed. This broke a few things and, so, it was restored when it was found that a file starts with 'scan-' and the directory matches the scancore agent directory. * Moved the 'scancore' daemon's 'load_agent_strings' to 'Words' * Updated Words->parse_banged_string() to look for variables in the format 'value=X:units=Y' and translate it properly. * Fixed a bug in scan-ipmitool where discovered sensor INSERT SQL queries were queued, but not committed. * Fixed a bug in scan-storcli where a while loop was broken, preventing execution. * Fixed a bug in the 'scancore' daemon where it wouldn't exit if sums changed. Fixed a bug where alerts weren't being sent between loops. Fixed a bug where command-line log level wasn't surviving inside the main loop. Signed-off-by: Digimer <digimer@alteeve.ca>
4 years ago
foreach my $serial_number (sort {$a cmp $b} keys %{$anvil->data->{old}{temperature}{$variable}})
{
my $temperature_uuid = $anvil->data->{old}{temperature}{$variable}{$serial_number}{temperature_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { temperature_uuid => $temperature_uuid }});
$temperature_uuid = $anvil->Database->insert_or_update_temperature({
cache => $anvil->data->{'scan-storcli'}{queries},
debug => 2,
'delete' => 1,
temperature_uuid => $temperature_uuid,
});
$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__, 'print' => 1, 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__, 'print' => 1, 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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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__, 'print' => 1, 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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{alert_sort}++,
set_by => $THIS_FILE,
});
my $query = "
UPDATE
scan_storcli_variables
SET
scan_storcli_variable_value = 'VANISHED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_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 '<host_controller_sn>-vd<x>' 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__, 'print' => 1, 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__, 'print' => 1, 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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{alert_sort}++,
set_by => $THIS_FILE,
});
my $query = "
UPDATE
scan_storcli_variables
SET
scan_storcli_variable_value = 'VANISHED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_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-storcli'}{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->Database->refresh_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__, 'print' => 1, 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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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__, 'print' => 1, 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__, 'print' => 1, 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__, 'print' => 1, 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-storcli'}{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->Database->refresh_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" ? 3 : 2;
$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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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" ? 3 : 2;
$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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{alert_sort}++,
set_by => $THIS_FILE,
});
my $query = "
UPDATE
scan_storcli_variables
SET
scan_storcli_variable_value = 'VANISHED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_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__, 'print' => 1, level => 0, 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__, 'print' => 1, 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 }});
# 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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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
next if not defined $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 $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-storcli'}{alert_sort}++,
set_by => $THIS_FILE,
});
my $query = "
UPDATE
scan_storcli_variables
SET
scan_storcli_variable_value = 'VANISHED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_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-storcli'}{alert_sort}++,
set_by => $THIS_FILE,
});
my $query = "
UPDATE
scan_storcli_cachevaults
SET
scan_storcli_cachevault_state = 'VANISHED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_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__, 'print' => 1, level => 0, 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__, 'print' => 1, 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 }});
# 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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{alert_sort}++,
set_by => $THIS_FILE,
});
my $query = "
UPDATE
scan_storcli_variables
SET
scan_storcli_variable_value = 'VANISHED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_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-storcli'}{alert_sort}++,
set_by => $THIS_FILE,
});
my $query = "
UPDATE
scan_storcli_bbus
SET
scan_storcli_bbu_state = 'VANISHED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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 ($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 => $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-storcli'}{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->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{alert_sort}++,
set_by => $THIS_FILE,
});
my $query = "
UPDATE
scan_storcli_variables
SET
scan_storcli_variable_value = 'VANISHED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_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-storcli'}{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->Database->refresh_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-storcli'}{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, merge_spaces => 0});
$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, merge_spaces => 0});
$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 => {
's1:variable' => $variable,
's2: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 => 0, '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} }});
}
# Do we have storcli64 installed?
if (not -e $anvil->data->{path}{exe}{storcli64})
{
# Nope, Call lspci to see if there's a MegaRAID controller. If there is, the user may need to
# install the RPM.
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{lspci}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
my $megaraid_installed = 0;
foreach my $line (split/\n/, $output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /MegaRAID/i)
{
# This host appears to have a RAID card, but it's not installed. Lets try to
# install it for them.
$megaraid_installed = install_storcli($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { megaraid_installed => $megaraid_installed }});
}
}
# exit.
if (not $megaraid_installed)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, 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 => 0, 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' => 2, level => 0, key => "scan_storcli_error_0003", variables => {
path => $anvil->data->{path}{exe}{storcli64},
}});
$anvil->nice_exit({exit_code => 3});
}
return(0);
}
sub install_storcli
{
my ($anvil) = @_;
# Tell the user what we're doing.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_note_0071"});
# Is this a Dell?
my $is_dell = 0;
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{dmidecode}." --string system-manufacturer"});
$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 =~ /Dell/i)
{
$is_dell = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { is_dell => $is_dell }});
}
}
my $rpm_name = $is_dell ? "perccli" : "storcli";
my $shell_call = $anvil->data->{path}{exe}{dnf}." -y install ".$rpm_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
($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,
}});
# Check now to see if the program is installed. If it is, register an alert announcing we installed it.
my $program = $is_dell ? $anvil->data->{path}{exe}{perccli64} : $anvil->data->{path}{exe}{storcli64};
if (-e $program)
{
# Installed successfully!
my $variables = {
rpm => $rpm_name,
};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_storcli_note_0072", variables => $variables});
$anvil->Alert->register({
alert_level => "notice",
message => "scan_storcli_note_0072",
show_header => 1,
variables => $variables,
sort_position => 0,
set_by => $THIS_FILE,
});
# Before we return, if we installed for Dell, switch out the 'storcli' program path.
if ($is_dell)
{
$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} }});
}
return(1);
}
else
{
# Didn't work.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "scan_storcli_note_0073"});
}
return(0);
}