You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1293 lines
71 KiB
1293 lines
71 KiB
#!/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->data->{switches}{force} = 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; |
|
|
|
# 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); |
|
|
|
# Shut down. |
|
$anvil->ScanCore->agent_shutdown({agent => $THIS_FILE}); |
|
$anvil->nice_exit({exit_code => 0}); |
|
|
|
|
|
############################################################################################################# |
|
# Functions # |
|
############################################################################################################# |
|
|
|
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_internal_uuid = $row->[1]; |
|
my $scan_lvm_pv_name = $row->[2]; |
|
$anvil->data->{sql}{scan_lvm_pvs}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{scan_lvm_pv_uuid} = $row->[0];; |
|
$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_internal_uuid = $row->[1]; |
|
my $scan_lvm_vg_name = $row->[2]; |
|
$anvil->data->{sql}{scan_lvm_vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_uuid} = $row->[0]; |
|
$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_internal_uuid = $row->[1]; |
|
my $scan_lvm_lv_name = $row->[2]; |
|
$anvil->data->{sql}{scan_lvm_lvs}{scan_lvm_lv_internal_uuid}{$scan_lvm_lv_internal_uuid}{scan_lvm_lv_uuid} = $row->[0]; |
|
$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, |
|
}}); |
|
|
|
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, |
|
}}); |
|
|
|
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, |
|
}}); |
|
|
|
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); |
|
} |
|
|
|
|