#!/usr/bin/perl
# 
# This software was created by Alteeve's Niche! Inc. and has been released
# under the terms of the GNU GPL version 2.
#
# ScanCore Scan Agent for HPE type RAID controllers using the 'hpacucli' command line tool.
#
# https://alteeve.com
# 
# Exit Codes:
# 0  - Success
# 1  - hpacucli not installed
# 2  - hpacucli is installed but it is not executable.
# 3  - No HPE type controllers found.
# 4  - Controller numeric value is invalid.
# 5  - Cache module numeric value is invalid.
# 6  - Array numeric value is invalid.
# 7  - Logical drive numeric value is invalid.
# 8  - Physical drive numeric value is invalid.
# 9  - Physical drive has no serial number.
# 
# 255 - The host's UUID isn't in the hosts table yet, ScanCore itself hasn't been run.
# 
# TODO:
# - 
# 
# NOTE: 
# - Health values
#   - Controller  - Correctable errors   = 1
#   - Controller  - Uncorrectable errors = 5
#   - Controller  - Status changes       = 5
#   - Drive group - partially degraded   = 5
#   - Drive group - degraded             = 10
#   - Cachevault  - Replacement needed   = 5
#   - BBU         - Replacement needed   = 5
#   - Temperature - Critical             = 2
#   - Temperature - Warning              = 1

# Use my modules.
use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
use Math::BigInt;
no warnings 'recursion';

# Disable buffering
$| = 1;

# Prevent a discrepency between UID/GID and EUID/EGID from throwing an error.
$< = $>;
$( = $);

my $THIS_FILE           =  ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory   =  ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
	$running_directory =~ s/^\./$ENV{PWD}/;
}

my $anvil = Anvil::Tools->new();

# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
if (($< != 0) && ($> != 0))
{
	# Not root
	print $anvil->Words->string({key => "error_0005"})."\n";
	$anvil->nice_exit({exit_code => 1});
}

# Here we store data and variables for this agent.
$anvil->data->{'scan-hpacucli'} = {
	health			=>	{
		old			=>	{},
		new			=>	{},
	},

	# This will keep track of devices with serial numbers so that it is easy to look up
	# the UUID from the serial numbers and vice versa.
	controllers		=>	{
		by_serial		=>	{},
		by_uuid			=>	{},
	},
	physical_drives		=>	{
		by_serial		=>	{},
		by_uuid			=>	{},
	},
	# Checking the drives for errors is expensive, so it is only done every hour (or 
	# there abouts). Change the interval if you want to check more or less often.
	diagnostics_interval	=>	1800,
	disable			=>	0,
	ignore_maximum_temperature =>	0,
	language		=>	"en_CA",
	log_level		=>	1,
	log_language		=>	"en_CA",
	log_file		=>	"/var/log/ScanCore.log",
	log_db_transactions	=>	0,
	thresholds			=>	{
		# This is used for unknown sensors and really shouldn't be used at all.
		'default'			=>	{
			high_warning			=>	50,
			high_critical			=>	55,
			low_warning			=>	15,
			low_critical			=>	10,
			jump				=>	5,
			buffer				=>	3,
		},
		drives				=>	{
			# http://storage.toshiba.com/docs/product-datasheets/mk01grrb-r.pdf
			# http://toshiba.semicon-storage.com/us/product/storage-products/enterprise-ssd/px02smb-px02smfxxx.html
			high_warning			=>	50,
			high_critical			=>	55,
			low_warning			=>	5,
			low_critical			=>	0,
			jump				=>	5,
			buffer				=>	2,
		},
		# I've not found official ranges on this yet... These are best-guess values
		controller_temperature		=>	{
			high_warning			=>	100,
			high_critical			=>	105,
			low_warning			=>	15,
			low_critical			=>	10,
			jump				=>	10,
			buffer				=>	5,
		},
		# I've not found official ranges on this yet... These are best-guess values
		capacitor			=>	{
			high_warning			=>	50,
			high_critical			=>	55,
			low_warning			=>	15,
			low_critical			=>	10,
			jump				=>	5,
			buffer				=>	3,
		},
		# https://support.hpe.com/hpsc/doc/public/display?docId=c04441382
		cache				=>	{
			high_warning			=>	50,
			high_critical			=>	55,
			low_warning			=>	15,
			low_critical			=>	10,
			jump				=>	5,
			buffer				=>	3,
		},
	},
	sys			=>	{
		alert_sort		=>	2,
		controller			=>	{},
		controller_count		=>	0,
		# When a lock is requested, this is set to the time the lock was set. 
		# DB->do_db_write() and DB->do_db_read() will check this and if its age is >50% of
		# scancore::locking::reap_age, it will renew the lock.
		lock_active		=>	0,
		process_diagnostics	=>	0,
	},
	queries			=>	[],
};

$anvil->Storage->read_config();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0115", variables => { program => $THIS_FILE }});

# Read switches
$anvil->Get->switches({list => ["purge"], man => $THIS_FILE});

# Handle start-up tasks
my $problem = $anvil->ScanCore->agent_startup({agent => $THIS_FILE});
if ($problem)
{
	$anvil->nice_exit({exit_code => 1});
}

if ($anvil->data->{switches}{purge})
{
	# This can be called when doing bulk-database purges.
	my $schema_file = $anvil->data->{path}{directories}{scan_agents}."/".$THIS_FILE."/".$THIS_FILE.".sql";
	$anvil->Database->purge_data({
		debug  => 2,
		tables => $anvil->Database->get_tables_from_schema({schema_file => $schema_file}),
	});
	$anvil->nice_exit({exit_code => 0});
}

$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "scan_hpacucli_message_0001"});

# This does two things; It checks to see if hpacucli is installed (exits '1' if not, exits '2' if not 
# executable) and then checks to see if any controllers are found in the system (exits '3' if not). 
find_hp_controllers($anvil);

# If we're still alive, start gathering data.
gather_data($anvil);

# Figure out, other than temperatures, what should be added to or removed from health.
pre_process_health($anvil);

# Look for changes.
find_changes($anvil);

# Process temperatures! This also sets health values for warning and critical temperatures so make sure we
# always call this before process_health().
process_temperatures($anvil);

# Finally, process health weights.
process_health($anvil);

# Shut down.
$anvil->ScanCore->agent_shutdown({agent => $THIS_FILE});


#############################################################################################################
# Function below                                                                                            #
#############################################################################################################

# This reads in the last scan data from one of the databases and compares it against the just-read data. If 
# anything changed, register an alert.
sub find_changes
{
	my ($anvil) = @_;
	
	# Read in the old data. As we compare and UPDATE if needed, then we'll delete. If any are not found,
	# then it must be new and will be INSERTed. Any old records left over will have vanished.
	read_last_scan($anvil);
	
	### NOTE: We will loop through each section of data we scanned, deleting records as we process them
	###       that existed in the DB, and then marking as removed anything left in the databased data not
	###       seen in this scan.
	process_controllers($anvil);
	
	# Now that controllers have been proceesed, we can process drives (and their arrays)
	process_drives($anvil);
	
	# If we processed diagnostics, update
	if ($anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics})
	{
		my $query = "
UPDATE 
    scan_hpacucli_controllers
SET 
    scan_hpacucli_controller_last_diagnostics = ".time.", 
    modified_date                             = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_controller_host_uuid        = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
	}
	
	return(0);
}

# This reads in all health wieghts previously set, alters ones as needed, INSERTs new ones and DELETEs old
# ones.
sub process_health
{
	my ($anvil) = @_;
	
	# This will hold our updates.
	$anvil->data->{'scan-hpacucli'}{queries} = [];
	
	# Read in previous health values.
	my $query = "
SELECT 
    health_uuid,
    health_agent_name,
    health_source_name,
    health_source_weight 
FROM 
    health 
WHERE 
    health_host_uuid  = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
AND 
    health_agent_name = ".$anvil->Database->quote($THIS_FILE)."
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	my $count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count, 
	}});
	foreach my $row (@{$results})
	{
		my $health_uuid          = $row->[0]; 
		my $health_agent_name    = $row->[1]; 
		my $health_source_name   = $row->[2]; 
		my $health_source_weight = $row->[3];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			health_uuid          => $health_uuid, 
			health_agent_name    => $health_agent_name, 
			health_source_name   => $health_source_name, 
			health_source_weight => $health_source_weight, 
		}});
		
		$anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{uuid}  = $health_uuid;
		$anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{value} = $health_source_weight;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan-hpacucli::health::old::${health_source_name}::uuid"  => $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{uuid}, 
			"scan-hpacucli::health::old::${health_source_name}::value" => $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{value}, 
		}});
	}
	
	# Read in the new ones
	foreach my $health_source_name (sort {$a cmp $b} keys %{$anvil->data->{'scan-hpacucli'}{health}{new}})
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"health::new::$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
		}});
		
		my $health_uuid = "";
		if (exists $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name})
		{
			$health_uuid = $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{uuid};
		}
		$health_uuid = $anvil->Database->insert_or_update_health({
			debug                => 2,
			cache                => $anvil->data->{'scan-hpacucli'}{queries}, 
			health_uuid          => $health_uuid,
			health_host_uuid     => $anvil->Get->host_uuid,
			health_agent_name    => $THIS_FILE,
			health_source_name   => $health_source_name,
			health_source_weight => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name},
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_uuid => $health_uuid }});
		
		if (exists $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name})
		{
			# Delete the new old key, regardless of whether it has changed now.
			delete $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name};
		}
	}
	
	# Delete any old entries that are left.
	foreach my $health_source_name (sort {$a cmp $b} keys %{$anvil->data->{'scan-hpacucli'}{health}{old}})
	{
		# Well set the source name to 'DELETED'.
		my $health_uuid = $anvil->Database->insert_or_update_health({
			debug       => 2,
			cache       => $anvil->data->{'scan-hpacucli'}{queries}, 
			'delete'    => 1,
			health_uuid => $anvil->data->{'scan-hpacucli'}{health}{old}{$health_source_name}{uuid},
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_uuid => $health_uuid }});
	}
	
	# Now commit the changes.
	$anvil->Database->write({query => $anvil->data->{'scan-hpacucli'}{queries}, source => $THIS_FILE, line => __LINE__});
	$anvil->data->{'scan-hpacucli'}{queries} = [];
	
	return(0);
}

# This reads in the various temperature sensors we read from this run and will set the temperature table 
# and/or set/clear warnings/critical states.
sub process_temperatures
{
	my ($anvil) = @_;
	
	### NOTE: We use 'sensor_host' to hold the serial number of the device hosting the sensor.
	# First, read in all existing entries. We'll compare and UPDATE or INSERT as needed and DELETE any 
	# stale entries. 
	my $query = "
SELECT 
    temperature_uuid, 
    temperature_sensor_name, 
    temperature_sensor_host, 
    temperature_value_c,
    temperature_state,
    temperature_is
FROM 
    temperature 
WHERE 
    temperature_host_uuid  = ".$anvil->Database->quote($anvil->Get->host_uuid)."
AND 
    temperature_agent_name = ".$anvil->Database->quote($THIS_FILE)." 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	
	# One or more records were found.
	foreach my $row (@{$results})
	{
		my $temperature_sensor_name = $row->[1];
		my $temperature_sensor_host = $row->[2];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			temperature_sensor_name => $temperature_sensor_name, 
			temperature_sensor_host => $temperature_sensor_host, 
		}});
		
		$anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_uuid}    = $row->[0];
		$anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_value_c} = $row->[3];
		$anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_state}   = $row->[4];
		$anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_is}      = $row->[5];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"old::temperature::${temperature_sensor_name}::${temperature_sensor_host}::temperature_uuid"    => $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_uuid}, 
			"old::temperature::${temperature_sensor_name}::${temperature_sensor_host}::temperature_value_c" => $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_value_c}, 
			"old::temperature::${temperature_sensor_name}::${temperature_sensor_host}::temperature_state"   => $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_state}, 
			"old::temperature::${temperature_sensor_name}::${temperature_sensor_host}::temperature_is"      => $anvil->data->{old}{temperature}{$temperature_sensor_name}{$temperature_sensor_host}{temperature_is}, 
		}});
	}
	
	# Loop through the temperature from this scan.
	foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{new}{temperature}})
	{
		foreach my $serial_number (sort {$a cmp $b} keys %{$anvil->data->{new}{temperature}{$variable}})
		{
			my $new_temperature_value_c = $anvil->data->{new}{temperature}{$variable}{$serial_number}{temperature_value_c};
			my $new_temperature_state   = $anvil->data->{new}{temperature}{$variable}{$serial_number}{temperature_state};
			my $new_temperature_is      = $anvil->data->{new}{temperature}{$variable}{$serial_number}{temperature_is};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				variable                => $variable, 
				serial_number           => $serial_number, 
				new_temperature_value_c => $new_temperature_value_c, 
				new_temperature_state   => $new_temperature_state, 
				new_temperature_is      => $new_temperature_is, 
			}});
			
			# If the state is 'warning', set  a health weight of 1 and set critical to 2.
			my $health_source_name                                               = "temperature:".$serial_number;
			   $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 0;
			if ($new_temperature_state eq "warning")
			{
				$anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 1;
			}
			elsif ($new_temperature_state eq "critical")
			{
				$anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 2;
			}
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"health::new::$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
			}});
			
			my $temperature_uuid = "";
			if (exists $anvil->data->{old}{temperature}{$variable}{$serial_number})
			{
				$temperature_uuid = $anvil->data->{old}{temperature}{$variable}{$serial_number}{temperature_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { temperature_uuid => $temperature_uuid }});
				delete $anvil->data->{old}{temperature}{$variable}{$serial_number};
			}
			$temperature_uuid = $anvil->Database->insert_or_update_temperature({
				cache                   => $anvil->data->{'scan-hpacucli'}{queries}, 
				debug                   => 2,
				temperature_uuid        => $temperature_uuid, 
				temperature_host_uuid   => $anvil->Get->host_uuid,
				temperature_agent_name  => $THIS_FILE,
				temperature_sensor_host => $serial_number,
				temperature_sensor_name => $variable,
				temperature_value_c     => $new_temperature_value_c, 
				temperature_state       => $new_temperature_state, 
				temperature_is          => $new_temperature_is, 
				temperature_weight      => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { temperature_uuid => $temperature_uuid }});
		}
	}
	
	# Now, if any undeleted old entries remain, delete them from the database.
	foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{old}{temperature}})
	{
		foreach my $serial_number (sort {$a cmp $b} keys %{$anvil->data->{old}{temperature}{$variable}})
		{
			my $temperature_uuid = $anvil->data->{old}{temperature}{$variable}{$serial_number}{temperature_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"variable"         => $variable, 
				"serial_number"    => $serial_number, 
				"temperature_uuid" => $temperature_uuid, 
			}});
			
			# Mark the sensor as DELETEd.
			$anvil->Database->insert_or_update_temperature({
				cache            => $anvil->data->{'scan-hpacucli'}{queries}, 
				debug            => 2,
				'delete'         => 1,
				temperature_uuid => $temperature_uuid, 
			});
		}
	}
	
	# Commit the queries.
	$anvil->Database->write({query => $anvil->data->{'scan-hpacucli'}{queries}, source => $THIS_FILE, line => __LINE__});
	$anvil->data->{'scan-hpacucli'}{queries} = [];
	
	return(0);
}

# Process drives (and their arrays and logical drives).
sub process_drives
{
	my ($anvil) = @_;
	
	# Look for new, changed or deleted controllers.
	$anvil->data->{'scan-hpacucli'}{queries} = [];
	
	# This is to collected data from every sweep.
	foreach my $scan_hpacucli_controller_serial_number (sort {$a cmp $b} keys %{$anvil->data->{controller}})
	{
		# Controller data;
		next if $scan_hpacucli_controller_serial_number eq "metadata";
		my $scan_hpacucli_controller_uuid = $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number, 
			scan_hpacucli_controller_uuid          => $scan_hpacucli_controller_uuid, 
		}});
		
		# Array
		foreach my $scan_hpacucli_array_name (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}})
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_array_name => $scan_hpacucli_array_name }});
			
			# Data, there is no temperature
			my $new_scan_hpacucli_array_type          = "virtual";
			my $new_scan_hpacucli_array_status        = "virtual";
			my $new_scan_hpacucli_array_error_message = "";
			
			if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{array_type})
			{
				$new_scan_hpacucli_array_type = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{array_type};
			}
			if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{status})
			{
				# Array transitions (OK -> Eject -> Plug back in)
				#scan-hpacucli 3117;   - Data; status: [OK]
				#scan-hpacucli 3117;   - Data; status: [Failed Physical Drive]
				#scan-hpacucli 3148;   - Data; status: [OK]
				$new_scan_hpacucli_array_status = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{status};
			}
			if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message})
			{
				$new_scan_hpacucli_array_error_message = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message};
			}
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_hpacucli_array_name              => $scan_hpacucli_array_name, 
				new_scan_hpacucli_array_type          => $new_scan_hpacucli_array_type, 
				new_scan_hpacucli_array_status        => $new_scan_hpacucli_array_status, 
				new_scan_hpacucli_array_error_message => $new_scan_hpacucli_array_error_message, 
			}});
			
			# Does this array exist already?
			my $scan_hpacucli_array_uuid = $anvil->data->{'scan-hpacucli'}{virtual_drives}{by_name}{$scan_hpacucli_array_name} ? $anvil->data->{'scan-hpacucli'}{virtual_drives}{by_name}{$scan_hpacucli_array_name} : "";
			if (($scan_hpacucli_array_uuid) && (exists $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}))
			{
				# Look for changes.
				my $old_scan_hpacucli_array_controller_uuid = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_controller_uuid};
				my $old_scan_hpacucli_controller_serial_number       = $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$old_scan_hpacucli_array_controller_uuid};
				my $old_scan_hpacucli_array_type            = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_type};
				my $old_scan_hpacucli_array_status          = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_status};
				my $old_scan_hpacucli_array_error_message   = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_error_message};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					old_scan_hpacucli_array_controller_uuid => $old_scan_hpacucli_array_controller_uuid, 
					old_scan_hpacucli_controller_serial_number       => $old_scan_hpacucli_controller_serial_number, 
					old_scan_hpacucli_array_type            => $old_scan_hpacucli_array_type, 
					old_scan_hpacucli_array_status          => $old_scan_hpacucli_array_status, 
					old_scan_hpacucli_array_error_message   => $old_scan_hpacucli_array_error_message, 
				}});
				
				# Delete the old one so we know we've seen it.
				delete $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid};
				
				# Has anything changed? Note that we don't check the name as that is how we 
				# find if it exists already or not.
				if (($scan_hpacucli_controller_serial_number ne $old_scan_hpacucli_controller_serial_number) or 
				    ($new_scan_hpacucli_array_type           ne $old_scan_hpacucli_array_type)      or 
				    ($new_scan_hpacucli_array_status         ne $old_scan_hpacucli_array_status)    or 
				    ($new_scan_hpacucli_array_error_message  ne $old_scan_hpacucli_array_error_message))
				{
					### Something changed.
					# If the array is not OK, clear alerts.
					if ($new_scan_hpacucli_array_status ne $old_scan_hpacucli_array_status)
					{
						my $cleared     = 0;
						my $message_key = "scan_hpacucli_note_0023";
						# Came back or went OK?
						if ($old_scan_hpacucli_array_status eq "VANISHED")
						{
							$message_key = "scan_hpacucli_note_0032";
						}
						elsif (lc($new_scan_hpacucli_array_status) eq "ok")
						{
							$cleared     = 1;
							$message_key = "scan_hpacucli_note_0024";
						}
						my $variables = {
							name          => $scan_hpacucli_array_name,
							serial_number => $scan_hpacucli_controller_serial_number,
							new_status    => $new_scan_hpacucli_array_status,
							old_status    => $old_scan_hpacucli_array_status,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
						$anvil->Alert->register({
							clear_alert   => $cleared, 
							alert_level   => "warning", 
							message       => $message_key, 
							variables     => $variables, 
							sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
							set_by        => $THIS_FILE,
						});
					}
					
					# Did the controller change?
					if ($scan_hpacucli_controller_serial_number ne $old_scan_hpacucli_controller_serial_number)
					{
						# yup. This is a notice as the new controller will have 
						# generated a warning alert.
						my $variables = {
							name              => $scan_hpacucli_array_name,
							new_serial_number => $scan_hpacucli_controller_serial_number,
							old_serial_number => $old_scan_hpacucli_controller_serial_number,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0025", variables => $variables});
						$anvil->Alert->register({
							clear_alert   => 0, 
							alert_level   => "notice", 
							message       => "scan_hpacucli_note_0025", 
							variables     => $variables, 
							sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
							set_by        => $THIS_FILE,
						});
					}
					
					# Has the error message changed?
					if ($new_scan_hpacucli_array_error_message ne $old_scan_hpacucli_array_error_message)
					{
						# Default is 'changed'
						my $cleared     = 0;
						my $message_key = "scan_hpacucli_note_0026";
						if (not $new_scan_hpacucli_array_error_message)
						{
							# Cleared
							$cleared     = 0;
							$message_key = "scan_hpacucli_note_0027";
						}
						elsif (not $old_scan_hpacucli_array_error_message)
						{
							# New error
							$message_key = "scan_hpacucli_note_0028";
						}
						my $variables = {
							name              => $scan_hpacucli_array_name,
							new_error_message => $new_scan_hpacucli_array_error_message,
							old_error_message => $old_scan_hpacucli_array_error_message,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
						$anvil->Alert->register({
							clear_alert   => $cleared, 
							alert_level   => "warning", 
							message       => $message_key, 
							variables     => $variables, 
							sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
							set_by        => $THIS_FILE,
						});
					}
					
					# Did the controller change?
					if ($new_scan_hpacucli_array_type ne $old_scan_hpacucli_array_type)
					{
						# yup. This is a warning because it should never change.
						my $variables = {
							name     => $scan_hpacucli_array_name,
							new_type => $new_scan_hpacucli_array_type,
							old_type => $old_scan_hpacucli_array_type,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0030", variables => $variables});
						$anvil->Alert->register({
							clear_alert   => 0, 
							alert_level   => "warning", 
							message       => "scan_hpacucli_note_0030", 
							variables     => $variables, 
							sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
							set_by        => $THIS_FILE,
						});
					}
					
					# UPDATE
					my $query = "
UPDATE 
    scan_hpacucli_arrays
SET
    scan_hpacucli_array_controller_uuid = ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", 
    scan_hpacucli_array_type            = ".$anvil->Database->quote($new_scan_hpacucli_array_type).", 
    scan_hpacucli_array_status          = ".$anvil->Database->quote($new_scan_hpacucli_array_status).", 
    scan_hpacucli_array_error_message   = ".$anvil->Database->quote($new_scan_hpacucli_array_error_message).", 
    modified_date                       = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_array_uuid            = ".$anvil->Database->quote($scan_hpacucli_array_uuid)." 
;";
					# Now record the query in the array
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
					push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
				}
			}
			else
			{
				# New.
				$scan_hpacucli_array_uuid                                                                        = $anvil->Get->uuid();
				$anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number} = $scan_hpacucli_controller_uuid;
				$anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid}            = $scan_hpacucli_controller_serial_number;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"scan-hpacucli::controllers::by_serial::${scan_hpacucli_controller_serial_number}" => $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}, 
					"scan-hpacucli::controllers::by_uuid::${scan_hpacucli_controller_uuid}"            => $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid}, 
				}});
				
				print $THIS_FILE." ".__LINE__."; - New Array: [$scan_hpacucli_array_name] (UUID: [$scan_hpacucli_array_uuid]); Type: [$new_scan_hpacucli_array_type], status: [$new_scan_hpacucli_array_status], error message: [$new_scan_hpacucli_array_error_message]\n";
				
				# Alert the user if this isn't the virtual array.
				if ($scan_hpacucli_array_name ne "ZZZZ")
				{
					# If the array is OK, it will be a notice.
					my $alert_level = "notice";
					my $message_key = "scan_hpacucli_note_0021";
					if (lc($new_scan_hpacucli_array_status) ne "ok")
					{
						$alert_level = "warning";
						$message_key = "scan_hpacucli_note_0022";
					}
					my $variables = {
						name   => $scan_hpacucli_array_name,
						type   => $new_scan_hpacucli_array_type,
						status => $new_scan_hpacucli_array_status,
						error  => $new_scan_hpacucli_array_error_message,
					};
					my $log_level = $alert_level eq "warning" ? 1 : 2;
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
					$anvil->Alert->register({
						clear_alert   => 0, 
						alert_level   => $alert_level, 
						message       => $message_key, 
						variables     => $variables, 
						sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
						set_by        => $THIS_FILE,
					});
				}
				
				my $query = "
INSERT INTO 
    scan_hpacucli_arrays
(
    scan_hpacucli_array_uuid, 
    scan_hpacucli_array_host_uuid, 
    scan_hpacucli_array_controller_uuid, 
    scan_hpacucli_array_name, 
    scan_hpacucli_array_type, 
    scan_hpacucli_array_status, 
    scan_hpacucli_array_error_message, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($scan_hpacucli_array_uuid).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", 
    ".$anvil->Database->quote($scan_hpacucli_array_name).", 
    ".$anvil->Database->quote($new_scan_hpacucli_array_type).", 
    ".$anvil->Database->quote($new_scan_hpacucli_array_status).", 
    ".$anvil->Database->quote($new_scan_hpacucli_array_error_message).", 
    ".$anvil->Database->quote($anvil->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-hpacucli'}{queries}}, $query;
			}
			
			# Logical Drive
			foreach my $scan_hpacucli_logical_drive_name (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}})
			{
				# No thermal data
				my $scan_hpacucli_logical_drive_uuid               = $anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name} ? $anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name} : "";
				my $new_scan_hpacucli_logical_drive_caching        = "";
				my $new_scan_hpacucli_logical_drive_os_device_name = "";
				my $new_scan_hpacucli_logical_drive_type           = "";
				my $new_scan_hpacucli_logical_drive_raid_level     = "";
				my $new_scan_hpacucli_logical_drive_size           = "";
				my $new_scan_hpacucli_logical_drive_strip_size     = "";
				my $new_scan_hpacucli_logical_drive_stripe_size    = "";
				my $new_scan_hpacucli_logical_drive_status         = "";
				
				# If this is the virtual array, set the sizes to 0.
				if ($scan_hpacucli_logical_drive_name eq "9999")
				{
					$new_scan_hpacucli_logical_drive_size        = 0;
					$new_scan_hpacucli_logical_drive_strip_size  = 0;
					$new_scan_hpacucli_logical_drive_stripe_size = 0;
				}

				### Gather the variables.
				# Caching
				if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{caching})
				{
					$new_scan_hpacucli_logical_drive_caching = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{caching};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_logical_drive_caching => $new_scan_hpacucli_logical_drive_caching }});
				}
				# Disk name (in the OS)
				if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{disk_name})
				{
					$new_scan_hpacucli_logical_drive_os_device_name = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{disk_name};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_logical_drive_os_device_name => $new_scan_hpacucli_logical_drive_os_device_name }});
				}
				# Drive type
				if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{drive_type})
				{
					$new_scan_hpacucli_logical_drive_type = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{drive_type};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_logical_drive_type => $new_scan_hpacucli_logical_drive_type }});
				}
				# RAID level
				if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{fault_tolerance})
				{
					$new_scan_hpacucli_logical_drive_raid_level = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{fault_tolerance};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_logical_drive_raid_level => $new_scan_hpacucli_logical_drive_raid_level }});
				}
				# Drive size - Needs to be converted to bytes at initial processing.
				if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{size})
				{
					$new_scan_hpacucli_logical_drive_size = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{size};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"new_scan_hpacucli_logical_drive_size" => $new_scan_hpacucli_logical_drive_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_size}).")", 
					}});
				}
				# Strip size
				if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{strip_size})
				{
					$new_scan_hpacucli_logical_drive_strip_size = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{strip_size};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"new_scan_hpacucli_logical_drive_strip_size" => $new_scan_hpacucli_logical_drive_strip_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_strip_size}).")", 
					}});
				}
				# Stripe size
				if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{full_stripe_size})
				{
					$new_scan_hpacucli_logical_drive_stripe_size = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{full_stripe_size};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"new_scan_hpacucli_logical_drive_stripe_size" => $new_scan_hpacucli_logical_drive_stripe_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_stripe_size}).")", 
					}});
				}
				# Status
				if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{status})
				{
					$new_scan_hpacucli_logical_drive_status = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{status};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_logical_drive_status => $new_scan_hpacucli_logical_drive_status }});
				}
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					new_scan_hpacucli_logical_drive_caching        => $new_scan_hpacucli_logical_drive_caching, 
					new_scan_hpacucli_logical_drive_os_device_name => $new_scan_hpacucli_logical_drive_os_device_name, 
					new_scan_hpacucli_logical_drive_type           => $new_scan_hpacucli_logical_drive_type, 
					new_scan_hpacucli_logical_drive_raid_level     => $new_scan_hpacucli_logical_drive_raid_level, 
					new_scan_hpacucli_logical_drive_size           => $new_scan_hpacucli_logical_drive_size, 
					new_scan_hpacucli_logical_drive_strip_size     => $new_scan_hpacucli_logical_drive_strip_size, 
					new_scan_hpacucli_logical_drive_stripe_size    => $new_scan_hpacucli_logical_drive_stripe_size, 
					new_scan_hpacucli_logical_drive_status         => $new_scan_hpacucli_logical_drive_status, 
				}});
				
				if (($scan_hpacucli_logical_drive_uuid) && (exists $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}))
				{
					my $old_scan_hpacucli_logical_drive_array_uuid     = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_array_uuid};
					my $old_scan_hpacucli_logical_drive_name           = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_name};
					my $old_scan_hpacucli_logical_drive_caching        = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_caching};
					my $old_scan_hpacucli_logical_drive_os_device_name = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_os_device_name};
					my $old_scan_hpacucli_logical_drive_type           = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_type};
					my $old_scan_hpacucli_logical_drive_raid_level     = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_raid_level};
					my $old_scan_hpacucli_logical_drive_size           = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_size};
					my $old_scan_hpacucli_logical_drive_strip_size     = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_strip_size};
					my $old_scan_hpacucli_logical_drive_stripe_size    = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_stripe_size};
					my $old_scan_hpacucli_logical_drive_status         = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_status};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						scan_hpacucli_logical_drive_uuid               => $scan_hpacucli_logical_drive_uuid, 
						old_scan_hpacucli_logical_drive_array_uuid     => $old_scan_hpacucli_logical_drive_array_uuid, 
						old_scan_hpacucli_logical_drive_name           => $old_scan_hpacucli_logical_drive_name, 
						old_scan_hpacucli_logical_drive_caching        => $old_scan_hpacucli_logical_drive_caching, 
						old_scan_hpacucli_logical_drive_os_device_name => $old_scan_hpacucli_logical_drive_os_device_name, 
						old_scan_hpacucli_logical_drive_type           => $old_scan_hpacucli_logical_drive_type, 
						old_scan_hpacucli_logical_drive_raid_level     => $old_scan_hpacucli_logical_drive_raid_level, 
						old_scan_hpacucli_logical_drive_size           => $old_scan_hpacucli_logical_drive_size, 
						old_scan_hpacucli_logical_drive_strip_size     => $old_scan_hpacucli_logical_drive_strip_size, 
						old_scan_hpacucli_logical_drive_stripe_size    => $old_scan_hpacucli_logical_drive_stripe_size, 
						old_scan_hpacucli_logical_drive_status         => $old_scan_hpacucli_logical_drive_status, 
					}});
					
					# Delete this so we know it was processed
					delete $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid};
					
					my $update    = 0;
					my $recovered = "";
					if ($new_scan_hpacucli_logical_drive_caching ne $old_scan_hpacucli_logical_drive_caching)
					{
						# Did it go enabled or disabled?
						   $update      = 1;
						my $cleared     = 0;
						my $message_key = "scan_hpacucli_note_0034";
						if (lc($new_scan_hpacucli_logical_drive_caching) eq "enabled")
						{
							# We're back.
							$cleared     = 1;
							$message_key = "scan_hpacucli_note_0035";
						}
						if (lc($new_scan_hpacucli_logical_drive_caching) eq "disabled")
						{
							# Warn the user about a possible performance hit.
							$message_key = "scan_hpacucli_note_0036";
						}
						
						# Send an alert telling the user that we've found a new controller.
						my $variables = {
							logical_drive => $scan_hpacucli_logical_drive_name,
							array         => $scan_hpacucli_array_name,
							serial_number => $scan_hpacucli_controller_serial_number,
							new_value     => $new_scan_hpacucli_logical_drive_caching, 
							old_value     => $old_scan_hpacucli_logical_drive_caching, 
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
						$anvil->Alert->register({
							clear_alert   => $cleared, 
							alert_level   => "warning", 
							message       => $message_key, 
							variables     => $variables, 
							sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
							set_by        => $THIS_FILE,
						});
					}
					elsif ($new_scan_hpacucli_logical_drive_status ne $old_scan_hpacucli_logical_drive_status)
					{
						# NOTE: Auto-restored a drive that was re-inserted
						# Example messages; "Interim Recovery Mode"
						#                   "Recovering, 0% complete"
						# LD transitions (OK -> Eject -> Plug back in)
						   $update      = 1;
						my $cleared     = 0;
						my $alert_level = "warning";
						my $message_key = "scan_hpacucli_note_0037";
						if ($old_scan_hpacucli_logical_drive_status eq "VANISHED")
						{
							# It's back
							$cleared     = 1;
							$message_key = "scan_hpacucli_note_0045";
						}
						elsif (lc($new_scan_hpacucli_logical_drive_status) eq "ok")
						{
							# Back to healthy.
							   $cleared     = 1;
							   $alert_level = "critical";
							   $message_key = "scan_hpacucli_note_0038";
							my $changed     = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_logical_drive_uuid.":rebuilding_logical_drive:".$scan_hpacucli_logical_drive_name, set_by => $THIS_FILE});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
						}
						elsif ($new_scan_hpacucli_logical_drive_status =~ /Recovering, (.*?)% complete/i)
						{
							# We'll set an alert so that one alert goes out when 
							# the rebuild starts.
							   $recovered = $1;
							my $changed   = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_logical_drive_uuid.":rebuilding_logical_drive:".$scan_hpacucli_logical_drive_name, set_by => $THIS_FILE});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								recovered => $recovered, 
								changed   => $changed, 
							}});
							if ($changed)
							{
								# Let the user know the rebuild has started.
								$message_key = "scan_hpacucli_note_0039";
							}
							else
							{
								# Still under way
								$alert_level = "notice";
								$message_key = "scan_hpacucli_note_0040";
							}
						}
						elsif (lc($new_scan_hpacucli_logical_drive_status) eq "interim recovery mode")
						{
							# Drive just failed.
							$alert_level = "critical";
							$message_key = "scan_hpacucli_note_0041";
						}
						
						# Send the alert
						my $variables = {
							logical_drive => $scan_hpacucli_logical_drive_name,
							array         => $scan_hpacucli_array_name,
							serial_number => $scan_hpacucli_controller_serial_number,
							new_value     => $new_scan_hpacucli_logical_drive_status, 
							old_value     => $old_scan_hpacucli_logical_drive_status, 
							recovered     => $recovered,
						};
						my $log_level = (($alert_level eq "warning") or ($alert_level eq "critical")) ? 1 : 2;
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
						$anvil->Alert->register({
							clear_alert   => $cleared, 
							alert_level   => $alert_level, 
							message       => $message_key, 
							variables     => $variables, 
							show_header   => 1, 
							sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
							set_by        => $THIS_FILE,
						});
					}
					elsif (($new_scan_hpacucli_logical_drive_os_device_name ne $old_scan_hpacucli_logical_drive_os_device_name) or 
					       ($new_scan_hpacucli_logical_drive_type           ne $old_scan_hpacucli_logical_drive_type)           or 
					       ($new_scan_hpacucli_logical_drive_raid_level     ne $old_scan_hpacucli_logical_drive_raid_level)     or 
					       ($new_scan_hpacucli_logical_drive_size           ne $old_scan_hpacucli_logical_drive_size)           or 
					       ($new_scan_hpacucli_logical_drive_strip_size     ne $old_scan_hpacucli_logical_drive_strip_size)     or 
					       ($new_scan_hpacucli_logical_drive_stripe_size    ne $old_scan_hpacucli_logical_drive_stripe_size))
					{
						# Something else changed. This should normally never happen.
						   $update    = 1;
						my $variables = {
							logical_drive     => $scan_hpacucli_logical_drive_name,
							array             => $scan_hpacucli_array_name,
							serial_number     => $scan_hpacucli_controller_serial_number,
							new_os_drive_name => $new_scan_hpacucli_logical_drive_os_device_name,
							old_os_drive_name => $old_scan_hpacucli_logical_drive_os_device_name,
							new_type          => $new_scan_hpacucli_logical_drive_type,
							old_type          => $old_scan_hpacucli_logical_drive_type,
							new_raid_level    => $new_scan_hpacucli_logical_drive_raid_level,
							old_raid_level    => $old_scan_hpacucli_logical_drive_raid_level,
							new_size          => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_size}),
							old_size          => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hpacucli_logical_drive_size}),
							new_strip_size    => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_strip_size}),
							old_strip_size    => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hpacucli_logical_drive_strip_size}),
							new_stripe_size   => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_stripe_size}),
							old_stripe_size   => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hpacucli_logical_drive_stripe_size}),
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0042", variables => $variables});
						$anvil->Alert->register({
							clear_alert   => 0, 
							alert_level   => "warning", 
							message       => "scan_hpacucli_note_0042", 
							variables     => $variables, 
							show_header   => 1, 
							sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
							set_by        => $THIS_FILE,
						});
					}
					
					# If something changed, UPDATE.
					if ($update)
					{
						# Quote the numbers.
						my $quoted_scan_hpacucli_logical_drive_size        =  $anvil->Database->quote($new_scan_hpacucli_logical_drive_size);
						my $quoted_scan_hpacucli_logical_drive_strip_size  =  $anvil->Database->quote($new_scan_hpacucli_logical_drive_strip_size);
						my $quoted_scan_hpacucli_logical_drive_stripe_size =  $anvil->Database->quote($new_scan_hpacucli_logical_drive_stripe_size);
						   $quoted_scan_hpacucli_logical_drive_size        =~ s/^'(.*?)'$/$1/;
						   $quoted_scan_hpacucli_logical_drive_strip_size  =~ s/^'(.*?)'$/$1/;
						   $quoted_scan_hpacucli_logical_drive_stripe_size =~ s/^'(.*?)'$/$1/;
						   
						# Do the update
						my $query = "
UPDATE 
    scan_hpacucli_logical_drives
SET
    scan_hpacucli_logical_drive_array_uuid     = ".$anvil->Database->quote($scan_hpacucli_array_uuid).", 
    scan_hpacucli_logical_drive_name           = ".$anvil->Database->quote($scan_hpacucli_logical_drive_name).", 
    scan_hpacucli_logical_drive_caching        = ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_caching).", 
    scan_hpacucli_logical_drive_os_device_name = ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_os_device_name).", 
    scan_hpacucli_logical_drive_type           = ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_type).", 
    scan_hpacucli_logical_drive_raid_level     = ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_raid_level).", 
    scan_hpacucli_logical_drive_size           = $quoted_scan_hpacucli_logical_drive_size, 
    scan_hpacucli_logical_drive_strip_size     = $quoted_scan_hpacucli_logical_drive_strip_size, 
    scan_hpacucli_logical_drive_stripe_size    = $quoted_scan_hpacucli_logical_drive_stripe_size, 
    scan_hpacucli_logical_drive_status         = ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_status).", 
    modified_date                              = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_logical_drive_uuid           = ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid)." 
;";
						# Now record the query in the array
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
						push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
					}
				}
				else
				{
					# New, INSERT.
					$scan_hpacucli_logical_drive_uuid                                                        = $anvil->Get->uuid();
					$anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name} = $scan_hpacucli_logical_drive_uuid;
					$anvil->data->{'scan-hpacucli'}{logical_drives}{by_uuid}{$scan_hpacucli_logical_drive_uuid} = $scan_hpacucli_logical_drive_name;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"scan-hpacucli::logical_drives::by_name::${scan_hpacucli_logical_drive_name}" => $anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name}, 
						"scan-hpacucli::logical_drives::by_uuid::${scan_hpacucli_logical_drive_uuid}" => $anvil->data->{'scan-hpacucli'}{logical_drives}{by_uuid}{$scan_hpacucli_logical_drive_uuid}, 
					}});
					
					# Send an alert telling the user that we've found a new controller.
					my $variables = {
						name               => $scan_hpacucli_array_name,
						logical_drive      => $scan_hpacucli_logical_drive_name,
						new_caching        => $new_scan_hpacucli_logical_drive_caching, 
						new_os_device_name => $new_scan_hpacucli_logical_drive_os_device_name, 
						new_type           => $new_scan_hpacucli_logical_drive_type, 
						new_raid_level     => $new_scan_hpacucli_logical_drive_raid_level, 
						new_size           => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_size}), 
						new_strip_size     => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_strip_size}), 
						new_stripe_size    => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_logical_drive_stripe_size}), 
						new_status         => $new_scan_hpacucli_logical_drive_status, 
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0033", variables => $variables});
					$anvil->Alert->register({
						clear_alert   => 0, 
						alert_level   => "notice", 
						message       => "scan_hpacucli_note_0033", 
						variables     => $variables, 
						show_header   => 1, 
						sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
						set_by        => $THIS_FILE,
					});
					
					### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'.
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0003", variables => $variables});
					$anvil->Alert->register({
						clear_alert   => 0, 
						alert_level   => "notice", 
						message       => "scan_hpacucli_note_0003", 
						variables     => $variables, 
						show_header   => 1, 
						sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
						set_by        => $THIS_FILE,
					});
					
					# Quote some stuff manually
					my $quoted_scan_hpacucli_logical_drive_size        =  $anvil->Database->quote($new_scan_hpacucli_logical_drive_size);
					my $quoted_scan_hpacucli_logical_drive_strip_size  =  $anvil->Database->quote($new_scan_hpacucli_logical_drive_strip_size);
					my $quoted_scan_hpacucli_logical_drive_stripe_size =  $anvil->Database->quote($new_scan_hpacucli_logical_drive_stripe_size);
					   $quoted_scan_hpacucli_logical_drive_size        =~ s/^'(.*?)'$/$1/;
					   $quoted_scan_hpacucli_logical_drive_strip_size  =~ s/^'(.*?)'$/$1/;
					   $quoted_scan_hpacucli_logical_drive_stripe_size =~ s/^'(.*?)'$/$1/;
					
					# Now INERT variables.
					my $query = "
INSERT INTO 
    scan_hpacucli_logical_drives 
(
    scan_hpacucli_logical_drive_uuid, 
    scan_hpacucli_logical_drive_host_uuid, 
    scan_hpacucli_logical_drive_array_uuid, 
    scan_hpacucli_logical_drive_name, 
    scan_hpacucli_logical_drive_caching, 
    scan_hpacucli_logical_drive_os_device_name, 
    scan_hpacucli_logical_drive_type, 
    scan_hpacucli_logical_drive_raid_level, 
    scan_hpacucli_logical_drive_size, 
    scan_hpacucli_logical_drive_strip_size, 
    scan_hpacucli_logical_drive_stripe_size, 
    scan_hpacucli_logical_drive_status, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    ".$anvil->Database->quote($scan_hpacucli_array_uuid).", 
    ".$anvil->Database->quote($scan_hpacucli_logical_drive_name).", 
    ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_caching).", 
    ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_os_device_name).", 
    ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_type).", 
    ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_raid_level).", 
    $quoted_scan_hpacucli_logical_drive_size, 
    $quoted_scan_hpacucli_logical_drive_strip_size, 
    $quoted_scan_hpacucli_logical_drive_stripe_size, 
    ".$anvil->Database->quote($new_scan_hpacucli_logical_drive_status).", 
    ".$anvil->Database->quote($anvil->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-hpacucli'}{queries}}, $query;
				}
				
				# Process logical drive variables now. Note that there are no temperatures.
				foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}})
				{
					# Insert the variables.
					my $new_scan_hpacucli_variable_value = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{data}{detail}{$scan_hpacucli_variable_name};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						scan_hpacucli_variable_name      => $scan_hpacucli_variable_name, 
						new_scan_hpacucli_variable_value => $new_scan_hpacucli_variable_value, 
					}});
					
					# Have we seen this variable before?
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::scan_hpacucli_logical_drives::source_uuid::${scan_hpacucli_logical_drive_uuid}::detail::${scan_hpacucli_variable_name}::scan_hpacucli_variable_uuid" => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_logical_drives}{source_uuid}{$scan_hpacucli_logical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}, 
					}});
					if ($anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_logical_drives}{source_uuid}{$scan_hpacucli_logical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid})
					{
						# Exists. Has it changed?
						my $scan_hpacucli_variable_uuid      = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_logical_drives}{source_uuid}{$scan_hpacucli_logical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid};
						my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_logical_drives}{source_uuid}{$scan_hpacucli_logical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value};
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							scan_hpacucli_variable_uuid      => $scan_hpacucli_variable_uuid, 
							old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, 
						}});
						
						# delete this so that we know it was processed.
						delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_logical_drives}{source_uuid}{$scan_hpacucli_logical_drive_uuid}{detail}{$scan_hpacucli_variable_name};
						
						if ($old_scan_hpacucli_variable_value ne $new_scan_hpacucli_variable_value)
						{
							# Now update. Alert the user as a warning, this 
							# should rarely ever change.
							my $variables = {
								logical_drive => $scan_hpacucli_logical_drive_name,
								array         => $scan_hpacucli_array_name,
								serial_number => $scan_hpacucli_controller_serial_number,
								variable_name => $scan_hpacucli_variable_name,
								old_value     => $old_scan_hpacucli_variable_value ? $old_scan_hpacucli_variable_value : "--",
								new_value     => $new_scan_hpacucli_variable_value ? $new_scan_hpacucli_variable_value : "--",
							};
							$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0066", variables => $variables});
							$anvil->Alert->register({
								clear_alert   => 0, 
								alert_level   => "warning", 
								message       => "scan_hpacucli_note_0066", 
								variables     => $variables, 
								show_header   => 1, 
								sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
								set_by        => $THIS_FILE,
							});
							
							# UPDATE 
							my $query = "
UPDATE 
    scan_hpacucli_variables 
SET 
    scan_hpacucli_variable_value = ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", 
    modified_date                = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_variable_uuid  = ".$anvil->Database->quote($scan_hpacucli_variable_uuid)."
;";
							# Now record the query in the array
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
							push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
						}
					}
					else
					{
						# New. Alert the user.
						my $variables = {
							name  => $scan_hpacucli_variable_name,
							value => $new_scan_hpacucli_variable_value,
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0004", variables => $variables});
						$anvil->Alert->register({
							clear_alert   => 0, 
							alert_level   => "notice", 
							message       => "scan_hpacucli_note_0004", 
							variables     => $variables, 
							show_header   => 0, 
							sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
							set_by        => $THIS_FILE,
						});
						
						# INSERT
						my $query = "
INSERT INTO 
    scan_hpacucli_variables
(
    scan_hpacucli_variable_uuid, 
    scan_hpacucli_variable_host_uuid, 
    scan_hpacucli_variable_source_table, 
    scan_hpacucli_variable_source_uuid, 
    scan_hpacucli_variable_is_temperature, 
    scan_hpacucli_variable_name, 
    scan_hpacucli_variable_value, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($anvil->Get->uuid()).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    'scan_hpacucli_logical_drives', 
    ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid).", 
    FALSE, 
    ".$anvil->Database->quote($scan_hpacucli_variable_name).", 
    ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", 
    ".$anvil->Database->quote($anvil->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-hpacucli'}{queries}}, $query;
					}
				}
				
				# Physical Disks.
				foreach my $port (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}})
				{
					foreach my $box (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}})
					{
						foreach my $bay (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}})
						{
							# Throw this into a function to get out of 
							# indent-hell.
							process_a_drive($anvil, $scan_hpacucli_controller_serial_number, $scan_hpacucli_logical_drive_uuid, $scan_hpacucli_array_name, $scan_hpacucli_logical_drive_name, $port, $box, $bay);
						}
					}
				}
			}
		}
		
		# Look for deleted arrays.
		foreach my $scan_hpacucli_array_uuid (keys %{$anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}})
		{
			my $old_scan_hpacucli_array_name               = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_name};
			my $old_scan_hpacucli_array_controller_uuid    = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_controller_uuid};
			my $old_scan_hpacucli_controller_serial_number = $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$old_scan_hpacucli_array_controller_uuid};
			my $old_scan_hpacucli_array_status             = $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_status};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				old_scan_hpacucli_array_name               => $old_scan_hpacucli_array_name, 
				old_scan_hpacucli_array_controller_uuid    => $old_scan_hpacucli_array_controller_uuid, 
				old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number, 
				old_scan_hpacucli_array_status             => $old_scan_hpacucli_array_status, 
			}});
			
			next if $old_scan_hpacucli_array_name   eq "ZZZZ";
			next if $old_scan_hpacucli_array_status eq "VANISHED";
			
			my $variables = {
				name          => $old_scan_hpacucli_array_name,
				serial_number => $old_scan_hpacucli_controller_serial_number,
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0031", variables => $variables});
			$anvil->Alert->register({
				clear_alert   => 0, 
				alert_level   => "warning", 
				message       => "scan_hpacucli_note_0031", 
				variables     => $variables, 
				show_header   => 0, 
				sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
				set_by        => $THIS_FILE,
			});
			
			my $query = "
UPDATE 
    scan_hpacucli_arrays
SET
    scan_hpacucli_array_status = 'VANISHED', 
    modified_date              = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_array_uuid   = ".$anvil->Database->quote($scan_hpacucli_array_uuid)." 
;";
			# Now record the query in the array
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
		}
		
		# Look for deleted logical drives.
		foreach my $scan_hpacucli_logical_drive_uuid (keys %{$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}})
		{
			# Look for changes
			my $old_scan_hpacucli_logical_drive_array_uuid = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_array_uuid};
			my $old_scan_hpacucli_logical_drive_name       = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_name};
			my $old_scan_hpacucli_logical_drive_status     = $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_status};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_hpacucli_logical_drive_uuid           => $scan_hpacucli_logical_drive_uuid, 
				old_scan_hpacucli_logical_drive_array_uuid => $old_scan_hpacucli_logical_drive_array_uuid, 
				old_scan_hpacucli_logical_drive_name       => $old_scan_hpacucli_logical_drive_name, 
				old_scan_hpacucli_logical_drive_status     => $old_scan_hpacucli_logical_drive_status, 
			}});
			
			next if $old_scan_hpacucli_logical_drive_name   eq "9999";
			next if $old_scan_hpacucli_logical_drive_status eq "VANISHED";
			
			my $variables = {
				logical_drive => $old_scan_hpacucli_logical_drive_name,
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0044", variables => $variables});
			$anvil->Alert->register({
				clear_alert   => 0, 
				alert_level   => "warning", 
				message       => "scan_hpacucli_note_0044", 
				variables     => $variables, 
				show_header   => 0, 
				sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
				set_by        => $THIS_FILE,
			});
			
			my $query = "
UPDATE 
    scan_hpacucli_logical_drives
SET
    scan_hpacucli_logical_drive_status = 'VANISHED', 
    modified_date                      = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_logical_drive_uuid   = ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid)." 
;";
			# Now record the query in the array
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
		}
	}
	
	# Now commit the changes.
	$anvil->Database->write({query => $anvil->data->{'scan-hpacucli'}{queries}, source => $THIS_FILE, line => __LINE__});
	$anvil->data->{'scan-hpacucli'}{queries} = [];
	
	return(0);
}

# Process a specific drive
sub process_a_drive
{
	my ($anvil, $scan_hpacucli_controller_serial_number, $scan_hpacucli_logical_drive_uuid, $scan_hpacucli_array_name, $scan_hpacucli_logical_drive_name, $port, $box, $bay) = @_;
	
	my $scan_hpacucli_physical_drive_uuid                    = "";
	my $scan_hpacucli_physical_drive_serial_number           = "";
	my $new_scan_hpacucli_physical_drive_model               = "";
	my $new_scan_hpacucli_physical_drive_interface           = "";
	my $new_scan_hpacucli_physical_drive_status              = "";
	my $new_scan_hpacucli_physical_drive_size                = 0;
	my $new_scan_hpacucli_physical_drive_type                = "";
	my $new_scan_hpacucli_physical_drive_rpm                 = 0;
	my $new_scan_hpacucli_physical_drive_temperature         = "";
	my $new_scan_hpacucli_physical_drive_last_failure_reason = ""; 
	my $maximum_drive_temperature                            = 0;
	
	# Serial Number
	if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{serial_number})
	{
		$scan_hpacucli_physical_drive_serial_number = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{serial_number};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_physical_drive_serial_number => $scan_hpacucli_physical_drive_serial_number }});
	}
	# Model
	if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{model})
	{
		$new_scan_hpacucli_physical_drive_model = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{model};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_model => $new_scan_hpacucli_physical_drive_model }});
	}
	# Interface
	if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{interface_type})
	{
		$new_scan_hpacucli_physical_drive_interface = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{interface_type};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_interface => $new_scan_hpacucli_physical_drive_interface }});
	}
	# Status
	if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{status})
	{
		$new_scan_hpacucli_physical_drive_status = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{status};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_status => $new_scan_hpacucli_physical_drive_status }});
	}
	# Size
	if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{size})
	{
		$new_scan_hpacucli_physical_drive_size = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{size};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"new_scan_hpacucli_physical_drive_size" => $new_scan_hpacucli_physical_drive_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_physical_drive_size}).")", 
		}});
	}
	# Type
	if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{drive_type})
	{
		$new_scan_hpacucli_physical_drive_type = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{drive_type};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_type => $new_scan_hpacucli_physical_drive_type }});
	}
	# RPM (0 if SSD)
	if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{rotational_speed})
	{
		$new_scan_hpacucli_physical_drive_rpm = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{rotational_speed};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_rpm => $new_scan_hpacucli_physical_drive_rpm }});
	}
	# Temperature
	if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{temperature}{current_temperature})
	{
		$new_scan_hpacucli_physical_drive_temperature = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{temperature}{current_temperature};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_temperature => $new_scan_hpacucli_physical_drive_temperature }});
	}
	# Last failure reason
	if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{last_failure_reason})
	{
		$new_scan_hpacucli_physical_drive_last_failure_reason = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{last_failure_reason};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_physical_drive_last_failure_reason => $new_scan_hpacucli_physical_drive_last_failure_reason }});
	}
	# Maximum temperature
	if ($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{temperature}{maximum_temperature})
	{
		$maximum_drive_temperature = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{temperature}{maximum_temperature};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { maximum_drive_temperature => $maximum_drive_temperature }});
	}
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		scan_hpacucli_physical_drive_serial_number           => $scan_hpacucli_physical_drive_serial_number, 
		new_scan_hpacucli_physical_drive_model               => $new_scan_hpacucli_physical_drive_model, 
		new_scan_hpacucli_physical_drive_interface           => $new_scan_hpacucli_physical_drive_interface, 
		new_scan_hpacucli_physical_drive_status              => $new_scan_hpacucli_physical_drive_status, 
		new_scan_hpacucli_physical_drive_size                => $new_scan_hpacucli_physical_drive_size, 
		new_scan_hpacucli_physical_drive_type                => $new_scan_hpacucli_physical_drive_type, 
		new_scan_hpacucli_physical_drive_rpm                 => $new_scan_hpacucli_physical_drive_rpm, 
		new_scan_hpacucli_physical_drive_temperature         => $new_scan_hpacucli_physical_drive_temperature, 
		new_scan_hpacucli_physical_drive_last_failure_reason => $new_scan_hpacucli_physical_drive_last_failure_reason, 
		maximum_drive_temperature                            => $maximum_drive_temperature, 
	}});
	
	# Delete the Port, Box and Bay values so that they don't get processed as their own variables.
	delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{port};
	delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{box};
	delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{bay};
	
	# Die if we don't have a serial number
	if (not $scan_hpacucli_physical_drive_serial_number)
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_hpacucli_error_0011", variables => { 
			serial_number      => $scan_hpacucli_controller_serial_number, 
			array_name         => $scan_hpacucli_array_name, 
			logical_drive_name => $scan_hpacucli_logical_drive_name, 
			port               => $port, 
			box                => $box, 
			bay                => $bay, 
		}});
		$anvil->nice_exit({exit_code => 9});
	}
	
	# Have we seen this drive before?
	if ($anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number})
	{
		# Yup! Look for changes.
		$scan_hpacucli_physical_drive_uuid = $anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_physical_drive_uuid => $scan_hpacucli_physical_drive_uuid }});
		
		# Gather the old data.
		my $old_scan_hpacucli_logical_drive_uuid                 = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_logical_drive_uuid};
		my $old_scan_hpacucli_physical_drive_model               = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_model};
		my $old_scan_hpacucli_physical_drive_interface           = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_interface};
		my $old_scan_hpacucli_physical_drive_status              = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_status};
		my $old_scan_hpacucli_physical_drive_size                = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_size};
		my $old_scan_hpacucli_physical_drive_type                = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_type};
		my $old_scan_hpacucli_physical_drive_rpm                 = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_rpm};
		my $old_scan_hpacucli_physical_drive_temperature         = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_temperature};
		my $old_scan_hpacucli_physical_drive_last_failure_reason = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_last_failure_reason};
		my $old_scan_hpacucli_physical_drive_port                = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_port};
		my $old_scan_hpacucli_physical_drive_box                 = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_box};
		my $old_scan_hpacucli_physical_drive_bay                 = $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_bay};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			old_scan_hpacucli_logical_drive_uuid                 => $old_scan_hpacucli_logical_drive_uuid, 
			old_scan_hpacucli_physical_drive_model               => $old_scan_hpacucli_physical_drive_model, 
			old_scan_hpacucli_physical_drive_interface           => $old_scan_hpacucli_physical_drive_interface, 
			old_scan_hpacucli_physical_drive_status              => $old_scan_hpacucli_physical_drive_status, 
			old_scan_hpacucli_physical_drive_size                => $old_scan_hpacucli_physical_drive_size, 
			old_scan_hpacucli_physical_drive_type                => $old_scan_hpacucli_physical_drive_type, 
			old_scan_hpacucli_physical_drive_rpm                 => $old_scan_hpacucli_physical_drive_rpm, 
			old_scan_hpacucli_physical_drive_temperature         => $old_scan_hpacucli_physical_drive_temperature, 
			old_scan_hpacucli_physical_drive_last_failure_reason => $old_scan_hpacucli_physical_drive_last_failure_reason, 
			old_scan_hpacucli_physical_drive_port                => $old_scan_hpacucli_physical_drive_port, 
			old_scan_hpacucli_physical_drive_box                 => $old_scan_hpacucli_physical_drive_box, 
			old_scan_hpacucli_physical_drive_bay                 => $old_scan_hpacucli_physical_drive_bay, 
		}});
		
		# delete this so that we know it was processed.
		delete $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid};
		
		my $update = 0;
		# Did the drive move between logical drives?
		if ($scan_hpacucli_logical_drive_uuid ne $old_scan_hpacucli_logical_drive_uuid)
		{
			$update = 1;
			
			# We'll need to get the host, controller serial number and array name
			my $query = "
SELECT 
    a.host_name, 
    b.scan_hpacucli_controller_serial_number, 
    c.scan_hpacucli_array_name, 
    d.scan_hpacucli_logical_drive_name 
FROM 
    hosts a, 
    scan_hpacucli_controllers b, 
    scan_hpacucli_arrays c, 
    scan_hpacucli_logical_drives d 
WHERE 
    a.host_uuid                     = b.scan_hpacucli_controller_host_uuid 
AND 
    b.scan_hpacucli_controller_uuid = c.scan_hpacucli_array_controller_uuid 
AND 
    c.scan_hpacucli_array_uuid      = d.scan_hpacucli_logical_drive_array_uuid 
AND 
    c.scan_hpacucli_array_uuid      = ".$anvil->Database->quote($old_scan_hpacucli_logical_drive_uuid)."
;";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			
			my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
			my $count   = @{$results};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				results => $results, 
				count   => $count, 
			}});
			my $old_host_name                              = $results->[0]->[0] ? $results->[0]->[0] : "--";
			my $old_scan_hpacucli_controller_serial_number = $results->[0]->[1] ? $results->[0]->[1] : "--";
			my $old_scan_hpacucli_array_name               = $results->[0]->[2] ? $results->[0]->[2] : "--";
			my $old_scan_hpacucli_logical_drive_name       = $results->[0]->[3] ? $results->[0]->[3] : "--";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				old_host_name                              => $old_host_name, 
				old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number, 
				old_scan_hpacucli_array_name               => $old_scan_hpacucli_array_name, 
				old_scan_hpacucli_logical_drive_name       => $old_scan_hpacucli_logical_drive_name, 
			}});
		
			# Send an alert telling the drive has moved.
			my $variables = {
				drive_serial_number          => $scan_hpacucli_physical_drive_serial_number, 
				old_host_name                => $old_host_name,
				new_host_name                => $anvil->Get->host_name,
				new_controller_serial_number => $scan_hpacucli_controller_serial_number, 
				old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number, 
				new_array_name               => $scan_hpacucli_array_name, 
				old_array_name               => $scan_hpacucli_array_name,
				new_logical_drive_name       => $scan_hpacucli_logical_drive_name, 
				old_logical_drive_name       => $old_scan_hpacucli_logical_drive_name
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0047", variables => $variables});
			$anvil->Alert->register({
				clear_alert   => 0, 
				alert_level   => "warning", 
				message       => "scan_hpacucli_note_0047", 
				variables     => $variables, 
				show_header   => 1, 
				sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
				set_by        => $THIS_FILE,
			});
		}
		
		# Has the status changed?
		if ($old_scan_hpacucli_physical_drive_status ne $new_scan_hpacucli_physical_drive_status)
		{
			$update = 1;
			
			# Yup. Start with an alert about it being not OK, and change if it is now OK.
			my $cleared     = 0;
			my $message_key = "scan_hpacucli_note_0048";
			
			# Did it return?
			if ($old_scan_hpacucli_physical_drive_status eq "VANISHED")
			{
				# The drive is back.
				$message_key = "scan_hpacucli_note_0050";
			}
			elsif (lc($new_scan_hpacucli_physical_drive_status) eq "ok")
			{
				# Drive is OK again.
				$cleared     = 1;
				$message_key = "scan_hpacucli_note_0051";
			}
			my $variables = {
				serial_number => $scan_hpacucli_physical_drive_serial_number, 
				old_status    => $old_scan_hpacucli_physical_drive_status,
				new_status    => $new_scan_hpacucli_physical_drive_status,
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
			$anvil->Alert->register({
				clear_alert   => $cleared, 
				alert_level   => "warning", 
				message       => $message_key, 
				variables     => $variables, 
				show_header   => 1, 
				sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
				set_by        => $THIS_FILE,
			});
		}

		# Did the temperature change? Whether it did or not, we need to record the current 
		# temperature state.
		### NOTE: HP tells us the maximum temperature each of its drives can handle. This is 
		###       a low number, so we need to tighten up some thresholds compared to usual 
		###       ranges.
		# Set defaults
		my $high_critical       = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{high_critical};
		my $high_warning        = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{high_warning};
		my $low_warning         = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{low_warning};
		my $low_critical        = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{low_critical};
		my $jump                = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{jump};
		my $buffer              = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{buffer};
		my $clear_high_critical = $high_critical - $buffer;
		my $clear_high_warning  = $high_warning - $buffer;
		my $clear_low_critical  = $low_critical - $buffer;
		my $clear_low_warning   = $low_warning - $buffer;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			high_critical       => $high_critical, 
			high_warning        => $high_warning, 
			low_warning         => $low_warning, 
			low_critical        => $low_critical, 
			jump                => $jump, 
			buffer              => $buffer, 
			clear_high_critical => $clear_high_critical, 
			clear_high_warning  => $clear_high_warning, 
			clear_low_critical  => $clear_low_critical, 
			clear_low_warning   => $clear_low_warning, 
		}});
		
		# Fine-tune the alert thresholds
		if ($clear_high_critical < $high_warning)
		{
			$clear_high_critical = $high_warning + 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }});
		}
		if ($clear_low_critical > $low_warning)
		{
			$clear_low_critical = $low_warning - 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }});
		}
		
		# Did we get a maximum temperature from the drive?
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			maximum_drive_temperature                   => $maximum_drive_temperature, 
			"scan-hpacucli::ignore_maximum_temperature" => $anvil->data->{'scan-hpacucli'}{ignore_maximum_temperature}, 
		}});
		if (($maximum_drive_temperature) && (not $anvil->data->{'scan-hpacucli'}{ignore_maximum_temperature}))
		{
			$high_critical       = $maximum_drive_temperature;
			$high_warning        = $maximum_drive_temperature - 2;
			$clear_high_critical = $high_critical - $buffer;
			$clear_high_warning  = $high_warning - $buffer;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				high_critical       => $high_critical, 
				high_warning        => $high_warning, 
				clear_high_critical => $clear_high_critical, 
				clear_high_warning  => $clear_high_warning, 
			}});
			
			# Fine-tune the alert thresholds
			if ($clear_high_critical < $high_warning)
			{
				$clear_high_critical = $high_warning + 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }});
			}
			if ($clear_low_critical > $low_warning)
			{
				$clear_low_critical = $low_warning - 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }});
			}
		}
		
		# Clear alerts, if needed. The order is important as clearing a warning will replace 
		# clearing a critical when a sensor goes critical -> ok in one scan. Once done, we'll
		# check if we've crossed into a warning or critical state. If so, those will replace 
		# any cleared messages.
		my $cleared     = 0;
		my $alert_level = "info";
		my $message_key = "scan_hpacucli_note_0053";
		my $delta       = 0;
		if ($new_scan_hpacucli_physical_drive_temperature)
		{
			if ($new_scan_hpacucli_physical_drive_temperature < $clear_high_critical)
			{
				my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_critical", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$cleared     = 1;
					$alert_level = "critical";
					$message_key = "scan_hpacucli_note_0054";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						cleared     => $cleared,
						alert_level => $alert_level, 
						message_key => $message_key, 
					}});
				}
			}
			if ($new_scan_hpacucli_physical_drive_temperature < $clear_high_warning)
			{
				my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_warning", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					# The temperature is no longer 
					# warning, and it didn't just go 
					# critical
					$cleared     = 1;
					$alert_level = "warning";
					$message_key = "scan_hpacucli_note_0055";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						cleared     => $cleared,
						alert_level => $alert_level, 
						message_key => $message_key, 
					}});
				}
			}
			if ($new_scan_hpacucli_physical_drive_temperature > $clear_low_critical)
			{
				my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_critical", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$cleared     = 1;
					$alert_level = "critical";
					$message_key = "scan_hpacucli_note_0056";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						cleared     => $cleared,
						alert_level => $alert_level, 
						message_key => $message_key, 
					}});
				}
			}
			if ($new_scan_hpacucli_physical_drive_temperature > $clear_low_warning)
			{
				my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_warning", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$cleared     = 1;
					$alert_level = "warning";
					$message_key = "scan_hpacucli_note_0057";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						cleared     => $cleared,
						alert_level => $alert_level, 
						message_key => $message_key, 
					}});
				}
			}
			
			# Now see if the temperature has crossed into a warning or critical state.
			my $temperature_state = "ok";
			my $temperature_is    = "nominal";
			if ($new_scan_hpacucli_physical_drive_temperature > $high_critical)
			{
				# Crossed the high critical threshold.
				my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_critical", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$alert_level = "critical";
					$message_key = "scan_hpacucli_note_0060";
				}
				$temperature_state = "critical";
				$temperature_is    = "high";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					temperature_state => $temperature_state, 
					temperature_is    => $temperature_is, 
				}});
			}
			elsif ($new_scan_hpacucli_physical_drive_temperature > $high_warning)
			{
				# Crossed the high warning threshold.
				my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_warning", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$alert_level = "warning";
					$message_key = "scan_hpacucli_note_0061";
				}
				$temperature_state = "warning";
				$temperature_is    = "high";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					temperature_state => $temperature_state, 
					temperature_is    => $temperature_is, 
				}});
			}
			elsif ($new_scan_hpacucli_physical_drive_temperature < $low_critical)
			{
				# Dropped below the low critical threshold.
				my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_critical", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$alert_level = "critical";
					$message_key = "scan_hpacucli_note_0062";
				}
				$temperature_state = "critical";
				$temperature_is    = "low";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"temperature_state" => $temperature_state, 
					"temperature_is"    => $temperature_is, 
				}});
			}
			elsif ($new_scan_hpacucli_physical_drive_temperature < $low_warning)
			{
				# Crossed the low warning threshold.
				my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_warning", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$alert_level = "warning";
					$message_key = "scan_hpacucli_note_0063";
				}
				$temperature_state = "warning";
				$temperature_is    = "low";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					temperature_state => $temperature_state, 
					temperature_is    => $temperature_is, 
				}});
			}
			else
			{
				# Did it change enough to trigger a jump alert?
				if ($new_scan_hpacucli_physical_drive_temperature > $old_scan_hpacucli_physical_drive_temperature)
				{
					# Jumped
					$delta = $new_scan_hpacucli_physical_drive_temperature - $old_scan_hpacucli_physical_drive_temperature;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { delta => $delta }});
					if ($delta >= $jump)
					{
						# Big jump.
						$alert_level = "warning";
						$message_key = "scan_hpacucli_note_0058";
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							alert_level => $alert_level, 
							message_key => $message_key, 
						}});
					}
				}
				else
				{
					# Dropped
					$delta = $old_scan_hpacucli_physical_drive_temperature - $new_scan_hpacucli_physical_drive_temperature;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { delta => $delta }});
					if ($delta >= $jump)
					{
						# Big drop.
						$alert_level = "warning";
						$message_key = "scan_hpacucli_note_0059";
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							alert_level => $alert_level, 
							message_key => $message_key, 
						}});
					}
				}
			}
			
			# Record this for later processing into the 'temperature' table.
			my $sensor_host_key = "physical_drive:".$scan_hpacucli_physical_drive_serial_number;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_host_key => $sensor_host_key }});
			
			$anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_value_c} = $new_scan_hpacucli_physical_drive_temperature;
			$anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_state}   = $temperature_state;
			$anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_is}      = $temperature_is;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_value_c" => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_value_c}, 
				"new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_state"   => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_state}, 
				"new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_is"      => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_is}, 
			}});
		}
		
		# Now, if the temperature changed, update and send an alert if appropriate.
		if ($new_scan_hpacucli_physical_drive_temperature ne $old_scan_hpacucli_physical_drive_temperature)
		{
			# Yup. Analyze
			$update = 1;
			
			# Send an alert telling the user that we've found a variable for this drive. Note 
			# that we add ' C' to the temperatures so that they get translated to 'Â°F' if desired
			# by the reader.
			my $variables = {
				serial_number             => $scan_hpacucli_physical_drive_serial_number,
				old_temperature           => $old_scan_hpacucli_physical_drive_temperature ? $old_scan_hpacucli_physical_drive_temperature." °C" : "--",
				new_temperature           => $new_scan_hpacucli_physical_drive_temperature ? $new_scan_hpacucli_physical_drive_temperature." °C" : "--",
				delta                     => $delta." °C",
				high_critical_temperature => $high_critical." °C", 
				high_warning_temperature  => $high_warning." °C", 
				low_critical_temperature  => $low_critical." °C", 
				low_warning_temperature   => $low_warning." °C", 
			};
			my $log_level = (($alert_level eq "warning") or ($alert_level eq "critical")) ? 1 : 2;
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
			$anvil->Alert->register({
				clear_alert   => $cleared, 
				alert_level   => $alert_level, 
				message       => $message_key, 
				variables     => $variables, 
				show_header   => 1, 
				sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
				set_by        => $THIS_FILE,
			});
		}
		# Anything else?
		if (($old_scan_hpacucli_physical_drive_model               ne $new_scan_hpacucli_physical_drive_model)               or 
		    ($old_scan_hpacucli_physical_drive_interface           ne $new_scan_hpacucli_physical_drive_interface)           or 
		    ($old_scan_hpacucli_physical_drive_size                ne $new_scan_hpacucli_physical_drive_size)                or 
		    ($old_scan_hpacucli_physical_drive_rpm                 ne $new_scan_hpacucli_physical_drive_rpm)                 or 
		    ($new_scan_hpacucli_physical_drive_last_failure_reason ne $old_scan_hpacucli_physical_drive_last_failure_reason) or 
		    ($port                                                 ne $old_scan_hpacucli_physical_drive_port)                or 
		    ($box                                                  ne $old_scan_hpacucli_physical_drive_box)                 or 
		    ($bay                                                  ne $old_scan_hpacucli_physical_drive_bay))
		{
			# Something else changed. These normally shouldn't change...
			   $update    = 1;
			my $variables = {
				serial_number           => $scan_hpacucli_physical_drive_serial_number, 
				old_model               => $old_scan_hpacucli_physical_drive_model,
				new_model               => $new_scan_hpacucli_physical_drive_model,
				old_interface           => $old_scan_hpacucli_physical_drive_interface,
				new_interface           => $new_scan_hpacucli_physical_drive_interface,
				old_size                => $anvil->Database->quote($old_scan_hpacucli_physical_drive_size),
				new_size                => $anvil->Database->quote($new_scan_hpacucli_physical_drive_size),
				old_rpm                 => $old_scan_hpacucli_physical_drive_rpm,
				new_rpm                 => $new_scan_hpacucli_physical_drive_rpm,
				old_last_failure_reason => $old_scan_hpacucli_physical_drive_last_failure_reason ? $old_scan_hpacucli_physical_drive_last_failure_reason : "--",
				new_last_failure_reason => $new_scan_hpacucli_physical_drive_last_failure_reason ? $new_scan_hpacucli_physical_drive_last_failure_reason : "--",
				old_port                => $old_scan_hpacucli_physical_drive_port,
				new_port                => $port,
				old_box                 => $old_scan_hpacucli_physical_drive_box,
				new_box                 => $box,
				old_bay                 => $old_scan_hpacucli_physical_drive_bay,
				new_bay                 => $bay,
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0052", variables => $variables});
			$anvil->Alert->register({
				clear_alert   => $cleared, 
				alert_level   => "warning", 
				message       => "scan_hpacucli_note_0052", 
				variables     => $variables, 
				show_header   => 1, 
				sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
				set_by        => $THIS_FILE,
			});
		}
		
		if ($update)
		{
			# UPDATE
			my $query = "
UPDATE 
    scan_hpacucli_physical_drives
SET
    scan_hpacucli_physical_drive_logical_drive_uuid  = ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid).", 
    scan_hpacucli_physical_drive_serial_number       = ".$anvil->Database->quote($scan_hpacucli_physical_drive_serial_number).", 
    scan_hpacucli_physical_drive_model               = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_model).", 
    scan_hpacucli_physical_drive_interface           = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_interface).", 
    scan_hpacucli_physical_drive_status              = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_status).", 
    scan_hpacucli_physical_drive_size                = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_size).", 
    scan_hpacucli_physical_drive_type                = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_type).", 
    scan_hpacucli_physical_drive_rpm                 = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_rpm).", 
    scan_hpacucli_physical_drive_temperature         = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_temperature).", 
    scan_hpacucli_physical_drive_last_failure_reason = ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_last_failure_reason).", 
    scan_hpacucli_physical_drive_port                = ".$anvil->Database->quote($port).", 
    scan_hpacucli_physical_drive_box                 = ".$anvil->Database->quote($box).", 
    scan_hpacucli_physical_drive_bay                 = ".$anvil->Database->quote($bay).", 
    modified_date                                    = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_physical_drive_uuid                = ".$anvil->Database->quote($scan_hpacucli_physical_drive_uuid)." 
;";
			# Now record the query in the array
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
		}
	}
	else
	{
		# New, INSERT it.
		$scan_hpacucli_physical_drive_uuid                                                                       = $anvil->Get->uuid();
		$anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number} = $scan_hpacucli_physical_drive_uuid;
		$anvil->data->{'scan-hpacucli'}{physical_drives}{by_uuid}{$scan_hpacucli_physical_drive_uuid}            = $scan_hpacucli_physical_drive_serial_number;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan-hpacucli::physical_drives::by_serial::${scan_hpacucli_physical_drive_serial_number}" => $anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number}, 
			"scan-hpacucli::physical_drives::by_uuid::${scan_hpacucli_physical_drive_uuid}"            => $anvil->data->{'scan-hpacucli'}{physical_drives}{by_uuid}{$scan_hpacucli_physical_drive_uuid}, 
		}});
		
		# Send an alert telling the user we found a new drive.
		my $variables = {
			controller_serial_number => $scan_hpacucli_controller_serial_number, 
			array_name               => $scan_hpacucli_array_name, 
			logical_drive_name       => $scan_hpacucli_logical_drive_name, 
			port                     => $port, 
			box                      => $box, 
			bay                      => $bay, 
			drive_serial_number      => $scan_hpacucli_physical_drive_serial_number,
			model                    => $new_scan_hpacucli_physical_drive_model, 
			interface                => $new_scan_hpacucli_physical_drive_interface, 
			status                   => $new_scan_hpacucli_physical_drive_status, 
			size                     => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_physical_drive_size}), 
			type                     => $new_scan_hpacucli_physical_drive_type, 
			rpm                      => $new_scan_hpacucli_physical_drive_rpm, 
			temperature              => $new_scan_hpacucli_physical_drive_temperature         ? $new_scan_hpacucli_physical_drive_temperature." °C"    : "--", 
			last_failure_reason      => $new_scan_hpacucli_physical_drive_last_failure_reason ? $new_scan_hpacucli_physical_drive_last_failure_reason : "--",
		};
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0046", variables => $variables});
		$anvil->Alert->register({
			clear_alert   => 0, 
			alert_level   => "warning", 
			message       => "scan_hpacucli_note_0046", 
			variables     => $variables, 
			show_header   => 1, 
			sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
			set_by        => $THIS_FILE,
		});
		
		# Check for problems with this new drive.
		if (lc($new_scan_hpacucli_physical_drive_status) ne "ok")
		{
			# There's a problem, send an alert.
			my $variables = {
				controller_serial_number => $scan_hpacucli_controller_serial_number, 
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0064", variables => $variables});
			$anvil->Alert->register({
				alert_level   => "warning", 
				message       => "scan_hpacucli_note_0064", 
				variables     => $variables, 
				show_header   => 1, 
				sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
				set_by        => $THIS_FILE,
			});
		}
		
		# Check the temperature, if we read one.
		if ($new_scan_hpacucli_physical_drive_temperature =~ /^\d+/)
		{
			### NOTE: HP tells us the maximum temperature each of its drives can handle. This is 
			###       a low number, so we need to tighten up some thresholds compared to usual 
			###       ranges.
			# Set defaults
			my $high_critical       = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{high_critical};
			my $high_warning        = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{high_warning};
			my $low_warning         = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{low_warning};
			my $low_critical        = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{low_critical};
			my $jump                = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{jump};
			my $buffer              = $anvil->data->{'scan-hpacucli'}{thresholds}{drives}{buffer};
			my $clear_high_critical = $high_critical - $buffer;
			my $clear_high_warning  = $high_warning - $buffer;
			my $clear_low_critical  = $low_critical - $buffer;
			my $clear_low_warning   = $low_warning - $buffer;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				high_critical       => $high_critical, 
				high_warning        => $high_warning, 
				low_warning         => $low_warning, 
				low_critical        => $low_critical, 
				jump                => $jump, 
				buffer              => $buffer, 
				clear_high_critical => $clear_high_critical, 
				clear_high_warning  => $clear_high_warning, 
				clear_low_critical  => $clear_low_critical, 
				clear_low_warning   => $clear_low_warning, 
			}});
			
			# Fine-tune the alert thresholds
			if ($clear_high_critical < $high_warning)
			{
				$clear_high_critical = $high_warning + 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }});
			}
			if ($clear_low_critical > $low_warning)
			{
				$clear_low_critical = $low_warning - 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }});
			}
			
			# Did we get a maximum temperature from the drive?
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				maximum_drive_temperature                   => $maximum_drive_temperature, 
				"scan-hpacucli::ignore_maximum_temperature" => $anvil->data->{'scan-hpacucli'}{ignore_maximum_temperature}, 
			}});
			if (($maximum_drive_temperature) && (not $anvil->data->{'scan-hpacucli'}{ignore_maximum_temperature}))
			{
				$high_critical       = $maximum_drive_temperature;
				$high_warning        = $maximum_drive_temperature - 2;
				$clear_high_critical = $high_critical - $buffer;
				$clear_high_warning  = $high_warning - $buffer;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					high_critical       => $high_critical, 
					high_warning        => $high_warning, 
					clear_high_critical => $clear_high_critical, 
					clear_high_warning  => $clear_high_warning, 
				}});
				
				# Fine-tune the alert thresholds
				if ($clear_high_critical < $high_warning)
				{
					$clear_high_critical = $high_warning + 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }});
				}
				if ($clear_low_critical > $low_warning)
				{
					$clear_low_critical = $low_warning - 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }});
				}
			}
			
			# See if the temperature outside of the warning or critical thresholds.
			my $temperature_state = "ok";
			my $temperature_is    = "nominal";
			my $alert_level       = "info";
			my $message_key       = "scan_hpacucli_note_0069";
			if ($new_scan_hpacucli_physical_drive_temperature > $high_critical)
			{
				# Crossed the high critical threshold. This should always be unset because it
				# is a new variable, but check anyway.
				my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_critical", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$alert_level = "critical";
					$message_key = "scan_hpacucli_note_0060";
				}
				$temperature_state = "critical";
				$temperature_is    = "high";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					temperature_state => $temperature_state, 
					temperature_is    => $temperature_is, 
				}});
			}
			elsif ($new_scan_hpacucli_physical_drive_temperature > $high_warning)
			{
				# Crossed the high warning threshold. This should always be unset because it
				# is a new variable, but check anyway.
				my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_high_warning", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$alert_level = "warning";
					$message_key = "scan_hpacucli_note_0061";
				}
				$temperature_state = "warning";
				$temperature_is    = "high";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					temperature_state => $temperature_state, 
					temperature_is    => $temperature_is, 
				}});
			}
			elsif ($new_scan_hpacucli_physical_drive_temperature < $low_critical)
			{
				# Dropped below the low critical threshold. This should always be unset 
				# because it is a new variable, but check anyway.
				my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_critical", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$alert_level = "critical";
					$message_key = "scan_hpacucli_note_0062";
				}
				$temperature_state = "critical";
				$temperature_is    = "low";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					temperature_state => $temperature_state, 
					temperature_is    => $temperature_is, 
				}});
			}
			elsif ($new_scan_hpacucli_physical_drive_temperature < $low_warning)
			{
				# Crossed the low warning threshold. This should always be unset because it 
				# is a new variable, but check anyway.
				my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":physical_drive_low_warning", set_by => $THIS_FILE});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
				if ($changed)
				{
					$alert_level = "warning";
					$message_key = "scan_hpacucli_note_0063";
				}
				$temperature_state = "warning";
				$temperature_is    = "low";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					temperature_state => $temperature_state, 
					temperature_is    => $temperature_is, 
				}});
			}
			
			# Record this for later processing into the 'temperature' table.
			my $sensor_host_key = "physical_drive:".$scan_hpacucli_physical_drive_serial_number;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_host_key => $sensor_host_key }});
			
			$anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_value_c} = $new_scan_hpacucli_physical_drive_temperature;
			$anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_state}   = $temperature_state;
			$anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_is}      = $temperature_is;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_value_c" => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_value_c}, 
				"new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_state"   => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_state}, 
				"new::temperature::scan_hpacucli_physical_drive_temperature::${sensor_host_key}::temperature_is"      => $anvil->data->{new}{temperature}{scan_hpacucli_physical_drive_temperature}{$sensor_host_key}{temperature_is}, 
			}});
			
			if ($temperature_is ne "nominal")
			{
				# Send an alert telling the user that we've found a drive outside nominal 
				# temperature. Note that we add ' C' to the temperatures so that they get
				# translated to 'Â°F' if desired by the reader.
				my $variables = {
					serial_number             => $scan_hpacucli_controller_serial_number,
					temperature               => $new_scan_hpacucli_physical_drive_temperature ? $new_scan_hpacucli_physical_drive_temperature." °C" : "--",
					high_critical_temperature => $high_critical." °C", 
					high_warning_temperature  => $high_warning." °C", 
					low_critical_temperature  => $low_critical." °C", 
					low_warning_temperature	  => $low_warning." °C", 
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					clear_alert   => 0, 
					alert_level   => $alert_level, 
					message       => $message_key, 
					variables     => $variables, 
					show_header   => 1, 
					sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
					set_by        => $THIS_FILE,
				});
				
				### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'.
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0003", variables => $variables});
				$anvil->Alert->register({
					clear_alert   => 0, 
					alert_level   => "notice", 
					message       => "scan_hpacucli_note_0003", 
					variables     => $variables, 
					show_header   => 1, 
					sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
					set_by        => $THIS_FILE,
				});
			}
		}
		
		my $query = "
INSERT INTO 
    scan_hpacucli_physical_drives
(
    scan_hpacucli_physical_drive_uuid, 
    scan_hpacucli_physical_drive_host_uuid, 
    scan_hpacucli_physical_drive_logical_drive_uuid, 
    scan_hpacucli_physical_drive_serial_number, 
    scan_hpacucli_physical_drive_model, 
    scan_hpacucli_physical_drive_interface, 
    scan_hpacucli_physical_drive_status, 
    scan_hpacucli_physical_drive_size, 
    scan_hpacucli_physical_drive_type, 
    scan_hpacucli_physical_drive_rpm, 
    scan_hpacucli_physical_drive_temperature, 
    scan_hpacucli_physical_drive_last_failure_reason, 
    scan_hpacucli_physical_drive_port,
    scan_hpacucli_physical_drive_box,
    scan_hpacucli_physical_drive_bay,
    modified_date 
) VALUES (
    ".$anvil->Database->quote($scan_hpacucli_physical_drive_uuid).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    ".$anvil->Database->quote($scan_hpacucli_logical_drive_uuid).", 
    ".$anvil->Database->quote($scan_hpacucli_physical_drive_serial_number).", 
    ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_model).", 
    ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_interface).", 
    ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_status).", 
    ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_size).", 
    ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_type).", 
    ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_rpm).", 
    ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_temperature).", 
    ".$anvil->Database->quote($new_scan_hpacucli_physical_drive_last_failure_reason).", 
    ".$anvil->Database->quote($port).", 
    ".$anvil->Database->quote($box).", 
    ".$anvil->Database->quote($bay).", 
    ".$anvil->Database->quote($anvil->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-hpacucli'}{queries}}, $query;
	}
	
	# Process physical drive variables now. Note that there are no temperatures.
	foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}})
	{
		my $new_scan_hpacucli_variable_value = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{$scan_hpacucli_variable_name};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan_hpacucli_variable_name"      => $scan_hpacucli_variable_name, 
			"new_scan_hpacucli_variable_value" => $new_scan_hpacucli_variable_value, 
		}});
		
		# Have we seen this variable before?
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::scan_hpacucli_physical_drives::source_uuid::${scan_hpacucli_physical_drive_uuid}::detail::${scan_hpacucli_variable_name}::scan_hpacucli_variable_uuid" => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}, 
		}});
		if ($anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid})
		{
			# Exists. Has it changed?
			my $scan_hpacucli_variable_uuid      = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid};
			my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_hpacucli_variable_uuid      => $scan_hpacucli_variable_uuid, 
				old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, 
			}});
			
			# delete this so that we know it was processed.
			delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name};
			
			if ($old_scan_hpacucli_variable_value ne $new_scan_hpacucli_variable_value)
			{
				# Now update. Alert the user as a warning, these should rarely ever change.
				my $variables = {
					serial_number => $scan_hpacucli_physical_drive_serial_number,
					variable_name => $scan_hpacucli_variable_name,
					old_value     => $old_scan_hpacucli_variable_value ? $old_scan_hpacucli_variable_value : "--",
					new_value     => $new_scan_hpacucli_variable_value ? $new_scan_hpacucli_variable_value : "--",
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0065", variables => $variables});
				$anvil->Alert->register({
					clear_alert   => 0, 
					alert_level   => "warning", 
					message       => "scan_hpacucli_note_0065", 
					variables     => $variables, 
					show_header   => 0, 
					sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
					set_by        => $THIS_FILE,
				});
				
				# UPDATE 
				my $query = "
UPDATE 
    scan_hpacucli_variables 
SET 
    scan_hpacucli_variable_value = ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", 
    modified_date                = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_variable_uuid  = ".$anvil->Database->quote($scan_hpacucli_variable_uuid)."
;";
				# Now record the query in the array
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
			}
		}
		else
		{
			# Clear the hash key that was autovivified in the previous check so that it doesn't 
			# cause a loop when looking for vanished values.
			delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name};
			
			# New. Alert the user.
			my $variables = {
				name  => $scan_hpacucli_variable_name,
				value => $new_scan_hpacucli_variable_value,
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0004", variables => $variables});
			$anvil->Alert->register({
				clear_alert   => 0, 
				alert_level   => "notice", 
				message       => "scan_hpacucli_note_0004", 
				variables     => $variables, 
				show_header   => 0, 
				sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
				set_by        => $THIS_FILE,
			});
			
			# INSERT
			my $query = "
INSERT INTO 
    scan_hpacucli_variables
(
    scan_hpacucli_variable_uuid, 
    scan_hpacucli_variable_host_uuid, 
    scan_hpacucli_variable_source_table, 
    scan_hpacucli_variable_source_uuid, 
    scan_hpacucli_variable_is_temperature, 
    scan_hpacucli_variable_name, 
    scan_hpacucli_variable_value, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($anvil->Get->uuid()).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    'scan_hpacucli_physical_drives', 
    ".$anvil->Database->quote($scan_hpacucli_physical_drive_uuid).", 
    FALSE, 
    ".$anvil->Database->quote($scan_hpacucli_variable_name).", 
    ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", 
    ".$anvil->Database->quote($anvil->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-hpacucli'}{queries}}, $query;
		}
	}
	
	# Look for vanished variables for this drive.
	foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}})
	{
		my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value};
		my $old_scan_hpacucli_variable_uuid  = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drives}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{detail}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_hpacucli_variable_name      => $scan_hpacucli_variable_name, 
			old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, 
			old_scan_hpacucli_variable_uuid  => $old_scan_hpacucli_variable_uuid, 
		}});
		
		# If the old alarm state is already 'VANISHED', ignore it.
		next if $old_scan_hpacucli_variable_value eq "VANISHED";

		# Still here? Alert and UPDATE.
		### NOTE: For now, we're going to use warning level because cache_modules 
		###       should never vanish unless one failed. If that is the case, the 
		###       admin already knows, but this will let other notification targets
		###       know that the change has happened.
		my $variables = {
			serial_number => $scan_hpacucli_physical_drive_serial_number,
			name          => $scan_hpacucli_variable_name, 
		};
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0067", variables => $variables});
		$anvil->Alert->register({
			clear_alert   => 0, 
			alert_level   => "warning", 
			message       => "scan_hpacucli_note_0067", 
			variables     => $variables, 
			sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
			set_by        => $THIS_FILE,
		});
		
		my $query = "
UPDATE 
    scan_hpacucli_variables 
SET 
    scan_hpacucli_variable_value = 'VANISHED', 
    modified_date           = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_variable_uuid  = ".$anvil->Database->quote($old_scan_hpacucli_variable_uuid)."
;";
		# Now record the query in the array
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
	}
	
	# If this was a diagnostics run, check for error counters
	if ($anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics})
	{
		# These are stored in the DB as standard variables, but we use the source is 
		# 'scan_hpacucli_physical_drive_diagnostics' to distinguish them.
		if (exists $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_hard})
		{
			# We got the data
			foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}})
			{
				# Store this in the main hash.
				my $new_scan_hpacucli_variable_value = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$scan_hpacucli_logical_drive_name}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{'diagnostics'}{$scan_hpacucli_variable_name};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_hpacucli_variable_name      => $scan_hpacucli_variable_name, 
					new_scan_hpacucli_variable_value => $new_scan_hpacucli_variable_value, 
				}});
				
				### TODO
				# If the variable name has 'error' in it and the value is numeric, see if it
				# is > 5 and, if so, set the health.
				
				# Have we seen this variable before?
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::scan_hpacucli_physical_drive_diagnostics::source_uuid::${scan_hpacucli_physical_drive_uuid}::diagnostics::${scan_hpacucli_variable_name}::scan_hpacucli_variable_uuid" => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}, 
				}});
				if ($anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid})
				{
					# Exists. Has it changed?
					my $scan_hpacucli_variable_uuid      = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid};
					my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						scan_hpacucli_variable_uuid      => $scan_hpacucli_variable_uuid, 
						old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, 
					}});
					
					# Delete this so that we know it was processed.
					delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name};
					
					if ($old_scan_hpacucli_variable_value ne $new_scan_hpacucli_variable_value)
					{
						# Now update. Alert the user as a warning, these should rarely ever change.
						my $variables = {
							serial_number => $scan_hpacucli_physical_drive_serial_number,
							variable_name => $scan_hpacucli_variable_name,
							old_value     => $old_scan_hpacucli_variable_value ? $old_scan_hpacucli_variable_value : "--",
							new_value     => $new_scan_hpacucli_variable_value ? $new_scan_hpacucli_variable_value : "--",
						};
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0065", variables => $variables});
						$anvil->Alert->register({
							clear_alert   => 0, 
							alert_level   => "warning", 
							message       => "scan_hpacucli_note_0065", 
							variables     => $variables, 
							sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
							set_by        => $THIS_FILE,
						});
						
						# UPDATE 
						my $query = "
UPDATE 
    scan_hpacucli_variables 
SET 
    scan_hpacucli_variable_value = ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", 
    modified_date                = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_variable_uuid  = ".$anvil->Database->quote($scan_hpacucli_variable_uuid)."
;";
						# Now record the query in the array
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
						push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
					}
				}
				else
				{
					# Clear the hash key that was autovivified in the previous check so 
					# that it doesn't cause a loop when looking for vanished values.
					delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name};
					
					# New. Alert the user.
					my $variables = {
						name  => $scan_hpacucli_variable_name,
						value => $new_scan_hpacucli_variable_value,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0004", variables => $variables});
					$anvil->Alert->register({
						clear_alert   => 0, 
						alert_level   => "notice", 
						message       => "scan_hpacucli_note_0004", 
						show_header   => 0, 
						variables     => $variables, 
						sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
						set_by        => $THIS_FILE,
					});
					
					# INSERT
					my $query = "
INSERT INTO 
    scan_hpacucli_variables
(
    scan_hpacucli_variable_uuid, 
    scan_hpacucli_variable_host_uuid, 
    scan_hpacucli_variable_source_table, 
    scan_hpacucli_variable_source_uuid, 
    scan_hpacucli_variable_is_temperature, 
    scan_hpacucli_variable_name, 
    scan_hpacucli_variable_value, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($anvil->Get->uuid()).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    'scan_hpacucli_physical_drive_diagnostics', 
    ".$anvil->Database->quote($scan_hpacucli_physical_drive_uuid).", 
    FALSE, 
    ".$anvil->Database->quote($scan_hpacucli_variable_name).", 
    ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", 
    ".$anvil->Database->quote($anvil->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-hpacucli'}{queries}}, $query;
				}
			}
		}
		
		# Look for vanished diagnostics variables.
		foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}})
		{
			my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value};
			my $old_scan_hpacucli_variable_uuid  = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_physical_drive_diagnostics}{source_uuid}{$scan_hpacucli_physical_drive_uuid}{'diagnostics'}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_hpacucli_variable_name      => $scan_hpacucli_variable_name, 
				old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, 
				old_scan_hpacucli_variable_uuid  => $old_scan_hpacucli_variable_uuid, 
			}});
			
			# If the old alarm state is already 'VANISHED', ignore it.
			next if $old_scan_hpacucli_variable_value eq "VANISHED";

			# Still here? Alert and UPDATE.
			### NOTE: For now, we're going to use warning level because cache_modules 
			###       should never vanish unless one failed. If that is the case, the 
			###       admin already knows, but this will let other notification targets
			###       know that the change has happened.
			my $variables = {
				serial_number => $scan_hpacucli_physical_drive_serial_number,
				name          => $scan_hpacucli_variable_name, 
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0068", variables => $variables});
			$anvil->Alert->register({
				clear_alert   => 0, 
				alert_level   => "warning", 
				message       => "scan_hpacucli_note_0068", 
				show_header   => 1, 
				variables     => $variables, 
				sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
				set_by        => $THIS_FILE,
			});
			
			my $query = "
UPDATE 
    scan_hpacucli_variables 
SET 
    scan_hpacucli_variable_value = 'VANISHED', 
    modified_date                = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_variable_uuid  = ".$anvil->Database->quote($old_scan_hpacucli_variable_uuid)."
;";
			# Now record the query in the array
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
		}
	}
	
	return(0);
}

# Look for added, changed or deleted controllers.
sub process_controllers
{
	my ($anvil) = @_;
	
	# Look for new, changed or deleted controllers.
	$anvil->data->{'scan-hpacucli'}{queries} = [];
	
	foreach my $scan_hpacucli_controller_serial_number (sort {$a cmp $b} keys %{$anvil->data->{controller}})
	{
		# Controller data;
		next if $scan_hpacucli_controller_serial_number eq "metadata";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_hpacucli_controller_serial_number                                           => $scan_hpacucli_controller_serial_number, 
			"scan-hpacucli::controllers::by_serial::$scan_hpacucli_controller_serial_number" => $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}, 
		}});
		
		# Have we seen this controller before?
		my $scan_hpacucli_controller_uuid = "";
		my $controller_is_new             = 0;
		if ($anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number})
		{
			# Yup!
			$scan_hpacucli_controller_uuid = $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_controller_uuid => $scan_hpacucli_controller_uuid }});
		}
		else
		{
			# No, this is a new controller. Create a new UUID for it.
			$scan_hpacucli_controller_uuid = $anvil->Get->uuid();
			$controller_is_new        = 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_hpacucli_controller_uuid => $scan_hpacucli_controller_uuid, 
				controller_is_new             => $controller_is_new, 
			}});
			
			# Add the keys for looking it up by UUID or serial number.
			$anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number} = $scan_hpacucli_controller_uuid;
			$anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid}            = $scan_hpacucli_controller_serial_number;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"scan-hpacucli::controllers::by_serial::$scan_hpacucli_controller_serial_number" => $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}, 
				"scan-hpacucli::controllers::by_uuid::$scan_hpacucli_controller_uuid"            => $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid}, 
			}});
		}
		
		# These are the values for the controller and cache tables. Anything else will go in the 
		# variables table which will be processed after the controller.
		# Controller
		my $new_scan_hpacucli_controller_model                  = "";
		my $new_scan_hpacucli_controller_status                 = "";
		my $new_scan_hpacucli_controller_last_diagnostics       = $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics} ? time : "";
		my $new_scan_hpacucli_controller_cache_present          = "unknown";
		my $new_scan_hpacucli_controller_drive_write_cache      = "";
		my $new_scan_hpacucli_controller_firmware_version       = "";
		my $new_scan_hpacucli_controller_unsafe_writeback_cache = "";
		
		# Cache
		my $new_scan_hpacucli_cache_module_size          = "";
		my $new_scan_hpacucli_cache_module_serial_number = "";
		my $new_scan_hpacucli_cache_module_status        = "";
		my $new_scan_hpacucli_cache_module_type          = "";
		
		foreach my $type ("detail", "temperature")
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }});
			foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}})
			{
				# Pick up the variables for the controller
				if (($type eq "detail") && ($variable eq "model_name"))
				{
					# Store and delete the value
					$new_scan_hpacucli_controller_model = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_model => $new_scan_hpacucli_controller_model }});
					next;
				}
				elsif (($type eq "detail") && ($variable eq "controller_status"))
				{
					# Store and delete the value
					$new_scan_hpacucli_controller_status = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
					$new_scan_hpacucli_controller_status = lc($new_scan_hpacucli_controller_status);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_status => $new_scan_hpacucli_controller_status }});
					next;
				}
				elsif (($type eq "detail") && ($variable eq "cache_board_present"))
				{
					# Store and delete the value
					$new_scan_hpacucli_controller_cache_present = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
					$new_scan_hpacucli_controller_cache_present = lc($new_scan_hpacucli_controller_cache_present);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_cache_present => $new_scan_hpacucli_controller_cache_present }});
					next;
				}
				elsif (($type eq "detail") && ($variable eq "drive_write_cache"))
				{
					# Store and delete the value
					$new_scan_hpacucli_controller_drive_write_cache = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
					$new_scan_hpacucli_controller_drive_write_cache = lc($new_scan_hpacucli_controller_drive_write_cache);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_drive_write_cache => $new_scan_hpacucli_controller_drive_write_cache }});
					next;
				}
				elsif (($type eq "detail") && ($variable eq "firmware_version"))
				{
					# Store and delete the value
					$new_scan_hpacucli_controller_firmware_version = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_firmware_version => $new_scan_hpacucli_controller_firmware_version }});
					next;
				}
				elsif (($type eq "detail") && ($variable eq "no_battery_write_cache"))
				{
					# Store and delete the value
					$new_scan_hpacucli_controller_unsafe_writeback_cache = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
					$new_scan_hpacucli_controller_unsafe_writeback_cache = lc($new_scan_hpacucli_controller_unsafe_writeback_cache);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_controller_unsafe_writeback_cache => $new_scan_hpacucli_controller_unsafe_writeback_cache }});
					next;
				}
				# Pick up the data for the cache.
				elsif (($type eq "detail") && ($variable eq "total_cache_size"))
				{
					# Store and delete the value
					$new_scan_hpacucli_cache_module_size = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_cache_module_size => $new_scan_hpacucli_cache_module_size }});
					next;
				}
				elsif (($type eq "detail") && ($variable eq "cache_serial_number"))
				{
					# Store and delete the value
					$new_scan_hpacucli_cache_module_serial_number = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_cache_module_serial_number => $new_scan_hpacucli_cache_module_serial_number }});
					next;
				}
				elsif (($type eq "detail") && ($variable eq "cache_status"))
				{
					# Store and delete the value
					$new_scan_hpacucli_cache_module_status = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
					$new_scan_hpacucli_cache_module_status = lc($new_scan_hpacucli_cache_module_status);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_cache_module_status => $new_scan_hpacucli_cache_module_status }});
					next;
				}
				elsif (($type eq "detail") && ($variable eq "cache_backup_power_source"))
				{
					# Store and delete the value
					$new_scan_hpacucli_cache_module_type = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
					$new_scan_hpacucli_cache_module_type = lc($new_scan_hpacucli_cache_module_type);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_scan_hpacucli_cache_module_type => $new_scan_hpacucli_cache_module_type }});
					next;
				}
				else
				{
					# Just for debug
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"controller::${scan_hpacucli_controller_serial_number}::data::${type}::${variable}" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}, 
					}});
				}
			}
		}
		
		# Pull out the rest of the variables now. If the controller is new, all variables will be 
		# INSERTed. If the controller exists, each variable will be examined and new ones will be
		# INSERTed, existing ones will be checked for changes and UPDATEd as needed. If the 
		# controller is NOT new, then variables from the old data will be deleted as we go and any
		# not found in the current data set will be left over. We'll use this to determine variables
		# that have vanished. They will not be deleted, but their value will be set to 'VANISHED'.
		if ($controller_is_new)
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_hpacucli_controller_serial_number              => $scan_hpacucli_controller_serial_number, 
				new_scan_hpacucli_controller_model                  => $new_scan_hpacucli_controller_model, 
				new_scan_hpacucli_controller_cache_present          => $new_scan_hpacucli_controller_cache_present, 
				new_scan_hpacucli_controller_drive_write_cache      => $new_scan_hpacucli_controller_drive_write_cache, 
				new_scan_hpacucli_controller_firmware_version       => $new_scan_hpacucli_controller_firmware_version, 
				new_scan_hpacucli_controller_unsafe_writeback_cache => $new_scan_hpacucli_controller_unsafe_writeback_cache, 
			}});
			
			# Send an alert telling the user that we've found a new controller.
			my $variables = {
				model                  => $new_scan_hpacucli_controller_model,
				serial_number          => $scan_hpacucli_controller_serial_number,
				status                 => $new_scan_hpacucli_controller_status,
				drive_write_cache      => $new_scan_hpacucli_controller_drive_write_cache, 
				firmware_version       => $new_scan_hpacucli_controller_firmware_version, 
				unsafe_writeback_cache => $new_scan_hpacucli_controller_unsafe_writeback_cache, 
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0001", variables => $variables});
			$anvil->Alert->register({
				clear_alert   => 0, 
				alert_level   => "notice", 
				message       => "scan_hpacucli_note_0001", 
				variables     => $variables, 
				show_header   => 1, 
				sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
				set_by        => $THIS_FILE,
			});
			
			# INSERT
			my $query = "
INSERT INTO 
    scan_hpacucli_controllers
(
    scan_hpacucli_controller_uuid, 
    scan_hpacucli_controller_host_uuid, 
    scan_hpacucli_controller_serial_number, 
    scan_hpacucli_controller_model, 
    scan_hpacucli_controller_status,
    scan_hpacucli_controller_last_diagnostics, 
    scan_hpacucli_controller_cache_present,
    scan_hpacucli_controller_drive_write_cache,
    scan_hpacucli_controller_firmware_version,
    scan_hpacucli_controller_unsafe_writeback_cache,
    modified_date 
) VALUES (
    ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    ".$anvil->Database->quote($scan_hpacucli_controller_serial_number).", 
    ".$anvil->Database->quote($new_scan_hpacucli_controller_model).", 
    ".$anvil->Database->quote($new_scan_hpacucli_controller_status).", 
    ".$anvil->Database->quote($new_scan_hpacucli_controller_last_diagnostics).", 
    ".$anvil->Database->quote($new_scan_hpacucli_controller_cache_present).", 
    ".$anvil->Database->quote($new_scan_hpacucli_controller_drive_write_cache).", 
    ".$anvil->Database->quote($new_scan_hpacucli_controller_firmware_version).", 
    ".$anvil->Database->quote($new_scan_hpacucli_controller_unsafe_writeback_cache).", 
    ".$anvil->Database->quote($anvil->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-hpacucli'}{queries}}, $query;
		}
		else
		{
			### NOTE: The serial number and model should never change (a changed SN/controller 
			###       should be picked up as a new controller), but we check/update just to be 
			###       safe.
			# Controller already exists, check for changes.
			my $old_scan_hpacucli_controller_serial_number          = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_serial_number};
			my $old_scan_hpacucli_controller_model                  = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_model};
			my $old_scan_hpacucli_controller_status                 = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_status};
			my $old_scan_hpacucli_controller_last_diagnostics       = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_last_diagnostics};
			my $old_scan_hpacucli_controller_cache_present          = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_cache_present};
			my $old_scan_hpacucli_controller_drive_write_cache      = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_drive_write_cache};
			my $old_scan_hpacucli_controller_firmware_version       = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_firmware_version};
			my $old_scan_hpacucli_controller_unsafe_writeback_cache = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_unsafe_writeback_cache};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_hpacucli_controller_serial_number              => $scan_hpacucli_controller_serial_number, 
				old_scan_hpacucli_controller_serial_number          => $old_scan_hpacucli_controller_serial_number, 
				old_scan_hpacucli_controller_model                  => $old_scan_hpacucli_controller_model, 
				old_scan_hpacucli_controller_status                 => $old_scan_hpacucli_controller_status, 
				old_scan_hpacucli_controller_last_diagnostics       => $old_scan_hpacucli_controller_last_diagnostics, 
				old_scan_hpacucli_controller_cache_present          => $old_scan_hpacucli_controller_cache_present, 
				old_scan_hpacucli_controller_drive_write_cache      => $old_scan_hpacucli_controller_drive_write_cache, 
				old_scan_hpacucli_controller_firmware_version       => $old_scan_hpacucli_controller_firmware_version, 
				old_scan_hpacucli_controller_unsafe_writeback_cache => $old_scan_hpacucli_controller_unsafe_writeback_cache, 
			}});
			
			# Delete this from the old cache.
			delete $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid};
			
			# NOTE: We don't check if the last diagnostics changed because it will change every 
			#       10 minutes or so.
			if (($scan_hpacucli_controller_serial_number              ne $old_scan_hpacucli_controller_serial_number)     or 
			    ($new_scan_hpacucli_controller_model                  ne $old_scan_hpacucli_controller_model)             or 
			    ($new_scan_hpacucli_controller_status                 ne $old_scan_hpacucli_controller_status)            or 
			    ($new_scan_hpacucli_controller_cache_present          ne $old_scan_hpacucli_controller_cache_present)     or 
			    ($new_scan_hpacucli_controller_drive_write_cache      ne $old_scan_hpacucli_controller_drive_write_cache) or 
			    ($new_scan_hpacucli_controller_firmware_version       ne $old_scan_hpacucli_controller_firmware_version)  or 
			    ($new_scan_hpacucli_controller_unsafe_writeback_cache ne $old_scan_hpacucli_controller_unsafe_writeback_cache))
			{
				# Send a warning level alert because the most likely change is 'status'. If, 
				# however, the status is now 'ok', then we'll clear the alert.
				my $cleared     = 0;
				my $message_key = "scan_hpacucli_warning_0002";
				if ($new_scan_hpacucli_controller_status ne $old_scan_hpacucli_controller_status)
				{
					if (($new_scan_hpacucli_controller_status ne $old_scan_hpacucli_controller_status) && ($old_scan_hpacucli_controller_status eq "VANISHED"))
					{
						# Controller has returned.
						$message_key = "scan_hpacucli_warning_0003";
					}
					if (($new_scan_hpacucli_controller_status ne $old_scan_hpacucli_controller_status) && ($new_scan_hpacucli_controller_status =~ /ok/i))
					{
						# Clear the alert, the controller is OK again.
						$cleared = 1;
					}
				}
				
				my $variables = {
					new_serial_number          => $scan_hpacucli_controller_serial_number,
					old_serial_number          => $old_scan_hpacucli_controller_serial_number,
					new_model_name             => $new_scan_hpacucli_controller_model,
					old_model_name             => $old_scan_hpacucli_controller_model,
					new_status                 => $new_scan_hpacucli_controller_status,
					old_status                 => $old_scan_hpacucli_controller_status,
					new_cache_present          => $new_scan_hpacucli_controller_cache_present,
					old_cache_present          => $old_scan_hpacucli_controller_cache_present,
					new_drive_write_cache      => $new_scan_hpacucli_controller_drive_write_cache,
					old_drive_write_cache      => $old_scan_hpacucli_controller_drive_write_cache,
					new_firmware_version       => $new_scan_hpacucli_controller_firmware_version,
					old_firmware_version       => $old_scan_hpacucli_controller_firmware_version,
					new_unsafe_writeback_cache => $new_scan_hpacucli_controller_unsafe_writeback_cache,
					old_unsafe_writeback_cache => $old_scan_hpacucli_controller_unsafe_writeback_cache,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					clear_alert   => $cleared, 
					alert_level   => "warning", 
					message       => $message_key, 
					variables     => $variables, 
					show_header   => 1, 
					sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
					set_by        => $THIS_FILE,
				});
				
				my $query = "
UPDATE 
    scan_hpacucli_controllers
SET 
    scan_hpacucli_controller_host_uuid              = ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    scan_hpacucli_controller_serial_number          = ".$anvil->Database->quote($scan_hpacucli_controller_serial_number).", 
    scan_hpacucli_controller_model                  = ".$anvil->Database->quote($new_scan_hpacucli_controller_model).", 
    scan_hpacucli_controller_status                 = ".$anvil->Database->quote($new_scan_hpacucli_controller_status).", 
    scan_hpacucli_controller_cache_present          = ".$anvil->Database->quote($new_scan_hpacucli_controller_cache_present).", 
    scan_hpacucli_controller_drive_write_cache      = ".$anvil->Database->quote($new_scan_hpacucli_controller_drive_write_cache).", 
    scan_hpacucli_controller_firmware_version       = ".$anvil->Database->quote($new_scan_hpacucli_controller_firmware_version).", 
    scan_hpacucli_controller_unsafe_writeback_cache = ".$anvil->Database->quote($new_scan_hpacucli_controller_unsafe_writeback_cache).", 
    modified_date                                   = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_controller_uuid                   = ".$anvil->Database->quote($scan_hpacucli_controller_uuid)." 
;";
				
				# Now record the query in the array
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
			}
		}
		
		# Now, if we had a cache module on this controller, see if we knew about it already.
		my $scan_hpacucli_cache_module_uuid = "";
		my $cache_is_new               = 0;
		if ($new_scan_hpacucli_cache_module_serial_number)
		{
			if ($anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$new_scan_hpacucli_cache_module_serial_number})
			{
				# Yup!
				$scan_hpacucli_cache_module_uuid = $anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$new_scan_hpacucli_cache_module_serial_number};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_cache_module_uuid => $scan_hpacucli_cache_module_uuid }});
			}
			else
			{
				# No, this is a new cache module. Create a new UUID for it.
				$scan_hpacucli_cache_module_uuid = $anvil->Get->uuid();
				$cache_is_new               = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_hpacucli_cache_module_uuid => $scan_hpacucli_cache_module_uuid, 
					cache_is_new               => $cache_is_new, 
				}});
				
				# Add the keys for looking it up by UUID or serial number.
				$anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$new_scan_hpacucli_cache_module_serial_number} = $scan_hpacucli_cache_module_uuid;
				$anvil->data->{'scan-hpacucli'}{cache_modules}{by_uuid}{$scan_hpacucli_cache_module_uuid}                = $new_scan_hpacucli_cache_module_serial_number;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"scan-hpacucli::cache_modules::by_serial::$new_scan_hpacucli_cache_module_serial_number" => $anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$new_scan_hpacucli_cache_module_serial_number}, 
					"scan-hpacucli::cache_modules::by_uuid::$scan_hpacucli_cache_module_uuid"                => $anvil->data->{'scan-hpacucli'}{cache_modules}{by_uuid}{$scan_hpacucli_cache_module_uuid}, 
				}});
			}
			
			if ($cache_is_new)
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					scan_hpacucli_cache_module_uuid              => $scan_hpacucli_cache_module_uuid, 
					new_scan_hpacucli_cache_module_size          => $new_scan_hpacucli_cache_module_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_cache_module_size}).")", 
					new_scan_hpacucli_cache_module_serial_number => $new_scan_hpacucli_cache_module_serial_number, 
					new_scan_hpacucli_cache_module_status        => $new_scan_hpacucli_cache_module_status, 
					new_scan_hpacucli_cache_module_type          => $new_scan_hpacucli_cache_module_type, 
				}});
				
				# Send an alert telling the user that we've found a new controller.
				my $variables = {
					serial_number => $new_scan_hpacucli_cache_module_serial_number,
					cache_size    => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_cache_module_size}),
					status        => $new_scan_hpacucli_cache_module_status,
					type          => $new_scan_hpacucli_cache_module_type,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0002", variables => $variables});
				$anvil->Alert->register({
					clear_alert   => 0, 
					alert_level   => "notice", 
					message       => "scan_hpacucli_note_0002", 
					variables     => $variables, 
					show_header   => 1, 
					sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
					set_by        => $THIS_FILE,
				});
				### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'.
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_note_0003"});
				$anvil->Alert->register({
					clear_alert   => 0, 
					alert_level   => "notice", 
					message       => "scan_hpacucli_note_0003", 
					variables     => {}, 
					show_header   => 1, 
					sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
					set_by        => $THIS_FILE,
				});
				
				# INSERT
				my $query = "
INSERT INTO 
    scan_hpacucli_cache_modules 
(
    scan_hpacucli_cache_module_uuid, 
    scan_hpacucli_cache_module_host_uuid, 
    scan_hpacucli_cache_module_controller_uuid, 
    scan_hpacucli_cache_module_serial_number, 
    scan_hpacucli_cache_module_status, 
    scan_hpacucli_cache_module_type, 
    scan_hpacucli_cache_module_size, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($scan_hpacucli_cache_module_uuid).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", 
    ".$anvil->Database->quote($new_scan_hpacucli_cache_module_serial_number).", 
    ".$anvil->Database->quote($new_scan_hpacucli_cache_module_status).", 
    ".$anvil->Database->quote($new_scan_hpacucli_cache_module_type).", 
    ".$anvil->Database->quote($new_scan_hpacucli_cache_module_size).", 
    ".$anvil->Database->quote($anvil->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-hpacucli'}{queries}}, $query;
			}
			else
			{
				# Exists already, look for changes. The serial number should never change, 
				# buuuut...
				my $old_scan_hpacucli_cache_module_controller_uuid = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_controller_uuid};
				my $old_scan_hpacucli_cache_module_serial_number   = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_serial_number};
				my $old_scan_hpacucli_cache_module_status          = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_status};
				my $old_scan_hpacucli_cache_module_type            = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_type};
				my $old_scan_hpacucli_cache_module_size            = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_size};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					old_scan_hpacucli_cache_module_controller_uuid => $old_scan_hpacucli_cache_module_controller_uuid, 
					old_scan_hpacucli_cache_module_serial_number   => $old_scan_hpacucli_cache_module_serial_number, 
					old_scan_hpacucli_cache_module_status          => $old_scan_hpacucli_cache_module_status, 
					old_scan_hpacucli_cache_module_type            => $old_scan_hpacucli_cache_module_type, 
					old_scan_hpacucli_cache_module_size            => $old_scan_hpacucli_cache_module_size, 
				}});
				
				# Delete this so we know we saw it.
				delete $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid};
				
				if (($scan_hpacucli_controller_uuid                ne $old_scan_hpacucli_cache_module_controller_uuid) or 
				    ($new_scan_hpacucli_cache_module_serial_number ne $old_scan_hpacucli_cache_module_serial_number)   or 
				    ($new_scan_hpacucli_cache_module_status        ne $old_scan_hpacucli_cache_module_status)          or 
				    ($new_scan_hpacucli_cache_module_type          ne $old_scan_hpacucli_cache_module_type)            or 
				    ($new_scan_hpacucli_cache_module_size          ne $old_scan_hpacucli_cache_module_size))
				{
					# Something has changed, but what? Any change is likely bad, so we 
					# default to 'warning'.
					my $cleared     = 0;
					my $message_key = "scan_hpacucli_warning_0004";
					
					# Did the status return to 'ok'?
					if (($old_scan_hpacucli_cache_module_status ne $new_scan_hpacucli_cache_module_status) && ($old_scan_hpacucli_cache_module_status eq "VANISHED"))
					{
						# The cache module is back
						$message_key = "scan_hpacucli_warning_0005";
					}
					elsif (($old_scan_hpacucli_cache_module_status ne $new_scan_hpacucli_cache_module_status) && ($new_scan_hpacucli_cache_module_status eq "ok"))
					{
						# The status is good now, clear the alert
						$cleared = 1;
					}
					
					# Convert the old controller UUID to a serial number.
					my $query = "SELECT scan_hpacucli_controller_serial_number FROM scan_hpacucli_controllers WHERE scan_hpacucli_controller_uuid = ".$anvil->Database->quote($old_scan_hpacucli_cache_module_controller_uuid).";";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
					
					my $old_scan_hpacucli_controller_serial_number = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
					   $old_scan_hpacucli_controller_serial_number = "--" if not defined $old_scan_hpacucli_controller_serial_number;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number }});
					
					# Send the alert
					my $variables = {
						old_serial_number            => $old_scan_hpacucli_cache_module_serial_number,
						new_serial_number            => $new_scan_hpacucli_cache_module_serial_number,
						old_scan_hpacucli_controller_serial_number => $old_scan_hpacucli_controller_serial_number,
						new_controller_serial_number => $scan_hpacucli_controller_serial_number,
						old_status                   => $old_scan_hpacucli_cache_module_status,
						new_status                   => $old_scan_hpacucli_cache_module_status,
						old_type                     => $new_scan_hpacucli_cache_module_type,
						new_type                     => $old_scan_hpacucli_cache_module_type,
						say_old_size                 => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_hpacucli_cache_module_size}),
						say_new_size                 => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_hpacucli_cache_module_size}),
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0002", variables => $variables});
					$anvil->Alert->register({
						clear_alert   => $cleared, 
						alert_level   => "warning", 
						message       => $message_key, 
						variables     => $variables, 
						show_header   => 1, 
						sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
						set_by        => $THIS_FILE,
					});
					
					### NOTE: The rest of the alerts will be in the format '- Variable: [$value]'.
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0003"});
					$anvil->Alert->register({
						clear_alert   => 0, 
						alert_level   => "warning", 
						message       => "scan_hpacucli_note_0003", 
						variables     => $variables, 
						show_header   => 1, 
						sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
						set_by        => $THIS_FILE,
					});
					
					# Update the database.
					$query = "
UPDATE 
    scan_hpacucli_cache_modules 
SET 
    scan_hpacucli_cache_module_host_uuid       = ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    scan_hpacucli_cache_module_controller_uuid = ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", 
    scan_hpacucli_cache_module_serial_number   = ".$anvil->Database->quote($new_scan_hpacucli_cache_module_serial_number).", 
    scan_hpacucli_cache_module_status          = ".$anvil->Database->quote($new_scan_hpacucli_cache_module_status).", 
    scan_hpacucli_cache_module_type            = ".$anvil->Database->quote($new_scan_hpacucli_cache_module_type).", 
    scan_hpacucli_cache_module_size            = ".$anvil->Database->quote($new_scan_hpacucli_cache_module_size).", 
    modified_date                              = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_cache_module_uuid            = ".$anvil->Database->quote($scan_hpacucli_cache_module_uuid)." 
;";
					
					# Now record the query in the array
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
					push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
				}
			}
		}
		
		# We do this after the cache so that the alerts make since when a new controller is found.
		foreach my $type ("detail", "temperature")
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }});
			foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}})
			{
				my $new_scan_hpacucli_variable_value = delete $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable};
				my $temperature                      = $type eq "temperature" ? "TRUE" : "FALSE";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					variable                         => $variable, 
					new_scan_hpacucli_variable_value => $new_scan_hpacucli_variable_value, 
					temperature                      => $temperature, 
				}});
				
				# Now, if the variable doesn't exist, INSERT it. If it does exist, see if it
				# changed and UPDATE it if so.
				if (exists $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$variable})
				{
					# Look for changes
					my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$variable}{scan_hpacucli_variable_value};
					my $variable_uuid                    = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$variable}{scan_hpacucli_variable_uuid};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						new_scan_hpacucli_variable_value => $new_scan_hpacucli_variable_value, 
						old_scan_hpacucli_variable_value => $old_scan_hpacucli_variable_value, 
						variable_uuid                    => $variable_uuid, 
					}});
				
					# Delete it so that we know it has been processed.
					delete $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$variable};
					
					# Set defaults
					my $high_critical       = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{high_critical};
					my $high_warning        = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{high_warning};
					my $low_warning         = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{low_warning};
					my $low_critical        = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{low_critical};
					my $jump                = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{jump};
					my $buffer              = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{buffer};
					my $clear_high_critical = $high_critical - $buffer;
					my $clear_high_warning  = $high_warning - $buffer;
					my $clear_low_critical  = $low_critical - $buffer;
					my $clear_low_warning   = $low_warning - $buffer;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						high_critical       => $high_critical, 
						high_warning        => $high_warning, 
						low_warning         => $low_warning, 
						low_critical        => $low_critical, 
						jump                => $jump, 
						buffer              => $buffer, 
						clear_high_critical => $clear_high_critical, 
						clear_high_warning  => $clear_high_warning, 
						clear_low_critical  => $clear_low_critical, 
						clear_low_warning   => $clear_low_warning, 
					}});
					
					# Fine-tune the alert thresholds
					if ($clear_high_critical < $high_warning)
					{
						$clear_high_critical = $high_warning + 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }});
					}
					if ($clear_low_critical > $low_warning)
					{
						$clear_low_critical = $low_warning - 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }});
					}
					
					# Does this variable have defined limits?
					if (exists $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_critical})
					{
						$high_critical       = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_critical};
						$high_warning        = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_warning};
						$low_warning         = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{low_warning};
						$low_critical        = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{low_critical};
						$jump                = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{jump};
						$buffer              = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{buffer};
						$clear_high_critical = $high_critical - $buffer;
						$clear_high_warning  = $high_warning - $buffer;
						$clear_low_critical  = $low_critical - $buffer;
						$clear_low_warning   = $low_warning - $buffer;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							high_critical       => $high_critical, 
							high_warning        => $high_warning, 
							low_warning         => $low_warning, 
							low_critical        => $low_critical, 
							jump                => $jump, 
							buffer              => $buffer, 
							clear_high_critical => $clear_high_critical, 
							clear_high_warning  => $clear_high_warning, 
							clear_low_critical  => $clear_low_critical, 
							clear_low_warning   => $clear_low_warning, 
						}});
						
						# Fine-tune the alert thresholds
						if ($clear_high_critical < $high_warning)
						{
							$clear_high_critical = $high_warning + 1;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }});
						}
						if ($clear_low_critical > $low_warning)
						{
							$clear_low_critical = $low_warning - 1;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }});
						}
					}
					
					# If it's a temperature, we need to analyze it and store it, 
					# regardless of if it changed this pass.
					my $cleared           = 0;
					my $temperature_state = "ok";
					my $temperature_is    = "nominal";
					my $message_key       = "scan_hpacucli_note_0009";
					my $alert_level       = "notice";
					my $delta             = 0;
					if ($type eq "temperature")
					{
						# Change the log level to info as temperatures change often.
						$alert_level = "info";
						
						# Now see if the temperature has crossed into a 
						# warning or critical state.
						if ($new_scan_hpacucli_variable_value > $high_critical)
						{
							# Crossed the high critical threshold.
							my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
							if ($changed)
							{
								$alert_level = "critical";
								$message_key = "scan_hpacucli_note_0005";
							}
							$temperature_state = "critical";
							$temperature_is    = "high";
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								temperature_state => $temperature_state, 
								temperature_is    => $temperature_is, 
							}});
						}
						elsif ($new_scan_hpacucli_variable_value > $high_warning)
						{
							# Crossed the high warning threshold.
							my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
							if ($changed)
							{
								$alert_level = "warning";
								$message_key = "scan_hpacucli_note_0006";
							}
							$temperature_state = "warning";
							$temperature_is    = "high";
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								temperature_state => $temperature_state, 
								temperature_is    => $temperature_is, 
							}});
						}
						elsif ($new_scan_hpacucli_variable_value < $low_critical)
						{
							# Dropped below the low critical threshold.
							my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
							if ($changed)
							{
								$alert_level = "critical";
								$message_key = "scan_hpacucli_note_0007";
							}
							$temperature_state = "critical";
							$temperature_is    = "low";
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								temperature_state => $temperature_state, 
								temperature_is    => $temperature_is, 
							}});
						}
						elsif ($new_scan_hpacucli_variable_value < $low_warning)
						{
							# Crossed the low warning threshold.
							my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
							if ($changed)
							{
								$alert_level = "warning";
								$message_key = "scan_hpacucli_note_0008";
							}
							$temperature_state = "warning";
							$temperature_is    = "low";
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								temperature_state => $temperature_state, 
								temperature_is    => $temperature_is, 
							}});
						}
						else
						{
							# Did it change enough to trigger a jump 
							# alert?
							if ($new_scan_hpacucli_variable_value > $old_scan_hpacucli_variable_value)
							{
								# Jumped
								$delta = $new_scan_hpacucli_variable_value - $old_scan_hpacucli_variable_value;
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { delta => $delta }});
								if ($delta >= $jump)
								{
									# Big jump.
									$alert_level = "warning";
									$message_key = "scan_hpacucli_note_0015";
									$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
										alert_level => $alert_level, 
										message_key => $message_key, 
									}});
								}
							}
							else
							{
								# Dropped
								$delta = $old_scan_hpacucli_variable_value - $new_scan_hpacucli_variable_value;
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { delta => $delta }});
								if ($delta >= $jump)
								{
									# Big drop.
									$alert_level = "warning";
									$message_key = "scan_hpacucli_note_0016";
									$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
										alert_level => $alert_level, 
										message_key => $message_key, 
									}});
								}
							}
						}
						
						# Record this for later processing into the 'temperature' 
						# table.
						my $sensor_host_key = "controller:$scan_hpacucli_controller_serial_number";
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_host_key => $sensor_host_key }});
						
						$anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_value_c} = $new_scan_hpacucli_variable_value;
						$anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_state}   = $temperature_state;
						$anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_is}      = $temperature_is;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							"new::temperature::${variable}::${sensor_host_key}::temperature_value_c" => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_value_c}, 
							"new::temperature::${variable}::${sensor_host_key}::temperature_state"   => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_state}, 
							"new::temperature::${variable}::${sensor_host_key}::temperature_is"      => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_is}, 
						}});
					}
					
					# Did the variable change?
					if ($new_scan_hpacucli_variable_value ne $old_scan_hpacucli_variable_value)
					{
						# How has it changed?
						if ($old_scan_hpacucli_variable_value eq "VANISHED")
						{
							$message_key = "scan_hpacucli_note_0010";
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message_key => $message_key }});
						}
						elsif ($type eq "temperature")
						{
							
							# Clear alerts, if needed. The order is important as 
							# clearing a warning will replace clearing a critical
							# when a sensor goes critical -> ok in one scan. Once
							# done, we'll check if we've crossed into a warning 
							# or critical state. If so, those will replace any
							# cleared messages.
							if ($new_scan_hpacucli_variable_value < $clear_high_critical)
							{
								my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE});
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
								if ($changed)
								{
									$cleared     = 1;
									$alert_level = "critical";
									$message_key = "scan_hpacucli_note_0011";
									$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
										cleared     => $cleared, 
										alert_level => $alert_level, 
										message_key => $message_key, 
									}});
								}
							}
							if ($new_scan_hpacucli_variable_value < $clear_high_warning)
							{
								my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE});
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
								if ($changed)
								{
									# The temperature is no longer 
									# warning, and it didn't just go 
									# critical
									$cleared     = 1;
									$alert_level = "warning";
									$message_key = "scan_hpacucli_note_0012";
									$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
										cleared     => $cleared, 
										alert_level => $alert_level, 
										message_key => $message_key, 
									}});
								}
							}
							if ($new_scan_hpacucli_variable_value > $clear_low_critical)
							{
								my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE});
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
								if ($changed)
								{
									$cleared     = 1;
									$alert_level = "critical";
									$message_key = "scan_hpacucli_note_0013";
									$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
										cleared     => $cleared, 
										alert_level => $alert_level, 
										message_key => $message_key, 
									}});
								}
							}
							if ($new_scan_hpacucli_variable_value > $clear_low_warning)
							{
								my $changed = $anvil->Alert->check_alert_sent({clear => 1, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE});
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
								if ($changed)
								{
									$cleared     = 1;
									$alert_level = "warning";
									$message_key = "scan_hpacucli_note_0014";
									$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
										cleared     => $cleared, 
										alert_level => $alert_level, 
										message_key => $message_key, 
									}});
								}
							}
						}
						
						# Send an alert telling the user that we've found a variable for this 
						# controller. Note that we add ' C' to the temperatures so that they get
						# translated to 'Â°F' if desired by the reader.
						my $variables = {
							sensor_name               => $variable,
							serial_number             => $scan_hpacucli_controller_serial_number,
							name                      => $variable,
							old_value                 => $type eq "temperature" ? $old_scan_hpacucli_variable_value." °C" : $old_scan_hpacucli_variable_value,
							new_value                 => $type eq "temperature" ? $new_scan_hpacucli_variable_value." °C" : $new_scan_hpacucli_variable_value,
							high_critical_temperature => $high_critical." °C", 
							high_warning_temperature  => $high_warning." °C", 
							low_critical_temperature  => $low_critical." °C", 
							low_warning_temperature   => $low_warning." °C", 
							delta                     => $delta,
						};
						my $log_level = (($alert_level eq "warning") or ($alert_level eq "critical")) ? 1 : 2;
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
						$anvil->Alert->register({
							clear_alert   => $cleared, 
							alert_level   => $alert_level, 
							message       => $message_key, 
							variables     => $variables, 
							show_header   => 1, 
							sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
							set_by        => $THIS_FILE,
						});
						
						# UPDATE 
						my $query = "
UPDATE 
    scan_hpacucli_variables 
SET 
    scan_hpacucli_variable_value = ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", 
    modified_date                = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_variable_uuid  = ".$anvil->Database->quote($variable_uuid)."
;";
						# Now record the query in the array
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
						push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
					}
				}
				else
				{
					# New, record.
					my $message_key = "scan_hpacucli_note_0004";
					my $alert_level = "notice";
					
					# Set defaults
					my $high_critical       = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{high_critical};
					my $high_warning        = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{high_warning};
					my $low_warning         = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{low_warning};
					my $low_critical        = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{low_critical};
					my $jump                = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{jump};
					my $buffer              = $anvil->data->{'scan-hpacucli'}{thresholds}{'default'}{buffer};
					my $clear_high_critical = $high_critical - $buffer;
					my $clear_high_warning  = $high_warning - $buffer;
					my $clear_low_critical  = $low_critical - $buffer;
					my $clear_low_warning   = $low_warning - $buffer;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"high_critical"       => $high_critical, 
						"high_warning"        => $high_warning, 
						"low_warning"         => $low_warning, 
						"low_critical"        => $low_critical, 
						"jump"                => $jump, 
						"buffer"              => $buffer, 
						"clear_high_critical" => $clear_high_critical, 
						"clear_high_warning"  => $clear_high_warning, 
						"clear_low_critical"  => $clear_low_critical, 
						"clear_low_warning"   => $clear_low_warning, 
					}});
					
					# Fine-tune the alert thresholds
					if ($clear_high_critical < $high_warning)
					{
						$clear_high_critical = $high_warning + 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }});
					}
					if ($clear_low_critical > $low_warning)
					{
						$clear_low_critical = $low_warning - 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }});
					}
					
					if ($type eq "temperature")
					{
						# Does this variable have defined limits?
						if (exists $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_critical})
						{
							$high_critical       = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_critical};
							$high_warning        = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{high_warning};
							$low_warning         = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{low_warning};
							$low_critical        = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{low_critical};
							$jump                = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{jump};
							$buffer              = $anvil->data->{'scan-hpacucli'}{thresholds}{$variable}{buffer};
							$clear_high_critical = $high_critical - $buffer;
							$clear_high_warning  = $high_warning - $buffer;
							$clear_low_critical  = $low_critical - $buffer;
							$clear_low_warning   = $low_warning - $buffer;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								high_critical       => $high_critical, 
								high_warning        => $high_warning, 
								low_warning         => $low_warning, 
								low_critical        => $low_critical, 
								jump                => $jump, 
								buffer              => $buffer, 
								clear_high_critical => $clear_high_critical, 
								clear_high_warning  => $clear_high_warning, 
								clear_low_critical  => $clear_low_critical, 
								clear_low_warning   => $clear_low_warning, 
							}});
							
							# Fine-tune the alert thresholds
							if ($clear_high_critical < $high_warning)
							{
								$clear_high_critical = $high_warning + 1;
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_high_critical => $clear_high_critical }});
							}
							if ($clear_low_critical > $low_warning)
							{
								$clear_low_critical = $low_warning - 1;
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_low_critical => $clear_low_critical }});
							}
						}
						
						# This is a temperature, so see if the temperature outside of
						# the warning or critical thresholds. This is a new sensor, 
						# so nothing to compare against.
						my $temperature_state = "ok";
						my $temperature_is    = "nominal";
						if ($new_scan_hpacucli_variable_value > $high_critical)
						{
							# Crossed the high critical threshold. This should 
							# always be unset because it is a new variable, but 
							# check anyway.
							my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_critical", set_by => $THIS_FILE});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
							if ($changed)
							{
								$alert_level = "critical";
								$message_key = "scan_hpacucli_note_0005";
							}
							$temperature_state = "critical";
							$temperature_is    = "high";
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								temperature_state => $temperature_state, 
								temperature_is    => $temperature_is, 
							}});
						}
						elsif ($new_scan_hpacucli_variable_value > $high_warning)
						{
							# Crossed the high warning threshold. This should 
							# always be unset because it is a new variable, but 
							# check anyway.
							my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_high_warning", set_by => $THIS_FILE});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
							if ($changed)
							{
								$alert_level = "warning";
								$message_key = "scan_hpacucli_note_0006";
							}
							$temperature_state = "warning";
							$temperature_is    = "high";
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								temperature_state => $temperature_state, 
								temperature_is    => $temperature_is, 
							}});
						}
						elsif ($new_scan_hpacucli_variable_value < $low_critical)
						{
							# Dropped below the low critical threshold. This 
							# should always be unset because it is a new 
							# variable, but check anyway.
							my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_critical", set_by => $THIS_FILE});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
							if ($changed)
							{
								$alert_level = "critical";
								$message_key = "scan_hpacucli_note_0007";
							}
							$temperature_state = "critical";
							$temperature_is    = "low";
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								"temperature_state" => $temperature_state, 
								"temperature_is"    => $temperature_is, 
							}});
						}
						elsif ($new_scan_hpacucli_variable_value < $low_warning)
						{
							# Crossed the low warning threshold. This should 
							# always be unset because it is a new variable, but 
							# check anyway.
							my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_controller_serial_number.":".$variable."_low_warning", set_by => $THIS_FILE});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
							if ($changed)
							{
								$alert_level = "warning";
								$message_key = "scan_hpacucli_note_0008";
							}
							$temperature_state = "warning";
							$temperature_is    = "low";
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								temperature_state => $temperature_state, 
								temperature_is    => $temperature_is, 
							}});
						}
						
						# Record this for later processing into the 'temperature' 
						# table.
						my $sensor_host_key = "controller:".$scan_hpacucli_controller_serial_number;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sensor_host_key => $sensor_host_key }});
						
						$anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_value_c} = $new_scan_hpacucli_variable_value;
						$anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_state}   = $temperature_state;
						$anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_is}      = $temperature_is;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							"new::temperature::${variable}::${sensor_host_key}::temperature_value_c" => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_value_c}, 
							"new::temperature::${variable}::${sensor_host_key}::temperature_state"   => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_state}, 
							"new::temperature::${variable}::${sensor_host_key}::temperature_is"      => $anvil->data->{new}{temperature}{$variable}{$sensor_host_key}{temperature_is}, 
						}});
					}
					
					# Send an alert telling the user that we've found a variable for this 
					# controller. 
					my $variables = {
						sensor_name               => $variable,
						serial_number             => $scan_hpacucli_controller_serial_number,
						name                      => $variable,
						value                     => $type eq "temperature" ? $new_scan_hpacucli_variable_value." °C" : $new_scan_hpacucli_variable_value,
						high_critical_temperature => $high_critical." °C", 
						high_warning_temperature  => $high_warning." °C", 
						low_critical_temperature  => $low_critical." °C", 
						low_warning_temperature	  => $low_warning." °C", 
					};
					my $log_level = (($alert_level eq "warning") or ($alert_level eq "critical")) ? 1 : 2;
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $message_key, variables => $variables});
					$anvil->Alert->register({
						clear_alert   => 0, 
						alert_level   => $alert_level, 
						message       => $message_key, 
						variables     => $variables, 
						show_header   => 0,
						sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
						set_by        => $THIS_FILE,
					});
					
					# INSERT
					my $query = "
INSERT INTO 
    scan_hpacucli_variables
(
    scan_hpacucli_variable_uuid, 
    scan_hpacucli_variable_host_uuid, 
    scan_hpacucli_variable_source_table, 
    scan_hpacucli_variable_source_uuid, 
    scan_hpacucli_variable_is_temperature, 
    scan_hpacucli_variable_name, 
    scan_hpacucli_variable_value, 
    modified_date 
) VALUES (
    ".$anvil->Database->quote($anvil->Get->uuid()).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    'scan_hpacucli_controllers', 
    ".$anvil->Database->quote($scan_hpacucli_controller_uuid).", 
    ".$anvil->Database->quote($temperature).", 
    ".$anvil->Database->quote($variable).", 
    ".$anvil->Database->quote($new_scan_hpacucli_variable_value).", 
    ".$anvil->Database->quote($anvil->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-hpacucli'}{queries}}, $query;
				}
			}
		}
	}
	
	# Look for removed controllers
	foreach my $scan_hpacucli_controller_uuid (keys %{$anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}})
	{
		# Controller vanished!
		my $old_scan_hpacucli_controller_serial_number = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_serial_number};
		my $old_scan_hpacucli_controller_model         = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_model};
		my $old_scan_hpacucli_controller_status        = $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_status};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan_hpacucli_controller_uuid"              => $scan_hpacucli_controller_uuid, 
			"old_scan_hpacucli_controller_serial_number" => $old_scan_hpacucli_controller_serial_number, 
			"old_scan_hpacucli_controller_model"         => $old_scan_hpacucli_controller_model, 
			"old_scan_hpacucli_controller_status"        => $old_scan_hpacucli_controller_status, 
		}});
		
		# Delete it so that we know it has been processed.
		delete $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid};
		
		# If the old alarm state is already 'VANISHED', ignore it.
		next if $old_scan_hpacucli_controller_status eq "VANISHED";
		
		# Still here? Alert and UPDATE.
		### NOTE: For now, we're going to use warning level because controllers should never vanish
		###       unless one failed. If that is the case, the admin already knows, but this will let
		###       other notification targets know that the change has happened.
		my $variables = {
			model         => $old_scan_hpacucli_controller_model,
			serial_number => $old_scan_hpacucli_controller_serial_number,
		};
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0017", variables => $variables});
		$anvil->Alert->register({
			clear_alert   => 0, 
			alert_level   => "warning", 
			message       => "scan_hpacucli_note_0017", 
			variables     => $variables, 
			show_header   => 1,
			sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
			set_by        => $THIS_FILE,
		});
		
		my $query = "
UPDATE 
    scan_hpacucli_controllers 
SET 
    scan_hpacucli_controller_status = 'VANISHED', 
    modified_date                   = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_controller_uuid   = ".$anvil->Database->quote($scan_hpacucli_controller_uuid)." 
;";
		# Now record the query in the array
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
	}
	
	# Look for removed cache modules
	foreach my $scan_hpacucli_cache_module_uuid (keys %{$anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}})
	{
		# Controller vanished!
		my $old_scan_hpacucli_cache_module_serial_number = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_serial_number};
		my $old_scan_hpacucli_cache_module_status        = $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_status};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan_hpacucli_cache_module_uuid"              => $scan_hpacucli_cache_module_uuid, 
			"old_scan_hpacucli_cache_module_serial_number" => $old_scan_hpacucli_cache_module_serial_number, 
			"old_scan_hpacucli_cache_module_status"        => $old_scan_hpacucli_cache_module_status, 
		}});
		
		# Delete it so that we know it has been processed.
		delete $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid};
		
		# If the old alarm state is already 'VANISHED', ignore it.
		next if $old_scan_hpacucli_cache_module_status eq "VANISHED";
		
		# Still here? Alert and UPDATE.
		### NOTE: For now, we're going to use warning level because cache_modules should never vanish
		###       unless one failed. If that is the case, the admin already knows, but this will let
		###       other notification targets know that the change has happened.
		my $variables = {
			serial_number => $old_scan_hpacucli_cache_module_serial_number,
		};
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_note_0018", variables => $variables});
		$anvil->Alert->register({
			clear_alert   => 0, 
			alert_level   => "warning", 
			message       => "scan_hpacucli_note_0018", 
			variables     => $variables, 
			show_header   => 1,
			sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
			set_by        => $THIS_FILE,
		});
		
		my $query = "
UPDATE 
    scan_hpacucli_cache_modules 
SET 
    scan_hpacucli_cache_module_status = 'VANISHED', 
    modified_date                     = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_cache_module_uuid   = ".$anvil->Database->quote($scan_hpacucli_cache_module_uuid)." 
;";
		# Now record the query in the array
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
	}
	
	# Look for removed controller variables.
	foreach my $scan_hpacucli_controller_uuid (keys %{$anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}})
	{
		# Get the serial numbre for this contrller
		my $scan_hpacucli_controller_serial_number = $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan_hpacucli_controller_uuid"          => $scan_hpacucli_controller_uuid, 
			"scan_hpacucli_controller_serial_number" => $scan_hpacucli_controller_serial_number, 
		}});
		foreach my $type ("detail", "temperature")
		{
			foreach my $scan_hpacucli_variable_name (sort {$a cmp $b} keys %{$anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}})
			{
				my $old_scan_hpacucli_variable_value = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value};
				my $old_scan_hpacucli_variable_uuid  = $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{scan_hpacucli_controllers}{source_uuid}{$scan_hpacucli_controller_uuid}{$type}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"type"                        => $type, 
					"scan_hpacucli_variable_name"      => $scan_hpacucli_variable_name, 
					"old_scan_hpacucli_variable_value" => $old_scan_hpacucli_variable_value, 
					"old_scan_hpacucli_variable_uuid"  => $old_scan_hpacucli_variable_uuid, 
				}});
				
				# If the old alarm state is already 'VANISHED', ignore it.
				next if $old_scan_hpacucli_variable_value eq "VANISHED";
		
				# Still here? Alert and UPDATE.
				### NOTE: For now, we're going to use warning level because cache_modules 
				###       should never vanish unless one failed. If that is the case, the 
				###       admin already knows, but this will let other notification targets
				###       know that the change has happened.
				my $message_key = $type eq "temperature" ? "scan_hpacucli_note_0019" : "scan_hpacucli_note_0020";
				my $variables = {
					serial_number => $scan_hpacucli_controller_serial_number,
					name          => $scan_hpacucli_variable_name, 
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $message_key, variables => $variables});
				$anvil->Alert->register({
					clear_alert   => 0, 
					alert_level   => "warning", 
					message       => $message_key, 
					variables     => $variables, 
					show_header   => 1,
					sort_position => $anvil->data->{'scan-ipmitool'}{alert_sort}++, 
					set_by        => $THIS_FILE,
				});
				
				my $query = "
UPDATE 
    scan_hpacucli_variables 
SET 
    scan_hpacucli_variable_value = 'VANISHED', 
    modified_date                = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_hpacucli_variable_uuid  = ".$anvil->Database->quote($old_scan_hpacucli_variable_uuid)."
;";
				# Now record the query in the array
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				push @{$anvil->data->{'scan-hpacucli'}{queries}}, $query;
			}
		}
	}
	
	# Now commit the changes.
	$anvil->Database->write({query => $anvil->data->{'scan-hpacucli'}{queries}, source => $THIS_FILE, line => __LINE__});
	$anvil->data->{'scan-hpacucli'}{queries} = [];

	return(0);
}

# This reads in the last scan's data.
sub read_last_scan
{
	my ($anvil) = @_;
	
	# Read in the controller(s)
	my $query = "
SELECT 
    scan_hpacucli_controller_uuid, 
    scan_hpacucli_controller_serial_number, 
    scan_hpacucli_controller_model, 
    scan_hpacucli_controller_status, 
    scan_hpacucli_controller_last_diagnostics, 
    scan_hpacucli_controller_cache_present, 
    scan_hpacucli_controller_drive_write_cache, 
    scan_hpacucli_controller_firmware_version, 
    scan_hpacucli_controller_unsafe_writeback_cache 
FROM 
    scan_hpacucli_controllers 
WHERE 
    scan_hpacucli_controller_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	my $count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count, 
	}});
	foreach my $row (@{$results})
	{
		my $scan_hpacucli_controller_uuid          = $row->[0]; 
		my $scan_hpacucli_controller_serial_number = $row->[1]; 
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_hpacucli_controller_uuid          => $scan_hpacucli_controller_uuid, 
			scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number, 
		}});
		
		$anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_serial_number}          = $scan_hpacucli_controller_serial_number;
		$anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_model}                  = $row->[2];
		$anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_status}                 = $row->[3];
		$anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_last_diagnostics}       = $row->[4];
		$anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_cache_present}          = $row->[5];
		$anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_drive_write_cache}      = $row->[6];
		$anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_firmware_version}       = $row->[7];
		$anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_unsafe_writeback_cache} = $row->[8];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_serial_number"          => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_serial_number}, 
			"sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_model"                  => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_model}, 
			"sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_status"                 => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_status}, 
			"sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_last_diagnostics"       => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_last_diagnostics}, 
			"sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_cache_present"          => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_cache_present}, 
			"sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_drive_write_cache"      => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_drive_write_cache}, 
			"sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_firmware_version"       => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_firmware_version}, 
			"sql::scan_hpacucli_controllers::scan_hpacucli_controller_uuid::${scan_hpacucli_controller_uuid}::scan_hpacucli_controller_unsafe_writeback_cache" => $anvil->data->{sql}{scan_hpacucli_controllers}{scan_hpacucli_controller_uuid}{$scan_hpacucli_controller_uuid}{scan_hpacucli_controller_unsafe_writeback_cache}, 
		}});
		
		# Store the information about this controllers
		$anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number} = $scan_hpacucli_controller_uuid;
		$anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid}            = $scan_hpacucli_controller_serial_number;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan-hpacucli::controllers::by_serial::${scan_hpacucli_controller_serial_number}" => $anvil->data->{'scan-hpacucli'}{controllers}{by_serial}{$scan_hpacucli_controller_serial_number}, 
			"scan-hpacucli::controllers::by_uuid::${scan_hpacucli_controller_uuid}"            => $anvil->data->{'scan-hpacucli'}{controllers}{by_uuid}{$scan_hpacucli_controller_uuid}, 
		}});
	}
	undef $results;
	undef $count;
	
	# Now load the cache data
	$query = "
SELECT 
    scan_hpacucli_cache_module_uuid, 
    scan_hpacucli_cache_module_serial_number, 
    scan_hpacucli_cache_module_controller_uuid, 
    scan_hpacucli_cache_module_status, 
    scan_hpacucli_cache_module_type, 
    scan_hpacucli_cache_module_size 
FROM 
    scan_hpacucli_cache_modules
WHERE
    scan_hpacucli_cache_module_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count, 
	}});
	foreach my $row (@{$results})
	{
		my $scan_hpacucli_cache_module_uuid            = $row->[0]; 
		my $scan_hpacucli_cache_module_serial_number   = $row->[1];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_hpacucli_cache_module_uuid          => $scan_hpacucli_cache_module_uuid, 
			scan_hpacucli_cache_module_serial_number => $scan_hpacucli_cache_module_serial_number, 
		}});
	
		# Store the information about this cache_module
		$anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_controller_uuid} = $row->[2];
		$anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_serial_number}   = $scan_hpacucli_cache_module_serial_number;
		$anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_status}          = $row->[3];
		$anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_type}            = $row->[4];
		$anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_size}            = $row->[5];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_hpacucli_cache_modules::scan_hpacucli_cache_module_uuid::${scan_hpacucli_cache_module_uuid}::scan_hpacucli_cache_module_controller_uuid" => $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_controller_uuid}, 
			"sql::scan_hpacucli_cache_modules::scan_hpacucli_cache_module_uuid::${scan_hpacucli_cache_module_uuid}::scan_hpacucli_cache_module_serial_number"   => $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_serial_number}, 
			"sql::scan_hpacucli_cache_modules::scan_hpacucli_cache_module_uuid::${scan_hpacucli_cache_module_uuid}::scan_hpacucli_cache_module_status"          => $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_status}, 
			"sql::scan_hpacucli_cache_modules::scan_hpacucli_cache_module_uuid::${scan_hpacucli_cache_module_uuid}::scan_hpacucli_cache_module_type"            => $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_type}, 
			"sql::scan_hpacucli_cache_modules::scan_hpacucli_cache_module_uuid::${scan_hpacucli_cache_module_uuid}::scan_hpacucli_cache_module_size"            => $anvil->data->{sql}{scan_hpacucli_cache_modules}{scan_hpacucli_cache_module_uuid}{$scan_hpacucli_cache_module_uuid}{scan_hpacucli_cache_module_size}, 
		}});
		
		$anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$scan_hpacucli_cache_module_serial_number} = $scan_hpacucli_cache_module_uuid;
		$anvil->data->{'scan-hpacucli'}{cache_modules}{by_uuid}{$scan_hpacucli_cache_module_uuid}            = $scan_hpacucli_cache_module_serial_number;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan-hpacucli::cache_modules::by_serial::${scan_hpacucli_cache_module_serial_number}" => $anvil->data->{'scan-hpacucli'}{cache_modules}{by_serial}{$scan_hpacucli_cache_module_serial_number}, 
			"scan-hpacucli::cache_modules::by_uuid::${scan_hpacucli_cache_module_uuid}"            => $anvil->data->{'scan-hpacucli'}{cache_modules}{by_uuid}{$scan_hpacucli_cache_module_uuid}, 
		}});
	}
	undef $results;
	undef $count;
	
	# The array data...
	$query = "
SELECT 
    scan_hpacucli_array_uuid, 
    scan_hpacucli_array_name, 
    scan_hpacucli_array_controller_uuid, 
    scan_hpacucli_array_type, 
    scan_hpacucli_array_status, 
    scan_hpacucli_array_error_message 
FROM 
    scan_hpacucli_arrays
WHERE
    scan_hpacucli_array_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count, 
	}});
	foreach my $row (@{$results})
	{
		my $scan_hpacucli_array_uuid = $row->[0]; 
		my $scan_hpacucli_array_name = $row->[1]; 
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_hpacucli_array_uuid => $scan_hpacucli_array_uuid, 
			scan_hpacucli_array_name => $scan_hpacucli_array_name, 
		}});
		
		# Store the drive group data. (Drive groups have no SN)
		$anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_controller_uuid} = $row->[2];
		$anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_name}            = $scan_hpacucli_array_name;
		$anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_type}            = $row->[3];
		$anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_status}          = $row->[4];
		$anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_error_message}   = $row->[5];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_hpacucli_arrays::scan_hpacucli_array_uuid::${scan_hpacucli_array_uuid}::scan_hpacucli_array_controller_uuid" => $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_controller_uuid}, 
			"sql::scan_hpacucli_arrays::scan_hpacucli_array_uuid::${scan_hpacucli_array_uuid}::scan_hpacucli_array_name"            => $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_name}, 
			"sql::scan_hpacucli_arrays::scan_hpacucli_array_uuid::${scan_hpacucli_array_uuid}::scan_hpacucli_array_type"            => $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_type}, 
			"sql::scan_hpacucli_arrays::scan_hpacucli_array_uuid::${scan_hpacucli_array_uuid}::scan_hpacucli_array_status"          => $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_status}, 
			"sql::scan_hpacucli_arrays::scan_hpacucli_array_uuid::${scan_hpacucli_array_uuid}::scan_hpacucli_array_error_message"   => $anvil->data->{sql}{scan_hpacucli_arrays}{scan_hpacucli_array_uuid}{$scan_hpacucli_array_uuid}{scan_hpacucli_array_error_message}, 
		}});
		
		# Store the information about this virtual drive.
		$anvil->data->{'scan-hpacucli'}{virtual_drives}{by_name}{$scan_hpacucli_array_name} = $scan_hpacucli_array_uuid;
		$anvil->data->{'scan-hpacucli'}{virtual_drives}{by_uuid}{$scan_hpacucli_array_uuid} = $scan_hpacucli_array_name;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan-hpacucli::virtual_drives::by_name::${scan_hpacucli_array_name}" => $anvil->data->{'scan-hpacucli'}{virtual_drives}{by_name}{$scan_hpacucli_array_name}, 
			"scan-hpacucli::virtual_drives::by_uuid::${scan_hpacucli_array_uuid}" => $anvil->data->{'scan-hpacucli'}{virtual_drives}{by_uuid}{$scan_hpacucli_array_uuid}, 
		}});
	}
	undef $results;
	undef $count;
	
	# The drive group data...
	$query = "
SELECT 
    scan_hpacucli_logical_drive_uuid, 
    scan_hpacucli_logical_drive_name, 
    scan_hpacucli_logical_drive_array_uuid, 
    scan_hpacucli_logical_drive_caching, 
    scan_hpacucli_logical_drive_os_device_name, 
    scan_hpacucli_logical_drive_type, 
    scan_hpacucli_logical_drive_raid_level, 
    scan_hpacucli_logical_drive_size, 
    scan_hpacucli_logical_drive_strip_size, 
    scan_hpacucli_logical_drive_stripe_size, 
    scan_hpacucli_logical_drive_status 
FROM 
    scan_hpacucli_logical_drives 
WHERE
    scan_hpacucli_logical_drive_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count, 
	}});
	foreach my $row (@{$results})
	{
		my $scan_hpacucli_logical_drive_uuid           = $row->[0]; 
		my $scan_hpacucli_logical_drive_name           = $row->[1]; 
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_hpacucli_logical_drive_uuid => $scan_hpacucli_logical_drive_uuid, 
			scan_hpacucli_logical_drive_name => $scan_hpacucli_logical_drive_name, 
		}});
		
		# Store the logical drive data. (LDs have no SN)
		$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_name}           = $scan_hpacucli_logical_drive_name;
		$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_array_uuid}     = $row->[2];
		$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_caching}        = $row->[3];
		$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_os_device_name} = $row->[4];
		$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_type}           = $row->[5];
		$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_raid_level}     = $row->[6];
		$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_size}           = $row->[7];
		$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_strip_size}     = $row->[8];
		$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_stripe_size}    = $row->[9];
		$anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_status}         = $row->[10];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_array_uuid"     => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_array_uuid}, 
			"sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_name"           => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_name}, 
			"sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_caching"        => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_caching}, 
			"sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_os_device_name" => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_os_device_name}, 
			"sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_type"           => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_type}, 
			"sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_raid_level"     => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_raid_level}, 
			"sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_size"           => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_size}, 
			"sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_strip_size"     => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_strip_size}, 
			"sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_stripe_size"    => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_stripe_size}, 
			"sql::scan_hpacucli_logical_drives::scan_hpacucli_logical_drive_uuid::${scan_hpacucli_logical_drive_uuid}::scan_hpacucli_logical_drive_status"         => $anvil->data->{sql}{scan_hpacucli_logical_drives}{scan_hpacucli_logical_drive_uuid}{$scan_hpacucli_logical_drive_uuid}{scan_hpacucli_logical_drive_status}, 
		}});
		
		# Store the information about this virtual drive.
		$anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name} = $scan_hpacucli_logical_drive_uuid;
		$anvil->data->{'scan-hpacucli'}{logical_drives}{by_uuid}{$scan_hpacucli_logical_drive_uuid} = $scan_hpacucli_logical_drive_name;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan-hpacucli::logical_drives::by_name::${scan_hpacucli_logical_drive_name}" => $anvil->data->{'scan-hpacucli'}{logical_drives}{by_name}{$scan_hpacucli_logical_drive_name}, 
			"scan-hpacucli::logical_drives::by_uuid::${scan_hpacucli_logical_drive_uuid}" => $anvil->data->{'scan-hpacucli'}{logical_drives}{by_uuid}{$scan_hpacucli_logical_drive_uuid}, 
		}});
	}
	undef $results;
	undef $count;
	
	# And now, the physical drives.
	$query = "
SELECT 
    scan_hpacucli_physical_drive_uuid, 
    scan_hpacucli_physical_drive_serial_number,
    scan_hpacucli_physical_drive_logical_drive_uuid, 
    scan_hpacucli_physical_drive_model,
    scan_hpacucli_physical_drive_interface,
    scan_hpacucli_physical_drive_status,
    scan_hpacucli_physical_drive_size,
    scan_hpacucli_physical_drive_type,
    scan_hpacucli_physical_drive_rpm, 
    scan_hpacucli_physical_drive_temperature, 
    scan_hpacucli_physical_drive_last_failure_reason, 
    scan_hpacucli_physical_drive_port, 
    scan_hpacucli_physical_drive_box, 
    scan_hpacucli_physical_drive_bay 
FROM 
    scan_hpacucli_physical_drives
WHERE
    scan_hpacucli_physical_drive_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count, 
	}});
	foreach my $row (@{$results})
	{
		my $scan_hpacucli_physical_drive_uuid                = $row->[0]; 
		my $scan_hpacucli_physical_drive_serial_number       = $row->[1];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_hpacucli_physical_drive_uuid          => $scan_hpacucli_physical_drive_uuid, 
			scan_hpacucli_physical_drive_serial_number => $scan_hpacucli_physical_drive_serial_number, 
		}});
		
		# Store the information about this physical drive
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_logical_drive_uuid}  = $row->[2];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_serial_number}       = $scan_hpacucli_physical_drive_serial_number;
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_model}               = $row->[3];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_interface}           = $row->[4];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_status}              = $row->[5];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_size}                = $row->[6];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_type}                = $row->[7];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_rpm}                 = $row->[8];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_temperature}         = $row->[9];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_last_failure_reason} = $row->[10];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_port}                = $row->[11];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_box}                 = $row->[12];
		$anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_bay}                 = $row->[13];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_logical_drive_uuid"  => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_logical_drive_uuid}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_serial_number"       => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_serial_number}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_model"               => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_model}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_interface"           => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_interface}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_status"              => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_status}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_size"                => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_size}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_type"                => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_type}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_rpm"                 => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_rpm}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_temperature"         => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_temperature}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_last_failure_reason" => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_last_failure_reason}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_port"                => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_port}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_box"                 => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_box}, 
			"sql::scan_hpacucli_physical_drives::scan_hpacucli_physical_drive_uuid::${scan_hpacucli_physical_drive_uuid}::scan_hpacucli_physical_drive_bay"                 => $anvil->data->{sql}{scan_hpacucli_physical_drives}{scan_hpacucli_physical_drive_uuid}{$scan_hpacucli_physical_drive_uuid}{scan_hpacucli_physical_drive_bay}, 
		}});
		
		# Make it so that we can look up the serial number from the drive's UUID and vice versa
		$anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number} = $scan_hpacucli_physical_drive_uuid;
		$anvil->data->{'scan-hpacucli'}{physical_drives}{by_uuid}{$scan_hpacucli_physical_drive_uuid}            = $scan_hpacucli_physical_drive_serial_number;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan-hpacucli::physical_drives::by_serial::${scan_hpacucli_physical_drive_serial_number}" => $anvil->data->{'scan-hpacucli'}{physical_drives}{by_serial}{$scan_hpacucli_physical_drive_serial_number}, 
			"scan-hpacucli::physical_drives::by_uuid::${scan_hpacucli_physical_drive_uuid}"            => $anvil->data->{'scan-hpacucli'}{physical_drives}{by_uuid}{$scan_hpacucli_physical_drive_uuid}, 
		}});
	}
	undef $results;
	undef $count;
	
	# Lastly, the variables.
	$query = "
SELECT 
    scan_hpacucli_variable_uuid, 
    scan_hpacucli_variable_source_table, 
    scan_hpacucli_variable_source_uuid, 
    scan_hpacucli_variable_is_temperature, 
    scan_hpacucli_variable_name, 
    scan_hpacucli_variable_value 
FROM 
    scan_hpacucli_variables
WHERE
    scan_hpacucli_variable_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
	
	$results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
	$count   = @{$results};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		results => $results, 
		count   => $count, 
	}});
	foreach my $row (@{$results})
	{
		my $scan_hpacucli_variable_uuid            = $row->[0]; 
		my $scan_hpacucli_variable_source_table    = $row->[1]; 
		my $scan_hpacucli_variable_source_uuid     = $row->[2]; 
		my $scan_hpacucli_variable_is_temperature  = $row->[3]; 
		my $scan_hpacucli_variable_name            = $row->[4]; 
		my $scan_hpacucli_variable_value           = $row->[5]; 
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_hpacucli_variable_uuid           => $scan_hpacucli_variable_uuid, 
			scan_hpacucli_variable_source_table   => $scan_hpacucli_variable_source_table, 
			scan_hpacucli_variable_source_uuid    => $scan_hpacucli_variable_source_uuid, 
			scan_hpacucli_variable_is_temperature => $scan_hpacucli_variable_is_temperature, 
			scan_hpacucli_variable_name           => $scan_hpacucli_variable_name, 
			scan_hpacucli_variable_value          => $scan_hpacucli_variable_value, 
		}});
		
		# We store these differently for easier reference. Diagnostic data is stored in the special 
		# 'scan_hpacucli_physical_drive_diagnostics' source.
		my $type = "detail";
		if ($scan_hpacucli_variable_source_table eq "scan_hpacucli_physical_drive_diagnostics")
		{
			$type = "diagnostics";
		}
		if ($scan_hpacucli_variable_is_temperature eq "1")
		{
			$type = "temperature";
		}
		$anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{$scan_hpacucli_variable_source_table}{source_uuid}{$scan_hpacucli_variable_source_uuid}{$type}{$scan_hpacucli_variable_name} = {
			scan_hpacucli_variable_uuid           => $scan_hpacucli_variable_uuid, 
			scan_hpacucli_variable_is_temperature => $scan_hpacucli_variable_is_temperature, 
			scan_hpacucli_variable_value	      => $scan_hpacucli_variable_value, 
		};
		
		# Entries are so long that we log the one per variable.
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::${scan_hpacucli_variable_source_table}::source_uuid::${scan_hpacucli_variable_source_uuid}::${type}::${scan_hpacucli_variable_name}::scan_hpacucli_variable_uuid"           => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{$scan_hpacucli_variable_source_table}{source_uuid}{$scan_hpacucli_variable_source_uuid}{$type}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_uuid}, 
		}});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::${scan_hpacucli_variable_source_table}::source_uuid::${scan_hpacucli_variable_source_uuid}::${type}::${scan_hpacucli_variable_name}::scan_hpacucli_variable_is_temperature" => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{$scan_hpacucli_variable_source_table}{source_uuid}{$scan_hpacucli_variable_source_uuid}{$type}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_is_temperature}, 
		}});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_hpacucli_variables::scan_hpacucli_variable_uuid::source_table::${scan_hpacucli_variable_source_table}::source_uuid::${scan_hpacucli_variable_source_uuid}::${type}::${scan_hpacucli_variable_name}::scan_hpacucli_variable_value"          => $anvil->data->{sql}{scan_hpacucli_variables}{scan_hpacucli_variable_uuid}{source_table}{$scan_hpacucli_variable_source_table}{source_uuid}{$scan_hpacucli_variable_source_uuid}{$type}{$scan_hpacucli_variable_name}{scan_hpacucli_variable_value}, 
		}});
	}
	undef $results;
	undef $count;
	
	# Return the number 
	return(0);
}

# This looks for anything other than temperature sensors that will feed into the health of the node.
sub pre_process_health
{
	my ($anvil) = @_;

	# This is to collected data from every sweep.
	foreach my $scan_hpacucli_controller_serial_number (sort {$a cmp $b} keys %{$anvil->data->{controller}})
	{
		# We don't care about metadata
		next if $scan_hpacucli_controller_serial_number eq "metadata";
		
		# Controller data
		foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}})
		{
			if (($variable eq "battery_or_capacitor_status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{$variable}) ne "ok"))
			{
				# BBU/FBU problem, score of 2
				my $health_source_name                                               = "controller:".$scan_hpacucli_controller_serial_number.":data:".$variable;
				   $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 2;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
				}});
			}
			elsif (($variable eq "cache_status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{$variable}) ne "ok"))
			{
				# Cache isn't OK, score of 2
				my $health_source_name                                               = "controller:".$scan_hpacucli_controller_serial_number.":data:".$variable;
				   $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 2;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
				}});
			}
			elsif (($variable eq "controller_status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{$variable}) ne "ok"))
			{
				# The controller isn't OK, this is major, score of 10
				my $health_source_name                                               = "controller:".$scan_hpacucli_controller_serial_number.":data:".$variable;
				   $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 10;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
				}});
			}
		}
		
		# Array
		foreach my $scan_hpacucli_array_name (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}})
		{
			# Data
			foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}})
			{
				if (($variable eq "status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{$variable}) ne "ok"))
				{
					# Something is wrong with this array
					my $health_source_name                                               = "controller:".$scan_hpacucli_controller_serial_number.":array:".$scan_hpacucli_array_name.":".$variable;
					   $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 5;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
					}});
				}
			}
			
			# Logical Drive
			foreach my $logical_drive (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}})
			{
				# Data
				foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{data}{detail}})
				{
					if (($variable eq "caching") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{data}{detail}{$variable}) ne "enabled"))
					{
						# Not enabled is going to hurt performance.
						my $health_source_name                                               = "controller:".$scan_hpacucli_controller_serial_number.":array:".$scan_hpacucli_array_name.":logical_drive:".$logical_drive.":".$variable;
						   $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							"health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
						}});
					}
					elsif (($variable eq "status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{data}{detail}{$variable}) ne "ok"))
					{
						# If the status isn't OK, it's degraded (or rebuilding, but 
						# still degraded).
						my $health_source_name                                               = "controller:".$scan_hpacucli_controller_serial_number.":array:".$scan_hpacucli_array_name.":logical_drive:".$logical_drive.":".$variable;
						   $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 2;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							"health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
						}});
					}
				}
				
				# Physical Disks.
				foreach my $port (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}})
				{
					foreach my $box (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}})
					{
						foreach my $bay (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}})
						{
							my $scan_hpacucli_physical_drive_serial_number = $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{serial_number};
							# Data
							foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}})
							{
								next if $variable eq "serial_number";
								next if $variable eq "port";
								next if $variable eq "box";
								next if $variable eq "bay";
								
								if (($variable eq "status") && (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{$variable}) ne "ok"))
								{
									# The drive is failed or is rebuilding. This adds 2.
									my $health_source_name                                               = "controller:".$scan_hpacucli_controller_serial_number.":physical_drive:".$scan_hpacucli_physical_drive_serial_number.":data:".$variable;
									   $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = 2;
									$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
										"health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
									}});
								}
							}
							
							# If this was a diagnostics run, check for error 
							# counters
							if ($anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics})
							{
								# If the diagnostics don't exist for the 
								# drive and the drive is OK, it's likely a 
								# 3rd party drive. If the status is not OK, 
								# there may not be diagnostic data.
								if (exists $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_hard})
								{
									# We got the data
									foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}})
									{
										# Store this in the main hash.
										if ((($variable eq "hardware_errors")           or 
										     ($variable eq "predictive_failure_errors") or 
										     ($variable eq "read_errors_hard")          or 
										     ($variable eq "write_errors_hard"))        && 
										     ($anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{$variable} =~ /^\d+$/) && 
										     ($anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{$variable} > 0))
										{
											# How high is the error count?
											my $score = 1;
											if ($anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{$variable} > 10)
											{
												# Eek
												$score = 3;
											}
											elsif ($anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{$variable} > 5)
											{
												# Getting a little high
												$score = 2;
											}
											my $health_source_name                                               = "controller:".$scan_hpacucli_controller_serial_number.":physical_drive:".$scan_hpacucli_physical_drive_serial_number.":diagnostics:".$variable;
											   $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name} = $score;
											$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
												"health::new::controller:$health_source_name" => $anvil->data->{'scan-hpacucli'}{health}{new}{$health_source_name}, 
											}});
										}
										
										# Record the diagnostic data 
										# under the drive's hash.
										$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{'diagnostics'}{$variable} = $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{$variable};
									}
								}
								elsif (lc($anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{detail}{status}) eq "ok")
								{
									# No data for this drive. It might be
									# a 3rd party drive. We'll warn the 
									# user that we can't predict failure.
									my $changed = $anvil->Alert->check_alert_sent({clear => 0, record_locator => $scan_hpacucli_physical_drive_serial_number.":no_diagnostics", set_by => $THIS_FILE});
									$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changed => $changed }});
									if ($changed)
									{
										# Warn the user that we can't
										# predict this drive's death.
										my $variables = {
											serial_number => $scan_hpacucli_physical_drive_serial_number,
											port          => $port,
											box           => $box, 
											bay           => $bay,
										};
										$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_hpacucli_warning_0001", variables => $variables});
										$anvil->Alert->register({
											clear_alert   => 0, 
											alert_level   => "warning", 
											message       => "scan_hpacucli_warning_0001", 
											variables     => $variables, 
											show_header   => 1, 
											sort_position => $anvil->data->{'scan-hpacucli'}{alert_sort}++, 
											set_by        => $THIS_FILE,
										});
									}
								}
							}
						}
					}
				}
			}
		}
	}
	
	return(0);
}

# This gets the basic information about the controller.
sub get_controller_info
{
	my ($anvil, $controller) = @_;
	
	my $model_name                                 = "";
	my $scan_hpacucli_controller_serial_number     = "";
	my $cache_serial_number                        = "";
	my $scan_hpacucli_physical_drive_serial_number = "";
	my $scan_hpacucli_array_name                   = "";
	my $logical_drive                              = "";
	my $port                                       = "";
	my $box                                        = "";
	my $bay                                        = "";
	my $in_array                                   = 0;
	my $shell_call                                 = $anvil->data->{path}{exe}{hpacucli}." controller slot=".$controller." show config detail";
	my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
		output      => $output, 
		return_code => $return_code,
	}});
	foreach my $line (split/\n/, $output)
	{
		$line =  $anvil->Words->clean_spaces({string => $line});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
		
		if ((not $scan_hpacucli_controller_serial_number) && ($line =~ /^(.*?) in Slot $controller /))
		{
			$model_name = $1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { model_name => $model_name }});
		}

		if (($line =~ /^Serial Number: (.*?)$/) && (not $port) && (not $box) && (not $bay))
		{
			$scan_hpacucli_controller_serial_number = $1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number }});
			
			# Record the model number
			if ($model_name)
			{
				$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{model_name} = $model_name;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"controller::${scan_hpacucli_controller_serial_number}::data::detail::model_name" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{model_name}, 
				}});
			}
			
			# Make a reference between the slot and SN
			$anvil->data->{controller}{metadata}{sn_to_slot}{$scan_hpacucli_controller_serial_number} = $controller;
			$anvil->data->{controller}{metadata}{slot_to_sn}{$controller}                        = $scan_hpacucli_controller_serial_number;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"controller::metadata::sn_to_slot::${scan_hpacucli_controller_serial_number}" => $anvil->data->{controller}{metadata}{sn_to_slot}{$scan_hpacucli_controller_serial_number}, 
				"controller::metadata::slot_to_sn::${controller}"    => $anvil->data->{controller}{metadata}{slot_to_sn}{$controller}, 
			}});
			next;
		}
		next if not $scan_hpacucli_controller_serial_number;
		
		if ($line =~ /Cache Serial Number: (.*?)$/i)
		{
			$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{cache_serial_number} = $1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"controller::${scan_hpacucli_controller_serial_number}::data::detail::cache_serial_number" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{detail}{cache_serial_number}, 
			}});
			next;
		}
		
		if ($line =~ /Array: (.*?)$/i)
		{
			$scan_hpacucli_array_name = $1;
			$in_array            = 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_hpacucli_array_name => $scan_hpacucli_array_name, 
				in_array            => $in_array, 
			}});
			next;
		}
		
		if ($line =~ /Logical Drive: (.*?)$/i)
		{
			$logical_drive = $1;
			$in_array      = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				logical_drive => $logical_drive, 
				in_array      => $in_array, 
			}});
			next;
		}
		
		if ($line =~ /physicaldrive (.*?):(.*?):(.*)$/)
		{
			$port = $1;
			$box  = $2;
			$bay  = $3;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				port => $port, 
				box  => $box, 
				bay  => $bay, 
			}});
			next;
		}
		elsif (($port) && (($line eq "Drive Type: Data") or ($line =~ /^Mirror Group \d+:$/)))
		{
			$port = "";
			$box  = "";
			$bay  = "";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				port => $port, 
				box  => $box, 
				bay  => $bay, 
			}});
		}
		
		if (lc($line) eq "unassigned")
		{
			$scan_hpacucli_array_name = "ZZZZ";
			$logical_drive       = "9999";
			$port                = "";
			$box                 = "";
			$bay                 = "";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_hpacucli_array_name => $scan_hpacucli_array_name, 
				logical_drive       => $logical_drive, 
				port                => $port, 
				box                 => $box, 
				bay                 => $bay, 
			}});
			next;
		}
		
		# Lines I don't care about
		next if $line =~ /^Slot: $controller$/i;
		
		my $type = "detail";
		if ($line =~ /^(.*?): (.*)$/)
		{
			my $variable = $1;
			my $value    = $2;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				variable => $variable, 
				value    => $value, 
			}});
			
			# If the variable has units, pull them out.
			if ($variable =~ / \(C\)$/i)
			{
				$variable =~ s/ \(C\)$//i;
				$variable =  $anvil->Words->clean_spaces({string => $variable});
				$type     =  "temperature";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					variable => $variable, 
					value    => $value, 
					type     => $type, 
				}});
			}
			elsif ($variable =~ / \(F\)/i)
			{
				# Covert to Â°C
				$variable =~ s/ \(F\)$//i;
				$variable =  $anvil->Words->clean_spaces({string => $variable});
				$value    =  $anvil->Convert->fahrenheit_to_celsius({temperature => $value});
				$type     =  "temperature";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					variable => $variable, 
					value    => $value, 
					type     => $type, 
				}});
			}
			elsif (($value =~ /^\d+ \wB$/) or ($value =~ /^\d+\.\d+ \wB$/))
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					variable   => $variable, 
					">> value" => $value, 
				}});
				if (($variable eq "Total Cache Size")             or 
				    ($variable eq "Total Cache Memory Available") or 
				    ($variable eq "Strip Size")                   or 
				    ($variable eq "Size")                         or 
				    ($variable eq "Full Stripe Size"))
				{
					# HP reports in MB, etc, but means MiB.
					$value = $anvil->Convert->human_readable_to_bytes({size => $value, base2 => 1});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						variable   => $variable, 
						"<< value" => $value, 
					}});
				}
			}
			
			# Save it.
			if (exists $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{$type}{$variable})
			{
				# Conflict! This is a dirty way to keep them separate
				$variable .= " 2";
			}
			
			$variable = process_variable_name($anvil, $variable);
			
			# What am I saving?
			if (($port) && ($box) && ($bay))
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"line" => $line, 
				}});
				
				# Physical drive info
				$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{$type}{$variable} = $value;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"controller::${scan_hpacucli_controller_serial_number}::array::${scan_hpacucli_array_name}::logical_drive::${logical_drive}::physical_drive::port::${port}::box::${box}::bay::${bay}::${type}::$variable" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{physical_drive}{port}{$port}{box}{$box}{bay}{$bay}{$type}{$variable}, 
				}});
				
				# Map the SN to it's current location.
				if ($line =~ /Serial Number: (.*?)$/)
				{
					   $scan_hpacucli_physical_drive_serial_number = $1;
					my $location                                   = $port.":".$box.":".$bay;
					$anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number} = {
						array         => $scan_hpacucli_array_name,
						logical_drive => $logical_drive,
						port          => $port,
						box           => $box,
						bay           => $bay,
					};
					$anvil->data->{physical_drive}{by_location}{$location} = $scan_hpacucli_physical_drive_serial_number;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"physical_drive::by_serial_number::${scan_hpacucli_physical_drive_serial_number}::array"         => $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number}{array}, 
						"physical_drive::by_serial_number::${scan_hpacucli_physical_drive_serial_number}::logical_drive" => $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number}{logical_drive}, 
						"physical_drive::by_serial_number::${scan_hpacucli_physical_drive_serial_number}::port"          => $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number}{port}, 
						"physical_drive::by_serial_number::${scan_hpacucli_physical_drive_serial_number}::box"           => $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number}{box}, 
						"physical_drive::by_serial_number::${scan_hpacucli_physical_drive_serial_number}::bay"           => $anvil->data->{physical_drive}{by_serial_number}{$scan_hpacucli_physical_drive_serial_number}{bay}, 
						"physical_drive::by_location::$location"                                                         => $anvil->data->{physical_drive}{by_location}{$location}, 
					}});
				}
			}
			elsif ($logical_drive)
			{
				# Logical drive
				$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{data}{$type}{$variable} = $value;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"controller::${scan_hpacucli_controller_serial_number}::array::${scan_hpacucli_array_name}::logical_drive::${logical_drive}::data::${type}::$variable" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{logical_drive}{$logical_drive}{data}{$type}{$variable}, 
				}});
			}
			elsif ($scan_hpacucli_array_name)
			{
				# Array
				$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{$type}{$variable} = $value;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"controller::${scan_hpacucli_controller_serial_number}::array::${scan_hpacucli_array_name}::data::${type}::$variable" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{$type}{$variable}, 
				}});
			}
			else
			{
				# Controller data
				$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable} = $value;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"controller::${scan_hpacucli_controller_serial_number}::data::${type}::$variable" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{data}{$type}{$variable}, 
				}});
			}
		}
		elsif ($in_array)
		{
			# Messages about a degraded array can be here.
			# ie: "One of the drives on this array have failed or has been removed."
			if ($line =~ /this array have failed/)
			{
				# We'll concatonate in case there are multiple errors.
				if (not exists $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message})
				{
					$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message} = "";
				}
				$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message} .= $line."\n";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"controller::${scan_hpacucli_controller_serial_number}::array::${scan_hpacucli_array_name}::data::detail::error_message" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{array}{$scan_hpacucli_array_name}{data}{detail}{error_message}, 
				}});
			}
		}

	}
	
	# If I didn't find a serial number, something went wrong.
	if (not $scan_hpacucli_controller_serial_number)
	{
		# Error out.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_hpacucli_error_0004", variables => { controller => $controller }});
		$anvil->nice_exit({exit_code => 6});
	}
	
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number }});
	return($scan_hpacucli_controller_serial_number);
}

# This will do a details diagnostics check, if enough time has passed.
sub get_diagnostics
{
	my ($anvil, $controller) = @_;

	# Every 'scan-hpacucli::diagnostics_interval' seconds, run a full diagnostics to check for drives in 
	# pre-failure.
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::process_diagnostics" => $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics} }});
	if (not $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics})
	{
		# Is it time?
		my $query = "SELECT scan_hpacucli_controller_last_diagnostics FROM scan_hpacucli_controllers WHERE scan_hpacucli_controller_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid).";";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		#                     The actual query -----------------.                                                .------- Row 0
		#                        Query this DB --.              |                                                |    .-- Columns 0
		my $last_diagnostics = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
		   $last_diagnostics = 0 if not defined $last_diagnostics;
		my $current_time     = time;
		my $last_scan_was    = $current_time - $last_diagnostics;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			last_diagnostics                      => $last_diagnostics, 
			current_time                          => $current_time, 
			last_scan_was                         => $last_scan_was, 
			"scan-hpacucli::diagnostics_interval" => $anvil->data->{'scan-hpacucli'}{diagnostics_interval}, 
		}});
		
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"scan-hpacucli::diagnostics_interval" => $last_diagnostics, 
		}});
		if ($anvil->data->{'scan-hpacucli'}{diagnostics_interval} !~ /^\d+$/)
		{
			# Invalid value, override.
			$anvil->data->{'scan-hpacucli'}{diagnostics_interval} = 1800;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"scan-hpacucli::diagnostics_interval" => $anvil->data->{'scan-hpacucli'}{diagnostics_interval}, 
			}});
		}
		if ($last_scan_was > $anvil->data->{'scan-hpacucli'}{diagnostics_interval})
		{
			$anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics} = 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"sys::process_diagnostics" => $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics}, 
			}});
		}
	}
	
	# Well, is it?
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"sys::process_diagnostics" => $anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics}, 
	}});
	if ($anvil->data->{'scan-hpacucli'}{sys}{process_diagnostics})
	{
		# Yup! We use hpacucli's diagnostics to gather all data.
		my $shell_call = "
cd /tmp/
".$anvil->data->{path}{exe}{hpacucli}." controller slot=".$controller." diag file=/tmp/ADUReport.zip
".$anvil->data->{path}{exe}{'unzip'}." -o /tmp/ADUReport.zip -d /tmp/
if [ -e '/tmp/ADUReport.xml' ];
then
    ".$anvil->data->{path}{exe}{rm}." -f /tmp/ADUReport.zip
    ".$anvil->data->{path}{exe}{rm}." -f /tmp/ADUReport.htm
    ".$anvil->data->{path}{exe}{rm}." -f /tmp/ADUReport.xml
    ".$anvil->data->{path}{exe}{rm}." -f /tmp/report.checksum
fi
";
		# Write a log message to warn the user that we're starting a long process.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_hpacucli_log_0003", variables => { shell_call => $shell_call }});
		my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
			output      => $output, 
			return_code => $return_code,
		}});
		foreach my $line (split/\n/, $output)
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
		}
		undef $output;
		undef $return_code;
		
		# Did it work?
		if (not -r "/tmp/ADUReport.txt")
		{
			# Something went wrong.
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_hpacucli_error_0005", variables => { path => "/tmp/ADUReport.txt" }});
			$anvil->nice_exit({exit_code => 4});
		}
		
		# Get this controller's serial number
		my $scan_hpacucli_controller_serial_number = $anvil->data->{controller}{metadata}{slot_to_sn}{$controller};
		
		# Parse!
		my $in_cache_config_status                     = 0;
		my $in_physical_drive                          = 0;
		my $scan_hpacucli_physical_drive_serial_number = "";
		my $port                                       = "";
		my $box                                        = "";
		my $bay                                        = "";
		my $skip_blank_line                            = 0;
		   $shell_call                                 = "/tmp/ADUReport.txt";
		($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
			output      => $output, 
			return_code => $return_code,
		}});
		foreach my $line (split/\n/, $output)
		{
			$line =  $anvil->Words->clean_spaces({string => $line});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});

			if (not $line)
			{
				if ($skip_blank_line)
				{
					next;
				}
				$in_cache_config_status                     = 0;
				$in_physical_drive                          = 0;
				$scan_hpacucli_physical_drive_serial_number = "";
				$port                                       = "";
				$box                                        = "";
				$bay                                        = "";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					in_cache_config_status                     => $in_cache_config_status, 
					in_physical_drive                          => $in_physical_drive, 
					scan_hpacucli_physical_drive_serial_number => $scan_hpacucli_physical_drive_serial_number, 
					port                                       => $port, 
					box                                        => $box, 
					bay                                        => $bay, 
				}});
				next;
			}
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
			
			$skip_blank_line = 0;
			
			if ($line =~ /: Cache Config Status$/i)
			{
				$in_cache_config_status = 1;
				$skip_blank_line        = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_cache_config_status => $in_cache_config_status }});
				next;
			}
			
			if ($line =~ /: Physical Drive \(.*?\) (.*?):(.*?):(.*?) : Monitor and Performance Statistics \(Since Factory\)/)
			{
				$port             = $1;
				$box              = $2;
				$bay              = $3;
				$skip_blank_line  = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					port => $port, 
					box  => $box, 
					bay  => $bay, 
				}});
			}
			
			if ($in_cache_config_status)
			{
				if ($line =~ /Parity Read Errors (\d+) \(/)
				{
					$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{'diagnostics'}{cache}{parity_read_errors} = $1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"controller::${scan_hpacucli_controller_serial_number}::diagnostics::cache::parity_read_errors" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{'diagnostics'}{cache}{parity_read_errors}, 
					}});
				}
				if ($line =~ /Parity Write Errors (\d+) \(/)
				{
					$anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{'diagnostics'}{cache}{parity_write_errors} = $1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"controller::${scan_hpacucli_controller_serial_number}::diagnostics::cache::parity_write_errors" => $anvil->data->{controller}{$scan_hpacucli_controller_serial_number}{'diagnostics'}{cache}{parity_write_errors}, 
					}});
				}
			}
			
			if (($port) && ($box) && ($bay))
			{
				my $location                                   = $port.":".$box.":".$bay;
				   $scan_hpacucli_physical_drive_serial_number = $anvil->data->{physical_drive}{by_location}{$location};

				if ($line =~ /Read Errors Hard (0x.*?)$/)
				{
					my $hex = $1;
					$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_hard} = hex($hex);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"hex"                                                                                          => $hex, 
						"physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::read_errors_hard" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_hard}, 
					}});
				}
				if ($line =~ /Read Errors Retry Recovered (0x.*?)$/)
				{
					my $hex = $1;
					$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_retry_recovered} = hex($hex);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"hex"                                                                                                     => $hex, 
						"physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::read_errors_retry_recovered" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_retry_recovered}, 
					}});
				}
				if ($line =~ /Read Errors ECC Corrected (0x.*?)$/)
				{
					my $hex = $1;
					$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_ecc_corrected} = hex($hex);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"hex"                                                                                                   => $hex, 
						"physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::read_errors_ecc_corrected" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{read_errors_ecc_corrected}, 
					}});
				}
				if ($line =~ /Write Errors Hard (0x.*?)$/)
				{
					my $hex = $1;
					$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_hard} = hex($hex);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"hex"                                                                                           => $hex, 
						"physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::write_errors_hard" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_hard}, 
					}});
				}
				if ($line =~ /Write Errors Retry Recovered (0x.*?)$/)
				{
					my $hex = $1;
					$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_retry_recovered} = hex($hex);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"hex"                                                                                                      => $hex, 
						"physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::write_errors_retry_recovered" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_retry_recovered}, 
					}});
				}
				if ($line =~ /Format Errors (0x.*?)$/)
				{
					my $hex = $1;
					$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{format_errors} = hex($hex);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"hex"                                                                                       => $hex, 
						"physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::format_errors" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{format_errors}, 
					}});
				}
				if ($line =~ /Write Errors After Remap (0x.*?)$/)
				{
					my $hex = $1;
					$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_after_remap} = hex($hex);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"hex"                                                                                                  => $hex, 
						"physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::write_errors_after_remap" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{write_errors_after_remap}, 
					}});
				}
				if ($line =~ /Hardware Errors (0x.*?)$/)
				{
					my $hex = $1;
					$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{hardware_errors} = hex($hex);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"hex"                                                                                         => $hex, 
						"physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::hardware_errors" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{hardware_errors}, 
					}});
				}
				if ($line =~ /Predictive Failure Errors (0x.*?)$/)
				{
					my $hex = $1;
					$anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{predictive_failure_errors} = hex($hex);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"hex"                                                                                                   => $hex, 
						"physical_drive::${scan_hpacucli_physical_drive_serial_number}::diagnostics::predictive_failure_errors" => $anvil->data->{physical_drive}{$scan_hpacucli_physical_drive_serial_number}{'diagnostics'}{predictive_failure_errors}, 
					}});
				}
			}
		}
	}
	
	return(0);
}

# This gathers the various data from the controller(s).
sub gather_data
{
	my ($anvil) = @_;
	
	### TODO: This assumes the controllers go 0, 1, ... n. If this is wrong, we'll need to call 
	###       'hpacucli controller all show' and parse the output as our outer loop.
	# Loops through reach found controller.
	foreach my $count (1..$anvil->data->{'scan-hpacucli'}{sys}{controller_count})
	{
		my $controller = $count - 1;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { controller => $controller }});
		
		# Read in controller data.
		my $scan_hpacucli_controller_serial_number = get_controller_info($anvil, $controller);
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_hpacucli_controller_serial_number => $scan_hpacucli_controller_serial_number }});
		
		get_diagnostics($anvil, $controller);
	}
	
	return(0);
}

# This processes variable names to flatten them and remove spaces and special characters.
sub process_variable_name
{
	my ($anvil, $variable) = @_;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "<< variable" => $variable }});
	
	$variable =  lc($variable);
	$variable =~ s/ /_/g;
	$variable =~ s/-/_/g;
	$variable =~ s/&/and/g;
	$variable =~ s/\//_or_/g;
	$variable =~ s/_%/_percent/g;
	$variable =~ s/{_}+/_/g;
	$variable =~ s/^_+//g;
	$variable =~ s/_+$//g;
	$variable =~ s/(\w)\(/$1_\(/;
	$variable =~ s/\((.*?)\)/-_$1/g;
	$variable =~ s/_+/_/g;
	
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ">> variable" => $variable }});
	return($variable);
}

# This does two things; It checks to see if hpacucli is installed (exits '1' if not, exits '2' if not 
# executable) and then checks to see if any controllers are found in the system (exits '3' if not). 
sub find_hp_controllers
{
	my ($anvil) = @_;
	

	# This will keep track of how many controllers we find.
	my $controller_count = 0;
	
	# First, do we have hpacucli installed?
	if (not -e $anvil->data->{path}{exe}{hpacucli})
	{
		# Nope, exit.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "scan_hpacucli_error_0001", variables => { path => $anvil->data->{path}{exe}{hpacucli} }});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Make sure it is executable
	if (not -x $anvil->data->{path}{exe}{hpacucli})
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_hpacucli_error_0002", variables => { path => $anvil->data->{path}{exe}{hpacucli} }});
		$anvil->nice_exit({exit_code => 2});
	}
	
	# Still alive? Good! Look for controllers now.
	my $shell_call = $anvil->data->{path}{exe}{hpacucli}." controller all show";
	my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
		output      => $output, 
		return_code => $return_code,
	}});
	foreach my $line (split/\n/, $output)
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
		
		if ($line =~ /.*? Slot (\d+) .*?\(sn: (.*?)\)/i)
		{
			my $controller_number        = $1;
			my $controller_serial_number = $2;
			   $controller_count++;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				controller_number        => $controller_number, 
				controller_serial_number => $controller_serial_number, 
				controller_count         => $controller_count, 
			}});
		}
	}
	
	# Have we any controllers?
	if ($controller_count > 0)
	{
		$anvil->data->{'scan-hpacucli'}{sys}{controller_count} = $controller_count;
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "scan_hpacucli_log_0001", variables => { count => $anvil->data->{'scan-hpacucli'}{sys}{controller_count} }});
	}
	else
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "scan_hpacucli_error_0003", variables => { path => $anvil->data->{path}{exe}{hpacucli} }});
		$anvil->nice_exit({exit_code => 3});
	}
	
	return(0);
}
