* Updated System->call() to take the 'timeout' parameter which, when set, prepends the call with 'timeout X <shell_call>' to make it easier to deal with calls that could potentially hang.
* Renamed scan-storage to scan-lvm as we only really care about LVM data in this agent. A dedicated scan-drbd will be created later. Got the agent to parse the pvs/vgs/lvs data. Signed-off-by: Digimer <digimer@alteeve.ca>main
parent
33101f969a
commit
2f4a06f2e0
12 changed files with 470 additions and 150 deletions
@ -0,0 +1,213 @@ |
||||
#!/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) |
||||
# |
||||
# 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({log_level => 2, log_secure => 1}); |
||||
$anvil->Log->level({set => 2}); |
||||
$anvil->Log->secure({set => 1}); |
||||
|
||||
# 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 => 1, key => "log_0115", variables => { program => $THIS_FILE }}); |
||||
|
||||
# Read switches |
||||
$anvil->Get->switches; |
||||
|
||||
# If we're disabled and '--force' wasn't used, exit. |
||||
if (($anvil->data->{scancore}{'scan-lvm'}{disable}) && (not $anvil->data->{switches}{force})) |
||||
{ |
||||
# Exit. |
||||
$anvil->nice_exit({exit_code => 0}); |
||||
} |
||||
|
||||
# These are the tables used by this agent. The order matters as it controls to order the tables are created |
||||
# and sync'ed. For purges, this array is walked backwards. |
||||
$anvil->data->{scancore}{'scan-lvm'}{tables} = ["scan_lvm_pvs", "scan_lvm_vgs", "scan_lvm_lvs"]; |
||||
|
||||
# Handle start-up tasks |
||||
my $problem = $anvil->ScanCore->agent_startup({ |
||||
debug => 3, |
||||
agent => $THIS_FILE, |
||||
tables => $anvil->data->{scancore}{'scan-lvm'}{tables}, |
||||
}); |
||||
if ($problem) |
||||
{ |
||||
$anvil->nice_exit({exit_code => 1}); |
||||
} |
||||
|
||||
if ($anvil->data->{switches}{purge}) |
||||
{ |
||||
# This can be called when doing bulk-database purges. |
||||
$anvil->Database->purge_data({ |
||||
debug => 2, |
||||
tables => $anvil->data->{scancore}{'scan-lvm'}{tables}, |
||||
}); |
||||
$anvil->nice_exit({exit_code => 0}); |
||||
} |
||||
|
||||
# Find the block devices on this host. |
||||
collect_data($anvil); |
||||
|
||||
|
||||
# Mark that we ran. |
||||
$anvil->Database->insert_or_update_updated({updated_by => $THIS_FILE}); |
||||
|
||||
$anvil->nice_exit({exit_code => 0}); |
||||
|
||||
############################################################################################################# |
||||
# Functions # |
||||
############################################################################################################# |
||||
|
||||
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 ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $anvil->data->{path}{exe}{pvscan}}); |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output, return_code => $return_code }}); |
||||
|
||||
($output, $return_code) = $anvil->System->call({timeout => 15, 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 => 3, list => { output => $output, return_code => $return_code }}); |
||||
|
||||
my $json = JSON->new->allow_nonref; |
||||
my $pvs_data = $json->decode($output); |
||||
foreach my $hash_ref (@{$pvs_data->{report}->[0]->{pv}}) |
||||
{ |
||||
my $pv_uuid = $hash_ref->{pv_uuid}; |
||||
$anvil->data->{lvm}{pv_uuid}{$pv_uuid}{name} = $hash_ref->{pv_name}; |
||||
$anvil->data->{lvm}{pv_uuid}{$pv_uuid}{used_by_vg} = $hash_ref->{vg_name}; |
||||
$anvil->data->{lvm}{pv_uuid}{$pv_uuid}{attributes} = $hash_ref->{pv_attr}; # TODO: Parse this out |
||||
$anvil->data->{lvm}{pv_uuid}{$pv_uuid}{size} = ($hash_ref->{pv_size} =~ /^(\d+)B/)[0]; |
||||
$anvil->data->{lvm}{pv_uuid}{$pv_uuid}{free_space} = ($hash_ref->{pv_free} =~ /^(\d+)B/)[0]; |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
||||
"lvm::pv_uuid::${pv_uuid}::name" => $anvil->data->{lvm}{pv_uuid}{$pv_uuid}{name}, |
||||
"lvm::pv_uuid::${pv_uuid}::used_by_vg" => $anvil->data->{lvm}{pv_uuid}{$pv_uuid}{used_by_vg}, |
||||
"lvm::pv_uuid::${pv_uuid}::attributes" => $anvil->data->{lvm}{pv_uuid}{$pv_uuid}{attributes}, |
||||
"lvm::pv_uuid::${pv_uuid}::size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{pv_uuid}{$pv_uuid}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{pv_uuid}{$pv_uuid}{size}}).")", |
||||
"lvm::pv_uuid::${pv_uuid}::free_space" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{pv_uuid}{$pv_uuid}{free_space}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{pv_uuid}{$pv_uuid}{free_space}}).")", |
||||
}}); |
||||
} |
||||
|
||||
return(0); |
||||
} |
||||
|
||||
sub collect_vgs_data |
||||
{ |
||||
my ($anvil) = @_; |
||||
|
||||
my ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $anvil->data->{path}{exe}{vgscan}}); |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output, return_code => $return_code }}); |
||||
|
||||
($output, $return_code) = $anvil->System->call({timeout => 15, 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 => 3, 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 $vg_uuid = $hash_ref->{vg_uuid}; |
||||
$anvil->data->{lvm}{vg_uuid}{$vg_uuid}{name} = $hash_ref->{vg_name}; |
||||
$anvil->data->{lvm}{vg_uuid}{$vg_uuid}{attributes} = $hash_ref->{vg_attr}; |
||||
$anvil->data->{lvm}{vg_uuid}{$vg_uuid}{extent_size} = ($hash_ref->{vg_extent_size} =~ /^(\d+)B/)[0]; |
||||
$anvil->data->{lvm}{vg_uuid}{$vg_uuid}{size} = ($hash_ref->{vg_size} =~ /^(\d+)B/)[0]; |
||||
$anvil->data->{lvm}{vg_uuid}{$vg_uuid}{free_space} = ($hash_ref->{vg_free} =~ /^(\d+)B/)[0]; |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
||||
"lvm::vg_uuid::${vg_uuid}::name" => $anvil->data->{lvm}{vg_uuid}{$vg_uuid}{name}, |
||||
"lvm::vg_uuid::${vg_uuid}::attributes" => $anvil->data->{lvm}{vg_uuid}{$vg_uuid}{attributes}, |
||||
"lvm::vg_uuid::${vg_uuid}::extent_size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{vg_uuid}{$vg_uuid}{extent_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{vg_uuid}{$vg_uuid}{extent_size}}), |
||||
"lvm::vg_uuid::${vg_uuid}::size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{vg_uuid}{$vg_uuid}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{vg_uuid}{$vg_uuid}{size}}), |
||||
"lvm::vg_uuid::${vg_uuid}::free_space" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{vg_uuid}{$vg_uuid}{free_space}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{vg_uuid}{$vg_uuid}{free_space}}), |
||||
}}); |
||||
} |
||||
|
||||
return(0); |
||||
} |
||||
|
||||
sub collect_lvs_data |
||||
{ |
||||
my ($anvil) = @_; |
||||
|
||||
my ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $anvil->data->{path}{exe}{lvscan}}); |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output, return_code => $return_code }}); |
||||
|
||||
($output, $return_code) = $anvil->System->call({timeout => 15, 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 => { 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 $lv_uuid = $hash_ref->{lv_uuid}; |
||||
$anvil->data->{lvm}{lv_uuid}{$lv_uuid}{name} = $hash_ref->{lv_name}; |
||||
$anvil->data->{lvm}{lv_uuid}{$lv_uuid}{attributes} = $hash_ref->{lv_attr}; |
||||
$anvil->data->{lvm}{lv_uuid}{$lv_uuid}{on_vg} = $hash_ref->{vg_name}; |
||||
$anvil->data->{lvm}{lv_uuid}{$lv_uuid}{device_path} = $hash_ref->{lv_path}; |
||||
$anvil->data->{lvm}{lv_uuid}{$lv_uuid}{size} = ($hash_ref->{lv_size} =~ /^(\d+)B/)[0]; |
||||
$anvil->data->{lvm}{lv_uuid}{$lv_uuid}{on_pvs} = $hash_ref->{devices}; |
||||
$anvil->data->{lvm}{lv_uuid}{$lv_uuid}{on_pvs} =~ s/\(\d+\)//g; # Remove the starting PE numver |
||||
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
||||
"lvm::lv_uuid::${lv_uuid}::name" => $anvil->data->{lvm}{lv_uuid}{$lv_uuid}{name}, |
||||
"lvm::lv_uuid::${lv_uuid}::attributes" => $anvil->data->{lvm}{lv_uuid}{$lv_uuid}{attributes}, |
||||
"lvm::lv_uuid::${lv_uuid}::on_vg" => $anvil->data->{lvm}{lv_uuid}{$lv_uuid}{on_vg}, |
||||
"lvm::lv_uuid::${lv_uuid}::device_path" => $anvil->data->{lvm}{lv_uuid}{$lv_uuid}{device_path}, |
||||
"lvm::lv_uuid::${lv_uuid}::size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{lv_uuid}{$lv_uuid}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{lv_uuid}{$lv_uuid}{size}}), |
||||
"lvm::lv_uuid::${lv_uuid}::on_pvs" => $anvil->data->{lvm}{lv_uuid}{$lv_uuid}{on_pvs}, |
||||
}}); |
||||
} |
||||
|
||||
return(0); |
||||
} |
||||
|
@ -0,0 +1,200 @@ |
||||
-- This is the database schema for the 'scan-lvm Scan Agent'. |
||||
|
||||
|
||||
-- This table stores physical volume information |
||||
CREATE TABLE scan_lvm_pvs ( |
||||
scan_lvm_pv_uuid uuid primary key, -- This comes from the PV itself. |
||||
scan_lvm_pv_host_uuid uuid not null, |
||||
scan_lvm_pv_name text not null, -- This is the name of the PV. |
||||
scan_lvm_pv_used_by_vg text not null, -- This is the name of the VG that uses this PV. If it's blank, then no VG uses it yet. |
||||
scan_lvm_pv_attributes text not null, -- This is the short 3-character attribute of the PV |
||||
scan_lvm_pv_size numeric not null, -- The size of the PV in bytes |
||||
scan_lvm_pv_free numeric not null, -- The free space, in bytes. |
||||
modified_date timestamp with time zone not null, |
||||
|
||||
FOREIGN KEY(scan_lvm_pv_host_uuid) REFERENCES hosts(host_uuid) |
||||
); |
||||
ALTER TABLE scan_lvm_pvs OWNER TO admin; |
||||
|
||||
CREATE TABLE history.scan_lvm_pvs ( |
||||
history_id bigserial, |
||||
scan_lvm_pv_uuid uuid, |
||||
scan_lvm_pv_host_uuid uuid, |
||||
scan_lvm_pv_name text, |
||||
scan_lvm_pv_used_by_vg text, |
||||
scan_lvm_pv_attributes text, |
||||
scan_lvm_pv_size numeric, |
||||
scan_lvm_pv_free numeric, |
||||
modified_date timestamp with time zone not null |
||||
); |
||||
ALTER TABLE history.scan_lvm_pvs OWNER TO admin; |
||||
|
||||
CREATE FUNCTION history_scan_lvm_pvs() RETURNS trigger |
||||
AS $$ |
||||
DECLARE |
||||
history_scan_lvm_pvs RECORD; |
||||
BEGIN |
||||
SELECT INTO history_scan_lvm_pvs * FROM scan_lvm_pvs WHERE scan_lvm_pv_uuid=new.scan_lvm_pv_uuid; |
||||
INSERT INTO history.scan_lvm_pvs |
||||
(scan_lvm_pv_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, |
||||
modified_date) |
||||
VALUES |
||||
(history_scan_lvm_pvs.scan_lvm_pv_uuid, |
||||
history_scan_lvm_pvs.scan_lvm_pv_host_uuid, |
||||
history_scan_lvm_pvs.scan_lvm_pv_name, |
||||
history_scan_lvm_pvs.scan_lvm_pv_used_by_vg, |
||||
history_scan_lvm_pvs.scan_lvm_pv_attributes, |
||||
history_scan_lvm_pvs.scan_lvm_pv_size, |
||||
history_scan_lvm_pvs.scan_lvm_pv_used, |
||||
history_scan_lvm_pvs.modified_date); |
||||
RETURN NULL; |
||||
END; |
||||
$$ |
||||
LANGUAGE plpgsql; |
||||
ALTER FUNCTION history_scan_lvm_pvs() OWNER TO admin; |
||||
|
||||
CREATE TRIGGER trigger_scan_lvm_pvs |
||||
AFTER INSERT OR UPDATE ON scan_lvm_pvs |
||||
FOR EACH ROW EXECUTE PROCEDURE history_scan_lvm_pvs(); |
||||
|
||||
|
||||
-- This table stores volume group information |
||||
CREATE TABLE scan_lvm_vgs ( |
||||
scan_lvm_vg_uuid uuid primary key, -- This comes from the VG itself. |
||||
scan_lvm_vg_host_uuid uuid not null, |
||||
scan_lvm_vg_name text not null, -- This is the name of the VG. |
||||
scan_lvm_vg_attributes text not null, -- This is the short 6-character attribute of the VG |
||||
scan_lvm_vg_extent_size numeric not null, -- The size of each physical extent, in bytes. |
||||
scan_lvm_vg_size numeric not null, -- The size of the VG, in bytes. |
||||
scan_lvm_vg_free numeric not null, -- The free space in the VG, in bytes. |
||||
modified_date timestamp with time zone not null, |
||||
|
||||
FOREIGN KEY(scan_lvm_vg_host_uuid) REFERENCES hosts(host_uuid) |
||||
); |
||||
ALTER TABLE scan_lvm_vgs OWNER TO admin; |
||||
|
||||
CREATE TABLE history.scan_lvm_vgs ( |
||||
history_id bigserial, |
||||
scan_lvm_vg_uuid uuid, |
||||
scan_lvm_vg_host_uuid uuid, |
||||
scan_lvm_vg_name text, |
||||
scan_lvm_vg_attributes text, |
||||
scan_lvm_vg_extent_size numeric, |
||||
scan_lvm_vg_size numeric, |
||||
scan_lvm_vg_free numeric, |
||||
modified_date timestamp with time zone not null |
||||
); |
||||
ALTER TABLE history.scan_lvm_vgs OWNER TO admin; |
||||
|
||||
CREATE FUNCTION history_scan_lvm_vgs() RETURNS trigger |
||||
AS $$ |
||||
DECLARE |
||||
history_scan_lvm_vgs RECORD; |
||||
BEGIN |
||||
SELECT INTO history_scan_lvm_vgs * FROM scan_lvm_vgs WHERE scan_lvm_vg_uuid=new.scan_lvm_vg_uuid; |
||||
INSERT INTO history.scan_lvm_vgs |
||||
(scan_lvm_vg_uuid, |
||||
scan_lvm_vg_host_uuid, |
||||
scan_lvm_vg_name, |
||||
scan_lvm_vg_attributes, |
||||
scan_lvm_vg_extent_size, |
||||
scan_lvm_vg_size, |
||||
scan_lvm_vg_free, |
||||
modified_date) |
||||
VALUES |
||||
(history_scan_lvm_vgs.scan_lvm_vg_uuid, |
||||
history_scan_lvm_vgs.scan_lvm_vg_host_uuid, |
||||
history_scan_lvm_vgs.scan_lvm_vg_name, |
||||
history_scan_lvm_vgs.scan_lvm_vg_attributes, |
||||
history_scan_lvm_vgs.scan_lvm_vg_extent_size, |
||||
history_scan_lvm_vgs.scan_lvm_vg_size, |
||||
history_scan_lvm_vgs.scan_lvm_vg_free, |
||||
history_scan_lvm_vgs.modified_date); |
||||
RETURN NULL; |
||||
END; |
||||
$$ |
||||
LANGUAGE plpgsql; |
||||
ALTER FUNCTION history_scan_lvm_vgs() OWNER TO admin; |
||||
|
||||
CREATE TRIGGER trigger_scan_lvm_vgs |
||||
AFTER INSERT OR UPDATE ON scan_lvm_vgs |
||||
FOR EACH ROW EXECUTE PROCEDURE history_scan_lvm_vgs(); |
||||
|
||||
|
||||
--lvs - lv_name,lv_uuid,lv_attr,vg_name,lv_size,lv_path,devices |
||||
CREATE TABLE scan_lvm_lvs ( |
||||
scan_lvm_lv_uuid uuid primary key, -- This comes from the VG itself. |
||||
scan_lvm_lv_host_uuid uuid not null, |
||||
scan_lvm_lv_name text not null, -- This is the name of the VG. |
||||
scan_lvm_lv_attributes text not null, -- This is the short 10-character attribute of the LV |
||||
scan_lvm_lv_on_vg text not null, -- This is the name of the volume group this LV is on |
||||
scan_lvm_lv_size numeric not null, -- The size of the VG, in bytes. |
||||
scan_lvm_lv_free numeric not null, -- The free space in the VG, in bytes. |
||||
scan_lvm_lv_path text not null, -- The device path to this LV |
||||
scan_lvm_lv_on_pvs text not null, -- This is a comma-separated list of PVs this LV spans over. |
||||
modified_date timestamp with time zone not null, |
||||
|
||||
FOREIGN KEY(scan_lvm_lv_host_uuid) REFERENCES hosts(host_uuid) |
||||
); |
||||
ALTER TABLE scan_lvm_lvs OWNER TO admin; |
||||
|
||||
CREATE TABLE history.scan_lvm_lvs ( |
||||
history_id bigserial, |
||||
scan_lvm_lv_uuid uuid, |
||||
scan_lvm_lv_host_uuid uuid, |
||||
scan_lvm_lv_name text, |
||||
scan_lvm_lv_attributes text, |
||||
scan_lvm_lv_on_vg text, |
||||
scan_lvm_lv_size numeric, |
||||
scan_lvm_lv_free numeric, |
||||
scan_lvm_lv_path text, |
||||
scan_lvm_lv_on_pvs text, |
||||
modified_date timestamp with time zone not null |
||||
); |
||||
ALTER TABLE history.scan_lvm_lvs OWNER TO admin; |
||||
|
||||
CREATE FUNCTION history_scan_lvm_lvs() RETURNS trigger |
||||
AS $$ |
||||
DECLARE |
||||
history_scan_lvm_lvs RECORD; |
||||
BEGIN |
||||
SELECT INTO history_scan_lvm_lvs * FROM scan_lvm_lvs WHERE scan_lvm_lv_uuid=new.scan_lvm_lv_uuid; |
||||
INSERT INTO history.scan_lvm_lvs |
||||
(scan_lvm_lv_uuid, |
||||
scan_lvm_lv_host_uuid, |
||||
scan_lvm_lv_name, |
||||
scan_lvm_lv_attributes, |
||||
scan_lvm_lv_on_vg, |
||||
scan_lvm_lv_size, |
||||
scan_lvm_lv_free, |
||||
scan_lvm_lv_path, |
||||
scan_lvm_lv_on_pvs, |
||||
modified_date) |
||||
VALUES |
||||
(history_scan_lvm_lvs.scan_lvm_lv_uuid, |
||||
history_scan_lvm_lvs.scan_lvm_lv_host_uuid, |
||||
history_scan_lvm_lvs.scan_lvm_lv_name, |
||||
history_scan_lvm_lvs.scan_lvm_lv_attributes, |
||||
history_scan_lvm_lvs.scan_lvm_lv_on_vg, |
||||
history_scan_lvm_lvs.scan_lvm_lv_size, |
||||
history_scan_lvm_lvs.scan_lvm_lv_free, |
||||
history_scan_lvm_lvs.scan_lvm_lv_path, |
||||
history_scan_lvm_lvs.scan_lvm_lv_on_pvs, |
||||
history_scan_lvm_lvs.modified_date); |
||||
RETURN NULL; |
||||
END; |
||||
$$ |
||||
LANGUAGE plpgsql; |
||||
ALTER FUNCTION history_scan_lvm_lvs() OWNER TO admin; |
||||
|
||||
CREATE TRIGGER trigger_scan_lvm_lvs |
||||
AFTER INSERT OR UPDATE ON scan_lvm_lvs |
||||
FOR EACH ROW EXECUTE PROCEDURE history_scan_lvm_lvs(); |
||||
|
||||
|
@ -0,0 +1,29 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
||||
<!-- |
||||
Company: Alteeve's Niche, Inc. |
||||
License: GPL v2+ |
||||
Author: Madison Kelly <mkelly@alteeve.ca> |
||||
|
||||
NOTE: All string keys MUST be prefixed with the agent name! ie: 'scan_lvm_log_0001'. |
||||
--> |
||||
|
||||
<words> |
||||
<meta version="3.0.0" languages="en_CA,jp"/> |
||||
<!-- Canadian English --> |
||||
<language name="en_CA" long_name="Canadian English" description="ScanCore scan agent that monitors hardware, like RAM modules, CSS LED status, CPU information, etc."> |
||||
|
||||
<!-- Alert entries --> |
||||
<key name="scan_lvm_alert_0001"></key> |
||||
|
||||
<!-- Log entries --> |
||||
<key name="scan_lvm_log_0001">Starting: [#!variable!program!#].</key> |
||||
|
||||
<!-- Message entries (usually meant to be alerts) --> |
||||
<key name="scan_lvm_message_0001"></key> |
||||
|
||||
<!-- Units --> |
||||
<key name="scan_lvm_unit_0001"></key> |
||||
|
||||
</language> |
||||
</words> |
@ -1,100 +0,0 @@ |
||||
#!/usr/bin/perl |
||||
# |
||||
# This scans the storage seen by the OS. That is to say, it monitors DRBD, LVM and backing devices. It does |
||||
# NOT monitor mdadm arrays, nor vendor-specific storage hardware. There should be dedicated scan agents for |
||||
# those tasks. |
||||
# |
||||
# Examples; |
||||
# |
||||
# Exit codes; |
||||
# 0 = Normal exit. |
||||
# 1 = Startup failure (not running as root, no DB, bad file read, etc) |
||||
# |
||||
# TODO: |
||||
# - |
||||
# |
||||
|
||||
use strict; |
||||
use warnings; |
||||
use Anvil::Tools; |
||||
use Data::Dumper; |
||||
|
||||
# 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({log_level => 2, log_secure => 1}); |
||||
$anvil->Log->level({set => 2}); |
||||
$anvil->Log->secure({set => 1}); |
||||
|
||||
# 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-storage'}{disable} = 0; |
||||
$anvil->data->{switches}{force} = 0; |
||||
|
||||
$anvil->Storage->read_config(); |
||||
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0115", variables => { program => $THIS_FILE }}); |
||||
|
||||
# Read switches |
||||
$anvil->Get->switches; |
||||
|
||||
# If we're disabled and '--force' wasn't used, exit. |
||||
if (($anvil->data->{scancore}{'scan-storage'}{disable}) && (not $anvil->data->{switches}{force})) |
||||
{ |
||||
# Exit. |
||||
$anvil->nice_exit({exit_code => 0}); |
||||
} |
||||
|
||||
# These are the tables used by this agent. The order matters as it controls to order the tables are created |
||||
# and sync'ed. For purges, this array is walked backwards. |
||||
$anvil->data->{scancore}{'scan-storage'}{tables} = ["scan_storage", "scan_storage_ram_modules"]; |
||||
|
||||
# Handle start-up tasks |
||||
my $problem = $anvil->ScanCore->agent_startup({ |
||||
debug => 3, |
||||
agent => $THIS_FILE, |
||||
tables => $anvil->data->{scancore}{'scan-storage'}{tables}, |
||||
}); |
||||
if ($problem) |
||||
{ |
||||
$anvil->nice_exit({exit_code => 1}); |
||||
} |
||||
|
||||
if ($anvil->data->{switches}{purge}) |
||||
{ |
||||
# This can be called when doing bulk-database purges. |
||||
$anvil->Database->purge_data({ |
||||
debug => 2, |
||||
tables => $anvil->data->{scancore}{'scan-storage'}{tables}, |
||||
}); |
||||
$anvil->nice_exit({exit_code => 0}); |
||||
} |
||||
|
||||
|
||||
# Mark that we ran. |
||||
$anvil->Database->insert_or_update_updated({updated_by => $THIS_FILE}); |
||||
|
||||
$anvil->nice_exit({exit_code => 0}); |
||||
|
||||
############################################################################################################# |
||||
# Functions # |
||||
############################################################################################################# |
||||
|
@ -1,42 +0,0 @@ |
||||
-- This is the database schema for the 'scan-storage Scan Agent'. |
||||
|
||||
CREATE TABLE scan_storage ( |
||||
scan_storage_uuid uuid primary key, |
||||
scan_storage_host_uuid uuid not null, |
||||
modified_date timestamp with time zone not null, |
||||
|
||||
FOREIGN KEY(scan_storage_host_uuid) REFERENCES hosts(host_uuid) |
||||
); |
||||
ALTER TABLE scan_storage OWNER TO admin; |
||||
|
||||
CREATE TABLE history.scan_storage ( |
||||
history_id bigserial, |
||||
scan_storage_uuid uuid, |
||||
scan_storage_host_uuid uuid, |
||||
modified_date timestamp with time zone not null |
||||
); |
||||
ALTER TABLE history.scan_storage OWNER TO admin; |
||||
|
||||
CREATE FUNCTION history_scan_storage() RETURNS trigger |
||||
AS $$ |
||||
DECLARE |
||||
history_scan_storage RECORD; |
||||
BEGIN |
||||
SELECT INTO history_scan_storage * FROM scan_storage WHERE scan_storage_uuid=new.scan_storage_uuid; |
||||
INSERT INTO history.scan_storage |
||||
(scan_storage_uuid, |
||||
scan_storage_host_uuid, |
||||
modified_date) |
||||
VALUES |
||||
(history_scan_storage.scan_storage_uuid, |
||||
history_scan_storage.scan_storage_host_uuid, |
||||
history_scan_storage.modified_date); |
||||
RETURN NULL; |
||||
END; |
||||
$$ |
||||
LANGUAGE plpgsql; |
||||
ALTER FUNCTION history_scan_storage() OWNER TO admin; |
||||
|
||||
CREATE TRIGGER trigger_scan_storage |
||||
AFTER INSERT OR UPDATE ON scan_storage |
||||
FOR EACH ROW EXECUTE PROCEDURE history_scan_storage(); |
Loading…
Reference in new issue