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.
 
 
 
 
 
 

10184 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.
foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{old}{temperature}})
{
foreach my $serial_number (sort {$a cmp $b} keys %{$anvil->data->{old}{temperature}{$variable}})
{
my $temperature_uuid = $anvil->data->{old}{temperature}{$variable}{$serial_number}{temperature_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 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,