#!/usr/bin/perl
# 
# This scans the LVM (logical volume management) components (PV, VG and LV). 
# 
# Examples;
# 
# Exit codes;
# 0 = Normal exit.
# 1 = Startup failure (not running as root, no DB, bad file read, etc)
# 
# NOTE: 
# - LVM created UUIDs before RFC 4122, so the internal UUIDs are incompatible with modern UUIDs. As such, 
#   they are treated as more of a "serial number" in this agent.
# 
# TODO: 
# - 
#

use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
use JSON;

# 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});
}

# These are the threasholds for when to alert when swap is running out.
$anvil->data->{scancore}{'scan-lvm'}{disable} = 0;

$anvil->Storage->read_config();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 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});
}

# Find the block devices on this host.
collect_data($anvil);

# Load stored data.
read_last_scan($anvil);

# Loog for changes
find_changes($anvil);

# Check storage for storage groups.
check_storage_groups($anvil);

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


#############################################################################################################
# Functions                                                                                                 #
#############################################################################################################

sub check_storage_groups
{
	my ($anvil) = @_;
	
	# Are we in an Anvil!? If so, are there any storage groups yet?
	my $anvil_uuid = $anvil->Cluster->get_anvil_uuid();
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
	
	if ($anvil_uuid)
	{
		# If we're node 1, we'll try to assemble the storage group. Onle node 1 does this to help avoid race 
		# conditions. This both loads storage group data and assembles ungrouped VGs into storage groups, 
		# when possible.
		$anvil->Database->get_anvils();
		my $host_uuid       = $anvil->Get->host_uuid;
		my $anvil_name      = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
		my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
		my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:anvil_name'      => $anvil_name,
			's2:node1_host_uuid' => $node1_host_uuid, 
			's3:node2_host_uuid' => $node2_host_uuid, 
			's4:host_uuid'       => $host_uuid, 
		}});
		if ($host_uuid eq $node1_host_uuid)
		{
			# Are there any storage groups yet? If not, try to assemble one.
			my $query = "SELECT COUNT(*) FROM storage_groups WHERE storage_group_anvil_uuid = ".$anvil->Database->quote($anvil_uuid).";";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});

			my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
			if (not $count)
			{
				$anvil->Cluster->assemble_storage_groups({
					debug      => 2,
					anvil_uuid => $anvil_uuid, 
				});
			}
		}
	}
	
	return(0);
}

sub find_changes
{
	my ($anvil) = @_;
	
	# Changes in PVs?
	find_changes_in_pvs($anvil);
	
	# Changes in VGs?
	find_changes_in_vgs($anvil);
	
	# Changes in LVs?
	find_changes_in_lvs($anvil);
	
	return(0);
}

sub find_changes_in_lvs
{
	my ($anvil) = @_;
	
	foreach my $scan_lvm_lv_internal_uuid (keys %{$anvil->data->{lvm}{scan_lvm_lv_internal_uuid}})
	{
		my $scan_lvm_lv_name       = $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{name};
		my $scan_lvm_lv_attributes = $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{attributes};
		my $scan_lvm_lv_on_vg      = $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{on_vg};
		my $scan_lvm_lv_size       = $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{size};
		my $scan_lvm_lv_path       = $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{device_path};
		my $scan_lvm_lv_on_pvs     = $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{on_pvs};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_lvm_lv_internal_uuid       => $scan_lvm_lv_internal_uuid, 
			scan_lvm_lv_name       => $scan_lvm_lv_name,
			scan_lvm_lv_attributes => $scan_lvm_lv_attributes,
			scan_lvm_lv_on_vg      => $scan_lvm_lv_on_vg,
			scan_lvm_lv_size       => $anvil->Convert->add_commas({number => $scan_lvm_lv_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_lv_size}),
			scan_lvm_lv_path       => $scan_lvm_lv_path,
			scan_lvm_lv_on_pvs     => $scan_lvm_lv_on_pvs, 
		}});
		
		# Have we seen this before?
		if (exists $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid})
		{
			# Yup, anything changed?
			my $scan_lvm_lv_uuid           = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_uuid};
			my $old_scan_lvm_lv_name       = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_name};
			my $old_scan_lvm_lv_attributes = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_attributes};
			my $old_scan_lvm_lv_on_vg      = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_on_vg};
			my $old_scan_lvm_lv_size       = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_size};
			my $old_scan_lvm_lv_path       = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_path};
			my $old_scan_lvm_lv_on_pvs     = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_on_pvs};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_lvm_lv_uuid           => $scan_lvm_lv_uuid, 
				old_scan_lvm_lv_name       => $old_scan_lvm_lv_name,
				old_scan_lvm_lv_attributes => $old_scan_lvm_lv_attributes,
				old_scan_lvm_lv_on_vg      => $old_scan_lvm_lv_on_vg,
				old_scan_lvm_lv_size       => $anvil->Convert->add_commas({number => $old_scan_lvm_lv_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_lv_size}),
				old_scan_lvm_lv_path       => $old_scan_lvm_lv_path,
				old_scan_lvm_lv_on_pvs     => $old_scan_lvm_lv_on_pvs, 
			}});
			
			my $update = 0;
			if ($scan_lvm_lv_name ne $old_scan_lvm_lv_name)
			{
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				if ($old_scan_lvm_lv_name eq "DELETED")
				{
					# A lost LV is back
					my $variables = { 
						lv_uuid => $scan_lvm_lv_internal_uuid, 
						lv_name => $scan_lvm_lv_name,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0021", variables => $variables});
					$anvil->Alert->register({clear_alert => 1, alert_level => "warning", message => "scan_lvm_alert_0021", variables => $variables, set_by => $THIS_FILE});
				}
				else
				{
					# LV name changed.
					my $variables = {
						lv_uuid     => $scan_lvm_lv_internal_uuid, 
						new_lv_name => $scan_lvm_lv_name,
						old_lv_name => $old_scan_lvm_lv_name,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0022", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0022", variables => $variables, set_by => $THIS_FILE});
				}
			}
			if ($scan_lvm_lv_attributes ne $old_scan_lvm_lv_attributes)
			{
				# Attribute bits changed.
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					lv_uuid        => $scan_lvm_lv_internal_uuid, 
					lv_name        => $scan_lvm_lv_name,
					new_attributes => $scan_lvm_lv_attributes,
					old_attributes => $old_scan_lvm_lv_attributes,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0023", variables => $variables});
				$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0023", variables => $variables, set_by => $THIS_FILE});
			}
			if ($scan_lvm_lv_on_vg ne $old_scan_lvm_lv_on_vg)
			{
				# This happens when an VG is renamed.
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					lv_uuid      => $scan_lvm_lv_internal_uuid, 
					lv_name      => $scan_lvm_lv_name,
					new_lv_on_vg => $scan_lvm_lv_on_vg,
					old_lv_on_vg => $old_scan_lvm_lv_on_vg,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0024", variables => $variables});
				$anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0024", variables => $variables, set_by => $THIS_FILE});
			}
			if ($scan_lvm_lv_size ne $old_scan_lvm_lv_size)
			{
				# VG size change; Did it grow or shrink?
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					lv_uuid           => $scan_lvm_lv_internal_uuid, 
					lv_name           => $scan_lvm_lv_name,
					new_lv_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_lv_size}),
					new_lv_size_bytes => $anvil->Convert->add_commas({number => $scan_lvm_lv_size}),
					old_lv_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_lv_size}),
					old_lv_size_bytes => $anvil->Convert->add_commas({number => $old_scan_lvm_lv_size}),
				};
				if ($scan_lvm_lv_size > $old_scan_lvm_lv_size)
				{
					# Grew, probably added a new PV
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0025", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0025", variables => $variables, set_by => $THIS_FILE});
				}
				else
				{
					# Shrank, 
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0026", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0026", variables => $variables, set_by => $THIS_FILE});
				}
			}
			if ($scan_lvm_lv_path ne $old_scan_lvm_lv_path)
			{
				# VG size changed, Grows when an LV is removed, shrings when an existing LV is extended or a new LV is created.
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					lv_uuid     => $scan_lvm_lv_internal_uuid, 
					lv_name     => $scan_lvm_lv_name,
					new_lv_path => $scan_lvm_lv_path,
					old_lv_path => $old_scan_lvm_lv_path,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0027", variables => $variables});
				$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0027", variables => $variables, set_by => $THIS_FILE});
			}
			if ($scan_lvm_lv_on_pvs ne $old_scan_lvm_lv_on_pvs)
			{
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					lv_uuid       => $scan_lvm_lv_internal_uuid, 
					lv_name       => $scan_lvm_lv_name,
					new_lv_on_pvs => $scan_lvm_lv_path,
					old_lv_on_pvs => $old_scan_lvm_lv_path,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0028", variables => $variables});
				$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0028", variables => $variables, set_by => $THIS_FILE});
			}
			
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
			if ($update)
			{
				my $query = "
UPDATE 
    scan_lvm_lvs 
SET 
    scan_lvm_lv_name       = ".$anvil->Database->quote($scan_lvm_lv_name).", 
    scan_lvm_lv_attributes = ".$anvil->Database->quote($scan_lvm_lv_attributes).", 
    scan_lvm_lv_on_vg      = ".$anvil->Database->quote($scan_lvm_lv_on_vg).", 
    scan_lvm_lv_size       = ".$anvil->Database->quote($scan_lvm_lv_size).", 
    scan_lvm_lv_path       = ".$anvil->Database->quote($scan_lvm_lv_path).", 
    scan_lvm_lv_on_pvs     = ".$anvil->Database->quote($scan_lvm_lv_on_pvs).", 
    modified_date          = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_lvm_lv_uuid       = ".$anvil->Database->quote($scan_lvm_lv_uuid)." 
;";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
			}
			
			# Delete the loaded entry so we can check for missing PVs later.
			delete $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid};
		}
		else
		{
			# New VG
			my $variables = {
				lv_uuid       => $scan_lvm_lv_internal_uuid, 
				lv_name       => $scan_lvm_lv_name,
				attributes    => $scan_lvm_lv_attributes,
				lv_on_vg      => $scan_lvm_lv_on_vg,
				lv_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_lv_size}),
				lv_size_bytes => $anvil->Convert->add_commas({number => $scan_lvm_lv_size}),
				lv_path       => $scan_lvm_lv_path,
				lv_on_pvs     => $scan_lvm_lv_on_pvs, 
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0029", variables => $variables});
			$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0029", variables => $variables, set_by => $THIS_FILE});
			
			my $scan_lvm_lv_uuid = $anvil->Get->uuid();
			my $query            = "
INSERT INTO 
    scan_lvm_lvs 
(
    scan_lvm_lv_uuid, 
    scan_lvm_lv_internal_uuid,
    scan_lvm_lv_host_uuid, 
    scan_lvm_lv_name, 
    scan_lvm_lv_on_vg, 
    scan_lvm_lv_attributes, 
    scan_lvm_lv_size, 
    scan_lvm_lv_path, 
    scan_lvm_lv_on_pvs, 
    modified_date
) VALUES (
    ".$anvil->Database->quote($scan_lvm_lv_uuid).", 
    ".$anvil->Database->quote($scan_lvm_lv_internal_uuid).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    ".$anvil->Database->quote($scan_lvm_lv_name).", 
    ".$anvil->Database->quote($scan_lvm_lv_on_vg).", 
    ".$anvil->Database->quote($scan_lvm_lv_attributes).", 
    ".$anvil->Database->quote($scan_lvm_lv_size).", 
    ".$anvil->Database->quote($scan_lvm_lv_path).", 
    ".$anvil->Database->quote($scan_lvm_lv_on_pvs).", 
    ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	# Any missing LVs?
	foreach my $scan_lvm_lv_internal_uuid (keys %{$anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}})
	{
		# This one is missing.
		my $scan_lvm_lv_uuid     = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_uuid};
		my $old_scan_lvm_lv_name = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_name};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_lvm_lv_uuid     => $scan_lvm_lv_uuid,
			old_scan_lvm_lv_name => $old_scan_lvm_lv_name, 
		}});
		next if $old_scan_lvm_lv_name eq "DELETED";
		
		# Register an alert
		my $variables = { 
			lv_uuid => $scan_lvm_lv_internal_uuid, 
			lv_name => $old_scan_lvm_lv_name,
		};
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0031", variables => $variables});
		$anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0031", variables => $variables, set_by => $THIS_FILE});
		
		# Update it PV name to be 'DELTED'
		my $query = "
UPDATE 
    scan_lvm_lvs
SET 
    scan_lvm_lv_name = 'DELETED',
    modified_date    = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_lvm_lv_uuid = ".$anvil->Database->quote($scan_lvm_lv_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);
}

sub find_changes_in_vgs
{
	my ($anvil) = @_;
	
	foreach my $scan_lvm_vg_internal_uuid (keys %{$anvil->data->{lvm}{scan_lvm_vg_internal_uuid}})
	{
		my $scan_lvm_vg_name        = $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{name};
		my $scan_lvm_vg_attributes  = $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{attributes};
		my $scan_lvm_vg_extent_size = $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{extent_size};
		my $scan_lvm_vg_size        = $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{size};
		my $scan_lvm_vg_free        = $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{free_space};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_lvm_vg_internal_uuid => $scan_lvm_vg_internal_uuid, 
			scan_lvm_vg_name          => $scan_lvm_vg_name,
			scan_lvm_vg_attributes    => $scan_lvm_vg_attributes,
			scan_lvm_vg_extent_size   => $anvil->Convert->add_commas({number => $scan_lvm_vg_extent_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_extent_size}),
			scan_lvm_vg_size          => $anvil->Convert->add_commas({number => $scan_lvm_vg_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_size}),
			scan_lvm_vg_free          => $anvil->Convert->add_commas({number => $scan_lvm_vg_free})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_free}),
		}});
		
		# Have we seen this before?
		if (exists $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid})
		{
			# Yup, anything changed?
			my $scan_lvm_vg_uuid            = $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_uuid};
			my $old_scan_lvm_vg_name        = $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_name};
			my $old_scan_lvm_vg_attributes  = $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_attributes};
			my $old_scan_lvm_vg_extent_size = $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_extent_size};
			my $old_scan_lvm_vg_size        = $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_size};
			my $old_scan_lvm_vg_free        = $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_free};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				scan_lvm_vg_uuid            => $scan_lvm_vg_uuid, 
				old_scan_lvm_vg_name        => $old_scan_lvm_vg_name,
				old_scan_lvm_vg_attributes  => $old_scan_lvm_vg_attributes,
				old_scan_lvm_vg_extent_size => $anvil->Convert->add_commas({number => $old_scan_lvm_vg_extent_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_vg_extent_size}),,
				old_scan_lvm_vg_size        => $anvil->Convert->add_commas({number => $old_scan_lvm_vg_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_vg_size}),
				old_scan_lvm_vg_free        => $anvil->Convert->add_commas({number => $old_scan_lvm_vg_free})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_vg_free}),
			}});
			
			my $update = 0;
			if ($scan_lvm_vg_name ne $old_scan_lvm_vg_name)
			{
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				if ($old_scan_lvm_vg_name eq "DELETED")
				{
					# A lost PV is back
					my $variables = { 
						vg_uuid => $scan_lvm_vg_internal_uuid, 
						vg_name => $scan_lvm_vg_name,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0011", variables => $variables});
					$anvil->Alert->register({clear_alert => 1, alert_level => "warning", message => "scan_lvm_alert_0011", variables => $variables, set_by => $THIS_FILE});
				}
				else
				{
					# Device (name) changed... This can happen if the vg was renamed 
					my $variables = {
						vg_uuid     => $scan_lvm_vg_internal_uuid, 
						new_vg_name => $scan_lvm_vg_name,
						old_vg_name => $old_scan_lvm_vg_name,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0012", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0012", variables => $variables, set_by => $THIS_FILE});
				}
			}
			if ($scan_lvm_vg_attributes ne $old_scan_lvm_vg_attributes)
			{
				# Attribute bits changed.
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					vg_uuid        => $scan_lvm_vg_internal_uuid, 
					vg_name        => $scan_lvm_vg_name,
					new_attributes => $scan_lvm_vg_attributes,
					old_attributes => $old_scan_lvm_vg_attributes,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0013", variables => $variables});
				$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0013", variables => $variables, set_by => $THIS_FILE});
			}
			if ($scan_lvm_vg_extent_size ne $old_scan_lvm_vg_extent_size)
			{
				# This should never happen...
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					vg_uuid                  => $scan_lvm_vg_internal_uuid, 
					vg_name                  => $scan_lvm_vg_name,
					new_vg_extent_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_extent_size}),
					new_vg_extent_size_bytes => $anvil->Convert->add_commas({number => $scan_lvm_vg_extent_size}),
					old_vg_extent_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_vg_extent_size}),
					old_vg_extent_size_bytes => $anvil->Convert->add_commas({number => $old_scan_lvm_vg_extent_size}),
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0014", variables => $variables});
				$anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0014", variables => $variables, set_by => $THIS_FILE});
			}
			if ($scan_lvm_vg_size ne $old_scan_lvm_vg_size)
			{
				# VG size change; Did it grow or shrink?
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					vg_uuid           => $scan_lvm_vg_internal_uuid, 
					vg_name           => $scan_lvm_vg_name,
					new_vg_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_size}),
					new_vg_size_bytes => $anvil->Convert->add_commas({number => $scan_lvm_vg_size}),
					old_vg_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_vg_size}),
					old_vg_size_bytes => $anvil->Convert->add_commas({number => $old_scan_lvm_vg_size}),
				};
				if ($scan_lvm_vg_size > $old_scan_lvm_vg_size)
				{
					# Grew, probably added a new PV
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0015", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0015", variables => $variables, set_by => $THIS_FILE});
				}
				else
				{
					# Shrank, wat?
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0016", variables => $variables});
					$anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0016", variables => $variables, set_by => $THIS_FILE});
				}
			}
			if ($scan_lvm_vg_free ne $old_scan_lvm_vg_free)
			{
				# VG size changed, Grows when an LV is removed, shrings when an existing LV is extended or a new LV is created.
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					vg_uuid           => $scan_lvm_vg_internal_uuid, 
					vg_name           => $scan_lvm_vg_name,
					new_vg_free       => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_free}),
					new_vg_free_bytes => $anvil->Convert->add_commas({number => $scan_lvm_vg_free}),
					old_vg_free       => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_vg_free}),
					old_vg_free_bytes => $anvil->Convert->add_commas({number => $old_scan_lvm_vg_free}),
				};
				if ($scan_lvm_vg_free < $old_scan_lvm_vg_free)
				{
					# Likely a new LV was created or an existing one was extended.
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0017", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0017", variables => $variables, set_by => $THIS_FILE});
				}
				else
				{
					# An old LV was probably removed.
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0018", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0018", variables => $variables, set_by => $THIS_FILE});
				}
			}
			
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
			if ($update)
			{
				my $query = "
UPDATE 
    scan_lvm_vgs 
SET 
    scan_lvm_vg_name        = ".$anvil->Database->quote($scan_lvm_vg_name).", 
    scan_lvm_vg_attributes  = ".$anvil->Database->quote($scan_lvm_vg_attributes).", 
    scan_lvm_vg_extent_size = ".$anvil->Database->quote($scan_lvm_vg_extent_size).", 
    scan_lvm_vg_size        = ".$anvil->Database->quote($scan_lvm_vg_size).", 
    scan_lvm_vg_free        = ".$anvil->Database->quote($scan_lvm_vg_free).", 
    modified_date           = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_lvm_vg_uuid        = ".$anvil->Database->quote($scan_lvm_vg_uuid)." 
;";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
			}
			
			# Delete the loaded entry so we can check for missing PVs later.
			delete $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid};
		}
		else
		{
			# New VG
			my $variables = {
				vg_uuid           => $scan_lvm_vg_internal_uuid, 
				vg_name           => $scan_lvm_vg_name,
				attributes        => $scan_lvm_vg_attributes,
				extent_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_extent_size}),
				extent_size_bytes => $anvil->Convert->add_commas({number => $scan_lvm_vg_extent_size}),
				vg_size           => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_size}),
				vg_size_bytes     => $anvil->Convert->add_commas({number => $scan_lvm_vg_size}),
				vg_free           => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_free}),
				vg_free_bytes     => $anvil->Convert->add_commas({number => $scan_lvm_vg_free}),
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0020", variables => $variables});
			$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0020", variables => $variables, set_by => $THIS_FILE});
			
			my $scan_lvm_vg_uuid = $anvil->Get->uuid();
			my $query            = "
INSERT INTO 
    scan_lvm_vgs 
(
    scan_lvm_vg_uuid, 
    scan_lvm_vg_internal_uuid,
    scan_lvm_vg_host_uuid, 
    scan_lvm_vg_name, 
    scan_lvm_vg_extent_size, 
    scan_lvm_vg_attributes, 
    scan_lvm_vg_size, 
    scan_lvm_vg_free, 
    modified_date
) VALUES (
    ".$anvil->Database->quote($scan_lvm_vg_uuid).", 
    ".$anvil->Database->quote($scan_lvm_vg_internal_uuid).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    ".$anvil->Database->quote($scan_lvm_vg_name).", 
    ".$anvil->Database->quote($scan_lvm_vg_extent_size).", 
    ".$anvil->Database->quote($scan_lvm_vg_attributes).", 
    ".$anvil->Database->quote($scan_lvm_vg_size).", 
    ".$anvil->Database->quote($scan_lvm_vg_free).", 
    ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	# Any missing VGs?
	foreach my $scan_lvm_vg_internal_uuid (keys %{$anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}})
	{
		# This one is missing.
		my $scan_lvm_vg_uuid     = $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_uuid};
		my $old_scan_lvm_vg_name = $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_name};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_lvm_vg_uuid     => $scan_lvm_vg_uuid,
			old_scan_lvm_vg_name => $old_scan_lvm_vg_name, 
		}});
		next if $old_scan_lvm_vg_name eq "DELETED";
		
		# Register an alert
		my $variables = { 
			vg_uuid => $scan_lvm_vg_internal_uuid, 
			vg_name => $old_scan_lvm_vg_name,
		};
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0030", variables => $variables});
		$anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0030", variables => $variables, set_by => $THIS_FILE});
		
		# Update it PV name to be 'DELTED'
		my $query = "
UPDATE 
    scan_lvm_vgs
SET 
    scan_lvm_vg_name = 'DELETED',
    modified_date    = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_lvm_vg_uuid = ".$anvil->Database->quote($scan_lvm_vg_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);
}

sub find_changes_in_pvs
{
	my ($anvil) = @_;
	
	foreach my $scan_lvm_pv_internal_uuid (keys %{$anvil->data->{lvm}{scan_lvm_pv_internal_uuid}})
	{
		my $scan_lvm_pv_name        = $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{name};
		my $scan_lvm_pv_used_by_vg  = $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{used_by_vg};
		my $scan_lvm_pv_attributes  = $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{attributes};
		my $scan_lvm_pv_size        = $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{size};
		my $scan_lvm_pv_free        = $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{free_space};
		my $scan_lvm_pv_sector_size = $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{sector_size};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_lvm_pv_internal_uuid       => $scan_lvm_pv_internal_uuid, 
			scan_lvm_pv_name        => $scan_lvm_pv_name,
			scan_lvm_pv_used_by_vg  => $scan_lvm_pv_used_by_vg,
			scan_lvm_pv_attributes  => $scan_lvm_pv_attributes,
			scan_lvm_pv_size        => $anvil->Convert->add_commas({number => $scan_lvm_pv_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_pv_size}),
			scan_lvm_pv_free        => $anvil->Convert->add_commas({number => $scan_lvm_pv_free})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_pv_free}),
			scan_lvm_pv_sector_size => $anvil->Convert->add_commas({number => $scan_lvm_pv_sector_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_pv_sector_size}),
		}});
		
		# Have we seen this before?
		if (exists $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid})
		{
			# Yup, anything changed?
			my $scan_lvm_pv_uuid            = $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_uuid};
			my $old_scan_lvm_pv_name        = $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_name};
			my $old_scan_lvm_pv_used_by_vg  = $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_used_by_vg};
			my $old_scan_lvm_pv_attributes  = $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_attributes};
			my $old_scan_lvm_pv_size        = $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_size};
			my $old_scan_lvm_pv_free        = $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_free};
			my $old_scan_lvm_pv_sector_size = $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_sector_size};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				old_scan_lvm_pv_name        => $old_scan_lvm_pv_name,
				old_scan_lvm_pv_used_by_vg  => $old_scan_lvm_pv_used_by_vg,
				old_scan_lvm_pv_attributes  => $old_scan_lvm_pv_attributes,
				old_scan_lvm_pv_size        => $anvil->Convert->add_commas({number => $old_scan_lvm_pv_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_pv_size}),
				old_scan_lvm_pv_free        => $anvil->Convert->add_commas({number => $old_scan_lvm_pv_free})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_pv_free}),
				old_scan_lvm_pv_sector_size => $anvil->Convert->add_commas({number => $old_scan_lvm_pv_sector_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_pv_sector_size}),
			}});
			
			my $update = 0;
			if ($scan_lvm_pv_name ne $old_scan_lvm_pv_name)
			{
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				if ($old_scan_lvm_pv_name eq "DELETED")
				{
					# A lost PV is back
					my $variables = { 
						pv_uuid => $scan_lvm_pv_internal_uuid, 
						pv_name => $scan_lvm_pv_name,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0001", variables => $variables});
					$anvil->Alert->register({clear_alert => 1, alert_level => "warning", message => "scan_lvm_alert_0001", variables => $variables, set_by => $THIS_FILE});
				}
				else
				{
					# Device (name) changed... This shouldn't normally happen.
					my $variables = {
						pv_uuid     => $scan_lvm_pv_internal_uuid, 
						new_pv_name => $scan_lvm_pv_name,
						old_pv_name => $old_scan_lvm_pv_name,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0002", variables => $variables});
					$anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0002", variables => $variables, set_by => $THIS_FILE});
				}
			}
			if ($scan_lvm_pv_used_by_vg ne $old_scan_lvm_pv_used_by_vg)
			{
				# If the old value was blank, then this PV was added to a VG and that's fine.
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				if (not $old_scan_lvm_pv_used_by_vg)
				{
					# Added to a VG
					my $variables = {
						pv_uuid => $scan_lvm_pv_internal_uuid, 
						pv_name => $scan_lvm_pv_name,
						vg_name => $scan_lvm_pv_used_by_vg,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0004", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0004", variables => $variables, set_by => $THIS_FILE});
				}
				else
				{
					# The VG was probably renamed.
					my $variables = {
						pv_uuid     => $scan_lvm_pv_internal_uuid, 
						pv_name     => $scan_lvm_pv_name,
						new_vg_name => $scan_lvm_pv_used_by_vg,
						old_vg_name => $old_scan_lvm_pv_used_by_vg,
					};
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0005", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0005", variables => $variables, set_by => $THIS_FILE});
				}
			}
			if ($scan_lvm_pv_attributes ne $old_scan_lvm_pv_attributes)
			{
				# Attribute bits changed.
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					pv_uuid        => $scan_lvm_pv_internal_uuid, 
					pv_name        => $scan_lvm_pv_name,
					new_attributes => $scan_lvm_pv_attributes,
					old_attributes => $old_scan_lvm_pv_attributes,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0006", variables => $variables});
				$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0006", variables => $variables, set_by => $THIS_FILE});
			}
			if ($scan_lvm_pv_size ne $old_scan_lvm_pv_size)
			{
				# PE size changed, likely grew.
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					pv_uuid           => $scan_lvm_pv_internal_uuid, 
					pv_name           => $scan_lvm_pv_name,
					new_pv_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_pv_size}),
					new_pv_size_bytes => $anvil->Convert->add_commas({number => $scan_lvm_pv_size}),
					old_pv_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_pv_size}),
					old_pv_size_bytes => $anvil->Convert->add_commas({number => $old_scan_lvm_pv_size}),
				};
				if ($scan_lvm_pv_size > $old_scan_lvm_pv_size)
				{
					# Yup
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0007", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0007", variables => $variables, set_by => $THIS_FILE});
				}
				else
				{
					# Uhhhh... We'll make this a warning as it shouldn't happen.
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0008", variables => $variables});
					$anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0008", variables => $variables, set_by => $THIS_FILE});
				}
			}
			if ($scan_lvm_pv_free ne $old_scan_lvm_pv_free)
			{
				# PE size changed, likely shrunk.
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					pv_uuid           => $scan_lvm_pv_internal_uuid, 
					pv_name           => $scan_lvm_pv_name,
					new_pv_free       => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_pv_free}),
					new_pv_free_bytes => $anvil->Convert->add_commas({number => $scan_lvm_pv_free}),
					old_pv_free       => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_pv_free}),
					old_pv_free_bytes => $anvil->Convert->add_commas({number => $old_scan_lvm_pv_free}),
				};
				if ($scan_lvm_pv_free < $old_scan_lvm_pv_free)
				{
					# Yup
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0009", variables => $variables});
					$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0009", variables => $variables, set_by => $THIS_FILE});
				}
				else
				{
					# Uhhhh... We'll make this a warning as it shouldn't happen.
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0010", variables => $variables});
					$anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0010", variables => $variables, set_by => $THIS_FILE});
				}
			}
			if ($scan_lvm_pv_sector_size ne $old_scan_lvm_pv_sector_size)
			{
				# This is always a warning as the sector size should never change.
				$update = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
				my $variables = {
					pv_uuid                  => $scan_lvm_pv_internal_uuid, 
					pv_name                  => $scan_lvm_pv_name,
					new_pv_sector_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_pv_sector_size}),
					new_pv_sector_size_bytes => $anvil->Convert->add_commas({number => $scan_lvm_pv_sector_size}),
					old_pv_sector_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_lvm_pv_sector_size}),
					old_pv_sector_size_bytes => $anvil->Convert->add_commas({number => $old_scan_lvm_pv_sector_size}),
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0032", variables => $variables});
				$anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0032", variables => $variables, set_by => $THIS_FILE});
			}
			
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }});
			if ($update)
			{
				my $query = "
UPDATE 
    scan_lvm_pvs 
SET 
    scan_lvm_pv_name        = ".$anvil->Database->quote($scan_lvm_pv_name).", 
    scan_lvm_pv_used_by_vg  = ".$anvil->Database->quote($scan_lvm_pv_used_by_vg).", 
    scan_lvm_pv_attributes  = ".$anvil->Database->quote($scan_lvm_pv_attributes).", 
    scan_lvm_pv_size        = ".$anvil->Database->quote($scan_lvm_pv_size).", 
    scan_lvm_pv_free        = ".$anvil->Database->quote($scan_lvm_pv_free).", 
    scan_lvm_pv_sector_size = ".$anvil->Database->quote($scan_lvm_pv_sector_size).", 
    modified_date           = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_lvm_pv_uuid        = ".$anvil->Database->quote($scan_lvm_pv_uuid)." 
;";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
			}
			
			# Delete the loaded entry so we can check for missing PVs later.
			delete $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid};
		}
		else
		{
			# New PV
			my $variables = {
				pv_uuid              => $scan_lvm_pv_internal_uuid, 
				pv_name              => $scan_lvm_pv_name,
				vg_name              => $scan_lvm_pv_used_by_vg ? $scan_lvm_pv_used_by_vg : "--",
				attributes           => $scan_lvm_pv_attributes,
				pv_size              => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_pv_size}),
				pv_size_bytes        => $anvil->Convert->add_commas({number => $scan_lvm_pv_size}),
				pv_free              => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_pv_free}),
				pv_free_bytes        => $anvil->Convert->add_commas({number => $scan_lvm_pv_free}),
				pv_sector_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_pv_sector_size}),
				pv_sector_size_bytes => $anvil->Convert->add_commas({number => $scan_lvm_pv_sector_size}),
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0019", variables => $variables});
			$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0019", variables => $variables, set_by => $THIS_FILE});
			
			my $scan_lvm_pv_uuid = $anvil->Get->uuid();
			my $query            = "
INSERT INTO 
    scan_lvm_pvs 
(
    scan_lvm_pv_uuid, 
    scan_lvm_pv_internal_uuid,
    scan_lvm_pv_host_uuid, 
    scan_lvm_pv_name, 
    scan_lvm_pv_used_by_vg, 
    scan_lvm_pv_attributes, 
    scan_lvm_pv_size, 
    scan_lvm_pv_free, 
    scan_lvm_pv_sector_size, 
    modified_date
) VALUES (
    ".$anvil->Database->quote($scan_lvm_pv_uuid).", 
    ".$anvil->Database->quote($scan_lvm_pv_internal_uuid).", 
    ".$anvil->Database->quote($anvil->Get->host_uuid).", 
    ".$anvil->Database->quote($scan_lvm_pv_name).", 
    ".$anvil->Database->quote($scan_lvm_pv_used_by_vg).", 
    ".$anvil->Database->quote($scan_lvm_pv_attributes).", 
    ".$anvil->Database->quote($scan_lvm_pv_size).", 
    ".$anvil->Database->quote($scan_lvm_pv_free).", 
    ".$anvil->Database->quote($scan_lvm_pv_sector_size).", 
    ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
		}
	}
	
	# Any missing PVs?
	foreach my $scan_lvm_pv_internal_uuid (keys %{$anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}})
	{
		# This one is missing.
		my $scan_lvm_pv_uuid     = $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_uuid};
		my $old_scan_lvm_pv_name = $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_name};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:scan_lvm_pv_internal_uuid' => $scan_lvm_pv_internal_uuid, 
			's2:scan_lvm_pv_uuid'          => $scan_lvm_pv_uuid,
			's3:old_scan_lvm_pv_name'      => $old_scan_lvm_pv_name, 
		}});
		next if $old_scan_lvm_pv_name eq "DELETED";
		
		# Register an alert
		my $variables = { 
			pv_uuid => $scan_lvm_pv_internal_uuid, 
			pv_name => $old_scan_lvm_pv_name,
		};
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0003", variables => $variables});
		$anvil->Alert->register({alert_level => "warning", message => "scan_lvm_alert_0003", variables => $variables, set_by => $THIS_FILE});
		
		# Update it PV name to be 'DELTED'
		my $query = "
UPDATE 
    scan_lvm_pvs
SET 
    scan_lvm_pv_name = 'DELETED',
    modified_date    = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE 
    scan_lvm_pv_uuid = ".$anvil->Database->quote($scan_lvm_pv_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 the last scan's data.
sub read_last_scan
{
	my ($anvil) = @_;
	
	# Load PV data
	my $query = "
SELECT 
    scan_lvm_pv_uuid, 
    scan_lvm_pv_internal_uuid, 
    scan_lvm_pv_name, 
    scan_lvm_pv_used_by_vg, 
    scan_lvm_pv_attributes, 
    scan_lvm_pv_size, 
    scan_lvm_pv_free, 
    scan_lvm_pv_sector_size  
FROM 
    scan_lvm_pvs 
WHERE 
    scan_lvm_pv_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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})
	{
		# We've got an entry in the 'scan_lvm_pv' table, so now we'll look for data in the node and 
		# services tables.
		my $scan_lvm_pv_uuid          = $row->[0];
		my $scan_lvm_pv_internal_uuid = $row->[1]; 
		my $scan_lvm_pv_name          = $row->[2];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_lvm_pv_uuid          => $scan_lvm_pv_uuid, 
			scan_lvm_pv_internal_uuid => $scan_lvm_pv_internal_uuid, 
			scan_lvm_pv_name          => $scan_lvm_pv_name, 
		}});
		
		# If there's an existing entry, delete this one, it's somehow a duplicate.
		if (exists $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid})
		{
			# Duplicate!
			my $variables = {
				pv_name       => $scan_lvm_pv_name, 
				pv_uuid       => $scan_lvm_pv_uuid, 
				internal_uuid => $scan_lvm_pv_internal_uuid,
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0033", variables => $variables});
			$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0033", variables => $variables, set_by => $THIS_FILE});
			
			my $query = "DELETE FROM scan_lvm_pvs WHERE scan_lvm_pv_uuid = ".$anvil->Database->quote($scan_lvm_pv_uuid).";\n";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
			next;
		}
		
		# Save
		$anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_uuid}        = $scan_lvm_pv_uuid; 
		$anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_name}        = $scan_lvm_pv_name; 
		$anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_used_by_vg}  = $row->[3]; 
		$anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_attributes}  = $row->[4];
		$anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_size}        = $row->[5];
		$anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_free}        = $row->[6];
		$anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_sector_size} = $row->[7];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_lvm_pvs::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::scan_lvm_pv_uuid"        => $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_uuid},
			"sql::scan_lvm_pvs::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::scan_lvm_pv_name"        => $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_name},
			"sql::scan_lvm_pvs::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::scan_lvm_pv_used_by_vg"  => $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_used_by_vg},
			"sql::scan_lvm_pvs::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::scan_lvm_pv_attributes"  => $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_attributes},
			"sql::scan_lvm_pvs::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::scan_lvm_pv_size"        => $anvil->Convert->add_commas({number => $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_size}}),
			"sql::scan_lvm_pvs::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::scan_lvm_pv_free"        => $anvil->Convert->add_commas({number => $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_free}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_free}}),
			"sql::scan_lvm_pvs::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::scan_lvm_pv_sector_size" => $anvil->Convert->add_commas({number => $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_sector_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_sector_size}}),
		}});
	}
	undef $count;
	undef $results;
	
	# Load VG data
	$query = "
SELECT 
    scan_lvm_vg_uuid, 
    scan_lvm_vg_internal_uuid, 
    scan_lvm_vg_name, 
    scan_lvm_vg_attributes, 
    scan_lvm_vg_extent_size,
    scan_lvm_vg_size,
    scan_lvm_vg_free 
FROM 
    scan_lvm_vgs 
WHERE 
    scan_lvm_vg_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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})
	{
		# We've got an entry in the 'scan_lvm_vg' table, so now we'll look for data in the node and 
		# services tables.
		my $scan_lvm_vg_uuid          = $row->[0];
		my $scan_lvm_vg_internal_uuid = $row->[1]; 
		my $scan_lvm_vg_name          = $row->[2];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_lvm_vg_uuid          => $scan_lvm_vg_uuid, 
			scan_lvm_vg_internal_uuid => $scan_lvm_vg_internal_uuid, 
			scan_lvm_vg_name          => $scan_lvm_vg_name, 
		}});
		
		# If there's an existing entry, delete this one, it's somehow a duplicate.
		if (exists $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid})
		{
			# Duplicate!
			my $variables = {
				vg_name       => $scan_lvm_vg_name, 
				vg_uuid       => $scan_lvm_vg_uuid, 
				internal_uuid => $scan_lvm_vg_internal_uuid,
			};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0034", variables => $variables});
			$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0034", variables => $variables, set_by => $THIS_FILE});
			
			my $query = "DELETE FROM scan_lvm_vgs WHERE scan_lvm_vg_uuid = ".$anvil->Database->quote($scan_lvm_vg_uuid).";\n";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
			$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
			next;
		}
		
		# Save
		$anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_uuid}        = $scan_lvm_vg_uuid; 
		$anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_name}        = $scan_lvm_vg_name; 
		$anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_attributes}  = $row->[3]; 
		$anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_extent_size} = $row->[4];
		$anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_size}        = $row->[5];
		$anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_free}        = $row->[6];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_lvm_vgs::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_uuid"        => $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_uuid},
			"sql::scan_lvm_vgs::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_name"        => $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_name},
			"sql::scan_lvm_vgs::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_attributes"  => $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_attributes},
			"sql::scan_lvm_vgs::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_extent_size" => $anvil->Convert->add_commas({number => $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_extent_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_extent_size}}),
			"sql::scan_lvm_vgs::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_size"        => $anvil->Convert->add_commas({number => $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_size}}),
			"sql::scan_lvm_vgs::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_free"        => $anvil->Convert->add_commas({number => $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_free}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_free}}),
		}});
	}
	undef $count;
	undef $results;
	
	# Load LV data
	$query = "
SELECT 
    scan_lvm_lv_uuid, 
    scan_lvm_lv_internal_uuid, 
    scan_lvm_lv_name, 
    scan_lvm_lv_attributes, 
    scan_lvm_lv_on_vg,
    scan_lvm_lv_size,
    scan_lvm_lv_path,
    scan_lvm_lv_on_pvs
FROM 
    scan_lvm_lvs 
WHERE 
    scan_lvm_lv_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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})
	{
		# We've got an entry in the 'scan_lvm_lv' table, so now we'll look for data in the node and 
		# services tables.
		my $scan_lvm_lv_uuid          = $row->[0]; 
		my $scan_lvm_lv_internal_uuid = $row->[1]; 
		my $scan_lvm_lv_name          = $row->[2];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			scan_lvm_lv_uuid          => $scan_lvm_lv_uuid, 
			scan_lvm_lv_internal_uuid => $scan_lvm_lv_internal_uuid, 
			scan_lvm_lv_name          => $scan_lvm_lv_name, 
		}});
		
		# If there's an existing entry, delete this one, it's somehow a duplicate.
		if (exists $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid})
		{
			# Duplicate! Is one of them DELETED?
			my $existing_name = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_name};
			my $existing_uuid = $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				existing_name => $existing_name, 
				existing_uuid => $existing_uuid, 
			}});
			
			if ($anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_name} eq "DELETED")
			{
				# Delete the one we already read.
				my $variables = {
					lv_name       => $existing_name, 
					lv_uuid       => $existing_uuid, 
					internal_uuid => $scan_lvm_lv_internal_uuid,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0035", variables => $variables});
				$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0034", variables => $variables, set_by => $THIS_FILE});
				
				my $query = "DELETE FROM scan_lvm_lvs WHERE scan_lvm_lv_uuid = ".$anvil->Database->quote($existing_uuid).";\n";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
				
				delete $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid};
			}
			else
			{
				# Delete the new one
				my $variables = {
					lv_name       => $scan_lvm_lv_name, 
					lv_uuid       => $scan_lvm_lv_uuid, 
					internal_uuid => $scan_lvm_lv_internal_uuid,
				};
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_alert_0035", variables => $variables});
				$anvil->Alert->register({alert_level => "notice", message => "scan_lvm_alert_0034", variables => $variables, set_by => $THIS_FILE});
				
				my $query = "DELETE FROM scan_lvm_lvs WHERE scan_lvm_lv_uuid = ".$anvil->Database->quote($scan_lvm_lv_uuid).";\n";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
				$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
				
				next;
			}
		}
		
		# Save
		$anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_uuid}       = $scan_lvm_lv_uuid; 
		$anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_name}       = $scan_lvm_lv_name; 
		$anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_attributes} = $row->[3]; 
		$anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_on_vg}      = $row->[4]; 
		$anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_size}       = $row->[5]; 
		$anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_path}       = $row->[6]; 
		$anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_on_pvs}     = $row->[7];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"sql::scan_lvm_lvs::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::scan_lvm_lv_uuid"       => $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_uuid},
			"sql::scan_lvm_lvs::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::scan_lvm_lv_name"       => $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_name},
			"sql::scan_lvm_lvs::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::scan_lvm_lv_attributes" => $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_attributes},
			"sql::scan_lvm_lvs::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::scan_lvm_lv_on_vg"      => $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_on_vg},
			"sql::scan_lvm_lvs::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::scan_lvm_lv_size"       => $anvil->Convert->add_commas({number => $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_size}}),
			"sql::scan_lvm_lvs::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::scan_lvm_lv_path"       => $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_path},
			"sql::scan_lvm_lvs::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::scan_lvm_lv_on_pvs"     => $anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_on_pvs},
		}});
	}
	
	return(0);
}

sub collect_data
{
	my ($anvil) = @_;
	
	### TODO: Swap oput '--separator \#!\#' for '--reportformat json'
	collect_pvs_data($anvil);
	collect_vgs_data($anvil);
	collect_lvs_data($anvil);
	
	return(0);
}

sub collect_pvs_data
{
	my ($anvil) = @_;
	
	my $shell_call = $anvil->data->{path}{exe}{pvscan};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	my ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		return_code => $return_code,
	}});
	
	$shell_call = $anvil->data->{path}{exe}{pvs}." --noheadings --units b --reportformat json -o pv_uuid,pv_name,vg_name,pv_attr,pv_size,pv_free";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		return_code => $return_code,
	}});
	
	# If there's an old filter in lvm.conf, it will generate an error that breaks the JSON formatting. 
	# See: https://issues.redhat.com/browse/RHEL-29680
	if ($output =~ /remove the lvm.conf filter/gs)
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_log_0002"});
		my $new_output = "";
		foreach my $line (split/\n/, $output)
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
			if ($line =~ /remove the lvm.conf filter/)
			{
				next;
			}
			$new_output .= $line."\n";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_output => $new_output }});
		}
		$output = $new_output;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output }});
	}
	
	my $json                = JSON->new->allow_nonref;
	my $pvs_data            = $json->decode($output);
	my $default_sector_size = 512;
	foreach my $hash_ref (@{$pvs_data->{report}->[0]->{pv}})
	{
		my $scan_lvm_pv_internal_uuid                                                             = $hash_ref->{pv_uuid};
		   $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{name}       = $hash_ref->{pv_name};
		   $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{used_by_vg} = $hash_ref->{vg_name};
		   $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{attributes} = $hash_ref->{pv_attr};	# TODO: Parse this out
		   $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{size}       = ($hash_ref->{pv_size} =~ /^(\d+)B/)[0];
		   $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{free_space} = ($hash_ref->{pv_free} =~ /^(\d+)B/)[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"lvm::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::name"       => $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{name},
			"lvm::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::used_by_vg" => $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{used_by_vg},
			"lvm::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::attributes" => $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{attributes},
			"lvm::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::size"       => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{size}}).")",
			"lvm::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::free_space" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{free_space}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{free_space}}).")",
		}});
		
		# We need to find the sector size of this PV.
		my $partition =  $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{name};
		   $partition =~ s/^.*\///;
		my $directory =  "/sys/class/block/".$partition."/subsystem";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			partition => $partition, 
			directory => $directory,
		}});
		
		# Look for the parent device. For partitions like 'sda1', this is 'sda'. For 'nvmen0p1', this is 'nvmen0', etc.
		my $sector_size = 0;
		until ($sector_size)
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { partition => $partition }});
			
			if (not $partition)
			{
				# Weird... Default to 512.
				   $sector_size        = $default_sector_size;
				my $original_partition = $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{name};
				my $sector_path        = $directory."/".$original_partition."/queue/hw_sector_size";
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_warning_0001", variables => { 
					device      => $original_partition, 
					sector_path => $sector_path, 
					sector_size => $sector_size, 
				}});
			}
			
			my $sector_size_file = $directory."/".$partition."/queue/hw_sector_size";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sector_size_file => $sector_size_file }});
			if (-e $sector_size_file)
			{
				$sector_size = $anvil->Storage->read_file({file => $sector_size_file });
				chomp $sector_size;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sector_size => $sector_size }});
				
				if ((not $sector_size) or ($sector_size =~ /\D/))
				{
					# Something went wrong, default to 512.
				   $sector_size        = $default_sector_size;
				my $original_partition = $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{name};
				my $sector_path        = $directory."/".$original_partition."/queue/hw_sector_size";
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_warning_0001", variables => { 
					device      => $original_partition, 
					sector_path => $sector_path, 
					sector_size => $sector_size, 
				}});
				}
			}
			
			# Take a number off and try again.
			chop $partition;
		}
		$anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{sector_size} = $sector_size;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"lvm::scan_lvm_pv_internal_uuid::${scan_lvm_pv_internal_uuid}::sector_size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{sector_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{sector_size}}).")",
		}});
	}
	
	return(0);
}

sub collect_vgs_data
{
	my ($anvil) = @_;
	
	my $shell_call = $anvil->data->{path}{exe}{vgscan};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	my ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		return_code => $return_code,
	}});
	
	$shell_call = $anvil->data->{path}{exe}{vgs}." --noheadings --units b --reportformat json -o vg_uuid,vg_name,vg_attr,vg_extent_size,vg_size,vg_free";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		return_code => $return_code,
	}});
	
	# If there's an old filter in lvm.conf, it will generate an error that breaks the JSON formatting. 
	# See: https://issues.redhat.com/browse/RHEL-29680
	if ($output =~ /remove the lvm.conf filter/gs)
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_log_0002"});
		my $new_output = "";
		foreach my $line (split/\n/, $output)
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
			if ($line =~ /remove the lvm.conf filter/)
			{
				next;
			}
			$new_output .= $line."\n";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_output => $new_output }});
		}
		$output = $new_output;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output }});
	}
	
	my $json     = JSON->new->allow_nonref;
	my $vgs_data = $json->decode($output);
	foreach my $hash_ref (@{$vgs_data->{report}->[0]->{vg}})
	{
		my $scan_lvm_vg_internal_uuid                                                     = $hash_ref->{vg_uuid};
		   $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{name}        = $hash_ref->{vg_name};
		   $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{attributes}  = $hash_ref->{vg_attr};
		   $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{extent_size} = ($hash_ref->{vg_extent_size} =~ /^(\d+)B/)[0];
		   $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{size}        = ($hash_ref->{vg_size} =~ /^(\d+)B/)[0];
		   $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{free_space}  = ($hash_ref->{vg_free} =~ /^(\d+)B/)[0];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"lvm::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::name"        => $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{name},
			"lvm::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::attributes"  => $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{attributes},
			"lvm::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::extent_size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{extent_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{extent_size}}),
			"lvm::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::size"        => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{size}}),
			"lvm::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::free_space"  => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{free_space}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{free_space}}),
		}});
	}
	
	return(0);
}
	
sub collect_lvs_data
{
	my ($anvil) = @_;
	
	my $shell_call = $anvil->data->{path}{exe}{lvscan};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	my ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		return_code => $return_code,
	}});
	
	$shell_call = $anvil->data->{path}{exe}{lvs}." --noheadings --units b --reportformat json -o lv_name,vg_name,lv_attr,lv_size,lv_uuid,lv_path,devices";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		return_code => $return_code,
	}});
	
	# If there's an old filter in lvm.conf, it will generate an error that breaks the JSON formatting. 
	# See: https://issues.redhat.com/browse/RHEL-29680
	if ($output =~ /remove the lvm.conf filter/gs)
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_log_0002"});
		my $new_output = "";
		foreach my $line (split/\n/, $output)
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
			if ($line =~ /remove the lvm.conf filter/)
			{
				next;
			}
			$new_output .= $line."\n";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_output => $new_output }});
		}
		$output = $new_output;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output }});
	}
	
	my $json     = JSON->new->allow_nonref;
	my $lvs_data = $json->decode($output);
	foreach my $hash_ref (@{$lvs_data->{report}->[0]->{lv}})
	{
		my $scan_lvm_lv_internal_uuid =  $hash_ref->{lv_uuid};
		my $on_pvs                    =  $hash_ref->{devices};
		   $on_pvs                    =~ s/\(\d+\)//g;
		# In JSON format, there are 2+ hash references when there are 2+ PVs under an LV. So we 
		# record all data on the first pass and append the additional PVs.
		if (not exists $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid})
		{
			$anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{name}        =  $hash_ref->{lv_name};
			$anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{attributes}  =  $hash_ref->{lv_attr};
			$anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{on_vg}       =  $hash_ref->{vg_name};
			$anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{device_path} =  $hash_ref->{lv_path};
			$anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{size}        =  ($hash_ref->{lv_size} =~ /^(\d+)B/)[0];
			$anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{on_pvs} = $on_pvs;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"lvm::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::name"        => $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{name},
				"lvm::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::attributes"  => $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{attributes},
				"lvm::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::on_vg"       => $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{on_vg},
				"lvm::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::device_path" => $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{device_path},
				"lvm::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::size"        => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{size}}),
				"lvm::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::on_pvs"      => $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{on_pvs},
			}});
		}
		else
		{
			$anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{on_pvs} .= ",".$on_pvs;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"lvm::scan_lvm_lv_internal_uuid::${scan_lvm_lv_internal_uuid}::on_pvs" => $anvil->data->{lvm}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{on_pvs},
			}});
		}
	}
	
	return(0);
}
	
