diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 89b09c36..dfcb4556 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1120,6 +1120,7 @@ sub _set_paths crm_error => "/usr/sbin/crm_error", crm_resource => "/usr/sbin/crm_resource", crm_mon => "/usr/sbin/crm_mon", + df => "/usr/bin/df", dmidecode => "/usr/sbin/dmidecode", dnf => "/usr/bin/dnf", drbdadm => "/usr/sbin/drbdadm", @@ -1147,8 +1148,9 @@ sub _set_paths journalctl => "/usr/bin/journalctl", logger => "/usr/bin/logger", ls => "/usr/bin/ls", - lspci => "/usr/sbin/lspci", lsblk => "/usr/bin/lsblk", + lshw => "/usr/sbin/lshw", + lspci => "/usr/sbin/lspci", lvchange => "/usr/sbin/lvchange", lvcreate => "/usr/sbin/lvcreate", lvremove => "/usr/sbin/lvremove", diff --git a/Anvil/Tools/Cluster.pm b/Anvil/Tools/Cluster.pm index 5e3a5477..c6dc5651 100644 --- a/Anvil/Tools/Cluster.pm +++ b/Anvil/Tools/Cluster.pm @@ -273,8 +273,16 @@ sub assemble_storage_groups if (not $anvil_uuid) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Cluster->assemble_storage_groups()", parameter => "anvil_uuid" }}); - return("!!error!!"); + # Can we deduce the anvil_uuid? + $anvil_uuid = $anvil->Cluster->get_anvil_uuid({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_uuid=> $anvil_uuid }}); + + if (not $anvil_uuid) + { + # Still no anvil_uuid + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Cluster->assemble_storage_groups()", parameter => "anvil_uuid" }}); + return("!!error!!"); + } } # Get the node UUIDs for this anvil. @@ -372,7 +380,8 @@ ORDER BY # only. my $storage_group_uuid = $anvil->data->{storage_groups}{vg_uuid}{$scan_lvm_vg_internal_uuid}{storage_group_uuid}; my $group_name = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{group_name}; - my $storage_group_member_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_uuid}{$scan_lvm_vg_internal_uuid}{storage_group_member_uuid}; + #my $storage_group_member_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_uuid}{$scan_lvm_vg_internal_uuid}{storage_group_member_uuid}; + my $storage_group_member_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{storage_group_member_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_uuid => $anvil_uuid, host_uuid => $host_uuid, @@ -434,6 +443,7 @@ ORDER BY storage_group_member_host_uuid => $host_uuid, storage_group_member_vg_uuid => $storage_group_member_vg_uuid, }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_member_uuid => $storage_group_member_uuid }}); $anvil->data->{ungrouped_vg_count}{$this_is}--; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { diff --git a/Anvil/Tools/Convert.pm b/Anvil/Tools/Convert.pm index c59464cf..2db207f6 100644 --- a/Anvil/Tools/Convert.pm +++ b/Anvil/Tools/Convert.pm @@ -204,9 +204,9 @@ sub bytes_to_human_readable my $unit = defined $parameter->{unit} ? uc($parameter->{unit}) : ""; my $base2 = defined $parameter->{base2} ? $parameter->{base2} : $anvil->data->{sys}{use_base2}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - base2 => $base2, - 'bytes' => $bytes, - unit => $unit, + base2 => $base2, + 'bytes' => $bytes, + unit => $unit, }}); # Expand exponential numbers. @@ -1044,14 +1044,24 @@ sub human_readable_to_bytes # If the "type" is "Xib" or if '$base2' is set, make sure we're running in Base2 notation. Conversly, # if the type is "Xb" or if '$base10' is set, make sure that we're running in Base10 notation. In # either case, shorten the 'type' to just the first letter to make the next sanity check simpler. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + base2 => $base2, + base10 => $base10, + }}); if ((not $base2) && (not $base10)) { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { type => $type }}); if ($type =~ /^(\w)ib$/) { # Make sure we're running in Base2. $type = $1; $base2 = 1; $base10 = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + type => $type, + base2 => $base2, + base10 => $base10, + }}); } elsif ($type =~ /^(\w)b$/) { @@ -1059,6 +1069,22 @@ sub human_readable_to_bytes $type = $1; $base2 = 0; $base10 = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + type => $type, + base2 => $base2, + base10 => $base10, + }}); + } + elsif ($type =~ /^b/) + { + $type = "b"; + $base2 = 1; + $base10 = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + type => $type, + base2 => $base2, + base10 => $base10, + }}); } } @@ -1070,11 +1096,12 @@ sub human_readable_to_bytes if (($type ne "p") && ($type ne "e") && ($type ne "z") && - ($type eq "y") && + ($type ne "y") && ($type ne "t") && ($type ne "g") && ($type ne "m") && - ($type ne "k")) + ($type ne "k") && + ($type ne "b")) { # Poop $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0119", variables => { @@ -1098,6 +1125,7 @@ sub human_readable_to_bytes elsif ($type eq "g") { $bytes = ($size * (10 ** 9)) } # Gigabyte elsif ($type eq "m") { $bytes = ($size * (10 ** 6)) } # Megabyte elsif ($type eq "k") { $bytes = ($size * (10 ** 3)) } # Kilobyte + elsif ($type eq "b") { $bytes = $size; } # bytes $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'bytes' => $bytes }}); } else @@ -1110,6 +1138,7 @@ sub human_readable_to_bytes elsif ($type eq "g") { $bytes = ($size * (2 ** 30)) } # Gibibyte elsif ($type eq "m") { $bytes = ($size * (2 ** 20)) } # Mebibyte elsif ($type eq "k") { $bytes = ($size * (2 ** 10)) } # Kibibyte + elsif ($type eq "b") { $bytes = $size; } # bytes $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'bytes' => $bytes }}); } diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index b7e80993..9b126a1f 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -2015,7 +2015,7 @@ WHERE $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node2_host_uuid} = $anvil_node2_host_uuid; $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_dr1_host_uuid} = $anvil_dr1_host_uuid; $anvil->data->{anvils}{anvil_name}{$anvil_name}{modified_date} = $modified_date; - $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{query_time} = time; + $anvil->data->{anvils}{anvil_name}{$anvil_uuid}{query_time} = time; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "anvils::anvil_name::${anvil_name}::anvil_uuid" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid}, "anvils::anvil_name::${anvil_name}::anvil_description" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description}, @@ -4219,7 +4219,7 @@ ORDER BY my $storage_group_name = $row->[2]; my $storage_group_member_uuid = $row->[3]; my $storage_group_member_host_uuid = $row->[4]; - my $storage_group_member_vg_uuid = $row->[5]; + my $storage_group_member_vg_uuid = $row->[5]; # This is the VG's internal UUID $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_uuid => $storage_group_uuid, storage_group_anvil_uuid => $storage_group_anvil_uuid, @@ -4423,6 +4423,14 @@ sub get_tables_from_schema } } + # Store the tables in 'sys::database::check_tables' + $anvil->data->{sys}{database}{check_tables} = $tables; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + tables => $tables, + 'sys::database::check_tables' => $anvil->data->{sys}{database}{check_tables}, + }}); + + my $table_count = @{$tables}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { table_count => $table_count }}); @@ -11644,7 +11652,9 @@ SELECT FROM storage_group_members WHERE - storage_group_member_vg_uuid = ".$anvil->Database->quote($storage_group_member_vg_uuid)." + storage_group_member_vg_uuid = ".$anvil->Database->quote($storage_group_member_vg_uuid)." +AND + storage_group_member_host_uuid = ".$anvil->Database->quote($storage_group_member_host_uuid)." ;"; my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); my $count = @{$results}; @@ -14472,8 +14482,6 @@ sub resync_databases return(0); } - #$anvil->data->{sys}{database}{log_transactions} = 1; - # Archive old data before resync'ing $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0451"}); $anvil->Database->archive_database({debug => $debug}); @@ -15496,7 +15504,7 @@ sub _find_behind_databases ### NOTE: Don't sort this! Tables need to be resynced in a specific order! # Loop through and resync the tables. - foreach my $table (@{$tables}) + foreach my $table (@{$tables}) { # Record the table in 'sys::database::check_tables' array for later use in archive and # resync methods. @@ -15542,16 +15550,43 @@ sub _find_behind_databases if ($count == 1) { - # Does this table have a '*_host_uuid' column? - my $query = "SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND column_name LIKE '\%_host_uuid' AND table_name = ".$anvil->Database->quote($table).";"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - - # See if there is a column that ends in '_host_uuid'. If there is, we'll use - # it later to restrict resync activity to these columns with the local - # 'sys::host_uuid'. - my $host_column = $anvil->Database->query({debug => $debug, uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; - $host_column = "" if not defined $host_column; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_column => $host_column }}); + # Some tables, like 'servers', has a host_uuid column, but it's not used to + # restrict data to a host, but instead show which host a movable resource is + # on. This prevents us from using the column by accident. + my $host_column = ""; + if (($table ne "servers") && + ($table ne "jobs")) + { + # Does this table have a '*_host_uuid' column? + my $test_columns = [$table."_host_uuid"]; + if ($table =~ /^(.*)s$/) + { + push @{$test_columns}, $1."_host_uuid"; + } + if ($table =~ /^(.*)es$/) + { + push @{$test_columns}, $1."_host_uuid"; + } + + foreach my $test_column (@{$test_columns}) + { + my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND column_name = ".$anvil->Database->quote($test_column)." AND table_name = ".$anvil->Database->quote($table).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); + + # See if there is a column that ends in '_host_uuid'. If there is, we'll use + # it later to restrict resync activity to these columns with the local + # 'sys::host_uuid'. + my $count = $anvil->Database->query({debug => $debug, uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }}); + + if ($count) + { + $host_column = $test_column; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_column => $host_column }}); + last; + } + } + } # Does this table have a history schema version? $query = "SELECT COUNT(*) FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema = 'history' AND table_name = ".$anvil->Database->quote($table).";"; diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index af29567c..ba5c488b 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -132,8 +132,14 @@ sub anvil_name_from_uuid if (not $anvil_uuid) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Get->anvil_name_from_uuid()", parameter => "server_name" }}); - return("!!error!!"); + $anvil_uuid = $anvil->Cluster->get_anvil_uuid({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_uuid => $anvil_uuid }}); + + if (not $anvil_uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Get->anvil_name_from_uuid()", parameter => "server_name" }}); + return("!!error!!"); + } } my $query = " @@ -423,8 +429,14 @@ sub available_resources if (not $anvil_uuid) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Get->available_resources()", parameter => "anvil_uuid" }}); - return("!!error!!"); + $anvil_uuid = $anvil->Cluster->get_anvil_uuid({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_uuid => $anvil_uuid }}); + + if (not $anvil_uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Get->available_resources()", parameter => "anvil_uuid" }}); + return("!!error!!"); + } } if (exists $anvil->data->{anvil_resources}{$anvil_uuid}) diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index 555123b3..5430623f 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -6,9 +6,10 @@ package Anvil::Tools::Storage; use strict; use warnings; use Data::Dumper; +use File::MimeInfo; +use JSON; use Scalar::Util qw(weaken isweak); use Text::Diff; -use File::MimeInfo; use utf8; our $VERSION = "3.0.0"; @@ -25,6 +26,7 @@ my $THIS_FILE = "Storage.pm"; # get_storage_group_details # make_directory # move_file +# parse_df # parse_lsblk # read_config # read_file @@ -2031,32 +2033,98 @@ fi"; } -=head2 parse_lsblk - -This calls C<< lsblk >> (in json format) and parses the output. Data is stored as: - - * lsblk::::... - -Parameters; +=head2 parse_df -=head3 password (optional) +This calls C<< df >> and parses the output. Data is stored as: -If C<< target >> is set, this is the password used to log into the remote system as the C<< remote_user >>. If it is not set, an attempt to connect without a password will be made.. + * storage::df::::... -=head3 port (optional, default 22) +This method takes no parameters. -If C<< target >> is set, this is the TCP port number used to connect to the remote machine. - -=head3 remote_user (optional) +=cut +sub parse_df +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Storage->parse_df()" }}); + + my $shell_call = $anvil->data->{path}{exe}{df}." --exclude-type=tmpfs --exclude-type=devtmpfs --no-sync --block-size=1 --output=source,fstype,size,used,avail,target"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + if ($return_code) + { + # Failed. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "warning_0079", variables => { + return_code => $return_code, + output => $output, + }}); + return(1); + } + + foreach my $line (split/\n/, $output) + { + if ($line =~ /^\/dev\/(.*?)\s+(.*?)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\/.*)$/) + { + my $kernel_device_name = $1; + my $filesystem_type = $2; + my $size = $3; + my $used = $4; + my $free = $5; + my $mount_point = $6; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:kernel_device_name' => $kernel_device_name, + 's2:mount_point' => $mount_point, + 's3:filesystem_type' => $filesystem_type, + 's4:size' => $anvil->Convert->add_commas({number => $size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $size}).")", + 's5:used' => $anvil->Convert->add_commas({number => $used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $used}).")", + 's6:free' => $anvil->Convert->add_commas({number => $free})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $free}).")", + }}); + + # If the line starts with 'mapper', we need to figure out what dm-X device it is. + if ($kernel_device_name =~ /^mapper\//) + { + # Use lstat + my $device_path = "/dev/".$kernel_device_name; + my $device_mapper = readlink($device_path); + if ($device_mapper =~ /^\.\.\/(.*)$/) + { + $kernel_device_name = $1; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + device_path => $device_path, + kernel_device_name => $kernel_device_name, + }}); + } + + $anvil->{storage}{df}{$kernel_device_name}{filesystem_type} = $filesystem_type; + $anvil->{storage}{df}{$kernel_device_name}{mount_point} = $mount_point; + $anvil->{storage}{df}{$kernel_device_name}{size} = $size; + $anvil->{storage}{df}{$kernel_device_name}{used} = $used; + $anvil->{storage}{df}{$kernel_device_name}{free} = $free; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "storage::df::${kernel_device_name}::filesystem_type" => $anvil->{storage}{df}{$kernel_device_name}{filesystem_type}, + "storage::df::${kernel_device_name}::mount_point" => $anvil->{storage}{df}{$kernel_device_name}{mount_point}, + "storage::df::${kernel_device_name}::size" => $anvil->Convert->add_commas({number => $anvil->{storage}{df}{$kernel_device_name}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->{storage}{df}{$kernel_device_name}{size}}).")", + "storage::df::${kernel_device_name}::used" => $anvil->Convert->add_commas({number => $anvil->{storage}{df}{$kernel_device_name}{used}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->{storage}{df}{$kernel_device_name}{used}}).")", + "storage::df::${kernel_device_name}::free" => $anvil->Convert->add_commas({number => $anvil->{storage}{df}{$kernel_device_name}{free}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->{storage}{df}{$kernel_device_name}{free}}).")", + }}); + } + } + + return(0); +} -If C<< target >> is set, this is the user account that will be used when connecting to the remote system. -=head3 target (optional) +=head2 parse_lsblk -If set, C<< lsblk >> read from the target machine. This must be either an IP address or a resolvable host name. +This calls C<< lsblk >> (in json format) and parses the output. Data is stored as: -B<< Note >>: If not set, the short host name of this system is used in C<< lsblk::::: >>. + * storage::lsblk::::... +This method takes no parameters. =cut sub parse_lsblk { @@ -2066,21 +2134,159 @@ sub parse_lsblk my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Storage->parse_lsblk()" }}); - # Setup default values - my $password = defined $parameter->{password} ? $parameter->{password} : ""; - my $port = defined $parameter->{port} ? $parameter->{port} : 22; - my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root"; - my $target = defined $parameter->{target} ? $parameter->{target} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - password => $anvil->Log->is_secure($password), - port => $port, - remote_user => $remote_user, - target => $target, - }}); + my $shell_call = $anvil->data->{path}{exe}{lsblk}." --output KNAME,FSTYPE,MOUNTPOINT,UUID,PARTLABEL,PARTUUID,RO,RM,HOTPLUG,MODEL,SERIAL,SIZE,STATE,ALIGNMENT,PHY-SEC,LOG-SEC,ROTA,SCHED,TYPE,TRAN,VENDOR --bytes --json"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); - my $shell_call = $anvil->data->{path}{exe}{lsblk}." --all --bytes --json"; - + my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + if ($return_code) + { + # Failed. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "warning_0079", variables => { + return_code => $return_code, + output => $output, + }}); + return(1); + } + + my $json = JSON->new->allow_nonref; + my $data = $json->decode($output); + + foreach my $hash_ref (@{$data->{blockdevices}}) + { + my $kernel_device_name = $hash_ref->{kname}; + #next if $kernel_device_name =~ /^dm-/; + #next if $kernel_device_name =~ /^mmcblk/; # Add support for this later when 'System->parse_lshw' is done + $anvil->{storage}{lsblk}{$kernel_device_name}{alignment_offset} = defined $hash_ref->{alignment} ? $hash_ref->{alignment} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{device_type} = defined $hash_ref->{type} ? $hash_ref->{type} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{filesystem_type} = defined $hash_ref->{fstype} ? $hash_ref->{fstype} : ""; + # This is the LVM formatted UUID, when it's an 'LVM2_member', so it should be easy to cross + # reference with: scan_lvm_lvs -> scan_lvm_lv_internal_uuid to map the LVs to a PV + $anvil->{storage}{lsblk}{$kernel_device_name}{filesystem_uuid} = defined $hash_ref->{uuid} ? $hash_ref->{uuid} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{hot_plug} = defined $hash_ref->{hotplug} ? $hash_ref->{hotplug} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{logical_sector_size} = defined $hash_ref->{'log-sec'} ? $hash_ref->{'log-sec'} : 0; + $anvil->{storage}{lsblk}{$kernel_device_name}{model} = defined $hash_ref->{model} ? $hash_ref->{model} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{model} = $anvil->Words->clean_spaces({string => $anvil->{storage}{lsblk}{$kernel_device_name}{model}}); + $anvil->{storage}{lsblk}{$kernel_device_name}{mount_point} = defined $hash_ref->{mountpoint} ? $hash_ref->{mountpoint} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{partition_label} = defined $hash_ref->{partlabel} ? $hash_ref->{partlabel} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{partition_uuid} = defined $hash_ref->{partuuid} ? $hash_ref->{partuuid} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{physical_sector_size} = defined $hash_ref->{'phy-sec'} ? $hash_ref->{'phy-sec'} : 0; + $anvil->{storage}{lsblk}{$kernel_device_name}{read_only} = defined $hash_ref->{ro} ? $hash_ref->{ro} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{removable} = defined $hash_ref->{rm} ? $hash_ref->{rm} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{rotating_drive} = defined $hash_ref->{rota} ? $hash_ref->{rota} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{serial_number} = defined $hash_ref->{serial} ? $hash_ref->{serial} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{serial_number} = $anvil->Words->clean_spaces({string => $anvil->{storage}{lsblk}{$kernel_device_name}{serial_number}}); + $anvil->{storage}{lsblk}{$kernel_device_name}{scheduler} = defined $hash_ref->{sched} ? $hash_ref->{sched} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{size} = defined $hash_ref->{size} ? $hash_ref->{size} : 0; + $anvil->{storage}{lsblk}{$kernel_device_name}{'state'} = defined $hash_ref->{'state'} ? $hash_ref->{'state'} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{transport} = defined $hash_ref->{tran} ? $hash_ref->{tran} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{type} = $anvil->{storage}{lsblk}{$kernel_device_name}{filesystem_uuid} ? "partition" : "drive"; + $anvil->{storage}{lsblk}{$kernel_device_name}{vendor} = defined $hash_ref->{vendor} ? $hash_ref->{vendor} : ""; + $anvil->{storage}{lsblk}{$kernel_device_name}{vendor} = $anvil->Words->clean_spaces({string => $anvil->{storage}{lsblk}{$kernel_device_name}{vendor}}); + + # There's precious little data that comes from SD cards. + if ($kernel_device_name =~ /^mmcblk/) + { + if ($kernel_device_name =~ /^mmcblk\d+p\d+/) + { + # This is a partition + $anvil->{storage}{lsblk}{$kernel_device_name}{filesystem_type} = "partition"; + $anvil->{storage}{lsblk}{$kernel_device_name}{model} = "SD Card" if not $anvil->{storage}{lsblk}{$kernel_device_name}{model}; + $anvil->{storage}{lsblk}{$kernel_device_name}{transport} = "pci" if not $anvil->{storage}{lsblk}{$kernel_device_name}{transport}; + $anvil->{storage}{lsblk}{$kernel_device_name}{type} = "ssd" if not $anvil->{storage}{lsblk}{$kernel_device_name}{type}; + $anvil->{storage}{lsblk}{$kernel_device_name}{vendor} = "unknown" if not $anvil->{storage}{lsblk}{$kernel_device_name}{vendor}; + } + else + { + # It's the drive + $anvil->{storage}{lsblk}{$kernel_device_name}{filesystem_type} = "drive"; + } + } + # Later, we'll want to trace device mapper devices back to the real device behind them (being + # LVM, crypt, etc). For now, this works. + if ($kernel_device_name =~ /^dm-/) + { + $anvil->{storage}{lsblk}{$kernel_device_name}{filesystem_type} = "partition"; + $anvil->{storage}{lsblk}{$kernel_device_name}{model} = "Device Mapper" if not $anvil->{storage}{lsblk}{$kernel_device_name}{model}; + $anvil->{storage}{lsblk}{$kernel_device_name}{transport} = "virtual" if not $anvil->{storage}{lsblk}{$kernel_device_name}{transport}; + $anvil->{storage}{lsblk}{$kernel_device_name}{type} = "virtual" if not $anvil->{storage}{lsblk}{$kernel_device_name}{type}; + $anvil->{storage}{lsblk}{$kernel_device_name}{vendor} = "Linux" if not $anvil->{storage}{lsblk}{$kernel_device_name}{vendor}; + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "storage::lsblk::${kernel_device_name}::alignment_offset" => $anvil->{storage}{lsblk}{$kernel_device_name}{alignment_offset}, + "storage::lsblk::${kernel_device_name}::device_type" => $anvil->{storage}{lsblk}{$kernel_device_name}{device_type}, + "storage::lsblk::${kernel_device_name}::filesystem_type" => $anvil->{storage}{lsblk}{$kernel_device_name}{filesystem_type}, + "storage::lsblk::${kernel_device_name}::filesystem_uuid" => $anvil->{storage}{lsblk}{$kernel_device_name}{filesystem_uuid}, + "storage::lsblk::${kernel_device_name}::hot_plug" => $anvil->{storage}{lsblk}{$kernel_device_name}{hot_plug}, + "storage::lsblk::${kernel_device_name}::logical_sector_size" => $anvil->{storage}{lsblk}{$kernel_device_name}{logical_sector_size}, + "storage::lsblk::${kernel_device_name}::model" => $anvil->{storage}{lsblk}{$kernel_device_name}{model}, + "storage::lsblk::${kernel_device_name}::mount_point" => $anvil->{storage}{lsblk}{$kernel_device_name}{mount_point}, + "storage::lsblk::${kernel_device_name}::partition_label" => $anvil->{storage}{lsblk}{$kernel_device_name}{partition_label}, + "storage::lsblk::${kernel_device_name}::partition_uuid" => $anvil->{storage}{lsblk}{$kernel_device_name}{partition_uuid}, + "storage::lsblk::${kernel_device_name}::physical_sector_size" => $anvil->{storage}{lsblk}{$kernel_device_name}{physical_sector_size}, + "storage::lsblk::${kernel_device_name}::read_only" => $anvil->{storage}{lsblk}{$kernel_device_name}{read_only}, + "storage::lsblk::${kernel_device_name}::removable" => $anvil->{storage}{lsblk}{$kernel_device_name}{removable}, + "storage::lsblk::${kernel_device_name}::rotating_drive" => $anvil->{storage}{lsblk}{$kernel_device_name}{rotating_drive}, + "storage::lsblk::${kernel_device_name}::serial_number" => $anvil->{storage}{lsblk}{$kernel_device_name}{serial_number}, + "storage::lsblk::${kernel_device_name}::scheduler" => $anvil->{storage}{lsblk}{$kernel_device_name}{scheduler}, + "storage::lsblk::${kernel_device_name}::size" => $anvil->Convert->add_commas({number => $anvil->{storage}{lsblk}{$kernel_device_name}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->{storage}{lsblk}{$kernel_device_name}{size}}).")", + "storage::lsblk::${kernel_device_name}::state" => $anvil->{storage}{lsblk}{$kernel_device_name}{'state'}, + "storage::lsblk::${kernel_device_name}::type" => $anvil->{storage}{lsblk}{$kernel_device_name}{type}, + "storage::lsblk::${kernel_device_name}::transport" => $anvil->{storage}{lsblk}{$kernel_device_name}{transport}, + "storage::lsblk::${kernel_device_name}::vendor" => $anvil->{storage}{lsblk}{$kernel_device_name}{vendor}, + }}); + } + # Now loop through devices and pass parent information (like transport, model, etc) from devices down to partitions. + my $parent_device = ""; + foreach my $kernel_device_name (sort {$a cmp $b} keys %{$anvil->{storage}{lsblk}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { kernel_device_name => $kernel_device_name }}); + + if ($anvil->{storage}{lsblk}{$kernel_device_name}{type} eq "drive") + { + $parent_device = $kernel_device_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { parent_device => $parent_device }}); + next; + } + + if (($parent_device) && (not $anvil->{storage}{lsblk}{$kernel_device_name}{model})) + { + $anvil->{storage}{lsblk}{$kernel_device_name}{model} = $anvil->{storage}{lsblk}{$parent_device}{model}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "storage::lsblk::${kernel_device_name}::model" => $anvil->{storage}{lsblk}{$kernel_device_name}{model}, + }}); + } + if (($parent_device) && (not $anvil->{storage}{lsblk}{$kernel_device_name}{serial_number})) + { + $anvil->{storage}{lsblk}{$kernel_device_name}{serial_number} = $anvil->{storage}{lsblk}{$parent_device}{serial_number}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "storage::lsblk::${kernel_device_name}::serial_number" => $anvil->{storage}{lsblk}{$kernel_device_name}{serial_number}, + }}); + } + if (($parent_device) && (not $anvil->{storage}{lsblk}{$kernel_device_name}{vendor})) + { + $anvil->{storage}{lsblk}{$kernel_device_name}{vendor} = $anvil->{storage}{lsblk}{$parent_device}{vendor}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "storage::lsblk::${kernel_device_name}::vendor" => $anvil->{storage}{lsblk}{$kernel_device_name}{vendor}, + }}); + } + if (($parent_device) && (not $anvil->{storage}{lsblk}{$kernel_device_name}{transport})) + { + $anvil->{storage}{lsblk}{$kernel_device_name}{transport} = $anvil->{storage}{lsblk}{$parent_device}{transport}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "storage::lsblk::${kernel_device_name}::transport" => $anvil->{storage}{lsblk}{$kernel_device_name}{transport}, + }}); + } + if (($parent_device) && (not $anvil->{storage}{lsblk}{$kernel_device_name}{'state'})) + { + $anvil->{storage}{lsblk}{$kernel_device_name}{'state'} = $anvil->{storage}{lsblk}{$parent_device}{'state'}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "storage::lsblk::${kernel_device_name}::state" => $anvil->{storage}{lsblk}{$kernel_device_name}{'state'}, + }}); + } + } + return(0); } diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index 961445b1..8c51e3fa 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -36,6 +36,7 @@ my $THIS_FILE = "System.pm"; # maintenance_mode # manage_authorized_keys # manage_firewall +# parse_lshw # read_ssh_config # reload_daemon # reboot_needed @@ -3806,6 +3807,151 @@ sub parse_arguments return($hash); } + +=head2 parse_lshw + +B<< NOTE >>: This method is not complete, do not use it yet! + +This calls C<< lshw >> (in XML format) and parses the output. Data is stored as: + + * lshw::... + +Parameters; + +=head3 xml (optional) + +If set, the passed-in XML is parsed and C<< lshw -xml >> is not called. This should only be used for testing / debugging. + +=cut +sub parse_lshw +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->parse_lsblk()" }}); + + my $xml = defined $parameter->{xml} ? $parameter->{xml} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { xml => $xml }}); + + if (not $xml) + { + my $shell_call = $anvil->data->{path}{exe}{lshw}." -xml"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + + ($xml, my $return_code) = $anvil->System->call({shell_call => $shell_call}); + if ($return_code) + { + # Failed. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "warning_0080", variables => { + return_code => $return_code, + output => $xml, + }}); + return(1); + } + } + + local $@; + my $dom = eval { XML::LibXML->load_xml(string => $xml); }; + if ($@) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "warning_0053", variables => { + cib => $xml, + error => $@, + }}); + } + + foreach my $node ($dom->findnodes('/list/node')) + { + my $id = $node->{id}; + my $class = $node->{class}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + id => $id, + class => $class, + }}); + } +=cut + foreach my $node ($dom->findnodes('/list/node')) + { + my $id = $node->{id}; + my $class = $node->{class}; + my $handle = $node->{handle}; + my $parent_description = defined $node->findvalue('./description') ? $node->findvalue('./description') : ""; + my $logical_name = defined $node->findvalue('./logicalname') ? $node->findvalue('./logicalname') : ""; + my $parent_vendor = defined $node->findvalue('./vendor') ? $node->findvalue('./vendor') : ""; + my $parent_model = defined $node->findvalue('./product') ? $node->findvalue('./product') : ""; + my $parent_serial_number = defined $node->findvalue('./serial') ? $node->findvalue('./serial') : ""; + my $parent_media = $id; + if ($id eq "device") + { + if (($parent_description =~ /sd card/i) or ($logical_name =~ /\/dev\/mmcblk/)) + { + $parent_media = "sdcard"; + } + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + id => $id, + class => $class, + logical_name => $logical_name, + parent_vendor => $parent_vendor, + parent_model => $parent_model, + }}); + # Sub devices may not appear, so we'll later match logical names (when they're a path) to devices in 'df' later. + foreach my $device ($node->findnodes('./node')) + { + my $dev_id = $device->{id}; + my $dev_class = $device->{class}; + my $bus_info = defined $device->findvalue('./businfo') ? $device->findvalue('./businfo') : ""; + my $path = defined $device->findvalue('./logicalname') ? $device->findvalue('./logicalname') : ""; + my $description = defined $device->findvalue('./description') ? $device->findvalue('./description') : ""; + my $vendor = defined $device->findvalue('./vendor') ? $device->findvalue('./vendor') : ""; + $vendor = $parent_vendor if not $vendor; + my $model = defined $device->findvalue('./product') ? $device->findvalue('./product') : ""; + $model = $parent_model if not $model; + my $serial_number = defined $device->findvalue('./serial') ? $device->findvalue('./serial') : ""; + $serial_number = $parent_serial_number if not $serial_number; + my $size_number = defined $device->findvalue('./size') ? $device->findvalue('./size') : ""; + $size_number = 0 if not $size_number; + my ($size_dom) = $device->findnodes('./size'); + my $size_units = $size_dom->{units}; + $size_units = "bytes" if not $size_units; + my $size_in_bytes = $anvil->Convert->human_readable_to_bytes({size => $size_number, type => $size_units}); + my $media = $dev_id; + if (($bus_info =~ /nvme/i) or ($path =~ /\/dev\/nvm/)) + { + $bus_info = "nvme"; + $media = "ssd"; + } + if ($dev_id eq "cdrom") + { + $media = "optical"; + } + if (($bus_info =~ /^scsi/) or ($description =~ /ATA Disk/i)) + { + # Call + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + dev_id => $dev_id, + dev_class => $dev_class, + bus_info => $bus_info, + path => $path, + description => $description, + vendor => $vendor, + model => $model, + serial_number => $serial_number, + size_number => $size_number, + size_units => $size_units, + size_in_bytes => $anvil->Convert->add_commas({number => $size_in_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $size_in_bytes}), + media => $media, + }}); + } + } +=cut + + return(0); +} + + =head2 read_ssh_config This reads /etc/ssh/ssh_config and notes hosts with defined ports. When found, the associated port will be automatically used for a given host name or IP address. diff --git a/cgi-bin/Makefile.am b/cgi-bin/Makefile.am index 33cd0e86..306463f0 100644 --- a/cgi-bin/Makefile.am +++ b/cgi-bin/Makefile.am @@ -1,9 +1,17 @@ -MAINTAINERCLEANFILES = Makefile.in +MAINTAINERCLEANFILES = Makefile.in -cgibindir = $(localstatedir)/www/cgi-bin -dist_cgibin_SCRIPTS = \ - striker \ - upload.pl \ - get_anvils \ - get_anvil_status +cgibindir = $(localstatedir)/www/cgi-bin +dist_cgibin_SCRIPTS = \ + cold_stop \ + get_anvil_status \ + get_anvils \ + get_cpu \ + get_memory \ + get_replicated_storage \ + get_shared_storage \ + get_status \ + set_membership \ + set_power \ + striker \ + upload.pl diff --git a/cgi-bin/cold_stop b/cgi-bin/cold_stop new file mode 100755 index 00000000..e69de29b diff --git a/cgi-bin/get_cpu b/cgi-bin/get_cpu new file mode 100755 index 00000000..e69de29b diff --git a/cgi-bin/get_memory b/cgi-bin/get_memory new file mode 100755 index 00000000..e69de29b diff --git a/cgi-bin/get_replicated_storage b/cgi-bin/get_replicated_storage new file mode 100755 index 00000000..e69de29b diff --git a/cgi-bin/get_shared_storage b/cgi-bin/get_shared_storage new file mode 100755 index 00000000..3455a04b --- /dev/null +++ b/cgi-bin/get_shared_storage @@ -0,0 +1,71 @@ +#!/usr/bin/perl +# +# This prints JSON formated data reporting the status of an Anvil! system and it's member hosts. +# + +use strict; +use warnings; +use Anvil::Tools; +use Data::Dumper; +use JSON; + +$| = 1; + +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(); + +$anvil->Get->switches; + +$anvil->Database->connect; +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); +if (not $anvil->data->{sys}{database}{connections}) +{ + # No databases, exit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003"}); + $anvil->nice_exit({exit_code => 1}); +} + +# Read in any CGI variables, if needed. +$anvil->Get->cgi(); + +$anvil->Database->get_hosts(); +$anvil->Database->get_anvils(); + +print $anvil->Template->get({file => "shared.html", name => "json_headers", show_name => 0})."\n"; + +my $hash = {}; +my $anvil_uuid = $anvil->data->{cgi}{anvil_uuid}{value}; +if ((not $anvil_uuid) or (not exists $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid})) +{ + $anvil->data->{anvil_status}{anvil_name} = "!!invalid!anvil_uuid!!"; +} +else +{ + $anvil->data->{anvil_status}{anvil_name} = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name}; + $anvil->data->{anvil_status}{anvil_description} = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_description}; + $anvil->data->{anvil_status}{timestamp} = time; + + my $node1_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; + my $node2_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; + my $node2_status = $anvil->data->{hosts}{host_uuid}{$node2_uuid}{host_status} eq "online" ? 1 : 0; + + $anvil->data->{anvil_status}{nodes}{node1}{host_name} = $anvil->data->{hosts}{host_uuid}{$node1_uuid}{host_name}; + $anvil->data->{anvil_status}{nodes}{node1}{host_uuid} = $node1_uuid; + $anvil->data->{anvil_status}{nodes}{node1}{host_status} = $anvil->data->{hosts}{host_uuid}{$node1_uuid}{host_status} eq "online" ? 1 : 0; + $anvil->data->{anvil_status}{nodes}{node2}{host_name} = $anvil->data->{hosts}{host_uuid}{$node2_uuid}{host_name}; + $anvil->data->{anvil_status}{nodes}{node2}{host_uuid} = $node2_uuid; + $anvil->data->{anvil_status}{nodes}{node2}{host_status} = $anvil->data->{hosts}{host_uuid}{$node2_uuid}{host_status} eq "online" ? 1 : 0; + + $hash->{timestamp} = time; + $hash->{nodes} = []; + push @{$hash->{nodes}}, { on => $anvil->data->{anvil_status}{nodes}{node1}{host_status} }; + push @{$hash->{nodes}}, { on => $anvil->data->{anvil_status}{nodes}{node2}{host_status} }; +} + +print JSON->new->utf8->encode($hash)."\n"; diff --git a/cgi-bin/get_status b/cgi-bin/get_status new file mode 100755 index 00000000..e69de29b diff --git a/cgi-bin/set_membership b/cgi-bin/set_membership new file mode 100755 index 00000000..e69de29b diff --git a/cgi-bin/set_power b/cgi-bin/set_power new file mode 100755 index 00000000..e69de29b diff --git a/notes b/notes index c1c35931..cf8509af 100644 --- a/notes +++ b/notes @@ -7,6 +7,12 @@ TODO: ============ +Jenkins; + +- + +============ + DISABLE KSM! - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_tuning_and_optimization_guide/chap-ksm diff --git a/scancore-agents/scan-filesystems/scan-filesystems b/scancore-agents/scan-filesystems/scan-filesystems new file mode 100755 index 00000000..a913ce33 --- /dev/null +++ b/scancore-agents/scan-filesystems/scan-filesystems @@ -0,0 +1,607 @@ +#!/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: +# - +# +# TODO: +# - +# + +use strict; +use warnings; +use Anvil::Tools; +use Data::Dumper; +use JSON; +use XML::LibXML; + +# 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-filesystems'}{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; + +# If we're disabled and '--force' wasn't used, exit. +if (($anvil->data->{scancore}{'scan-filesystems'}{disable}) && (not $anvil->data->{switches}{force})) +{ + # Exit. + $anvil->nice_exit({exit_code => 0}); +} + +# Handle start-up tasks +my $problem = $anvil->ScanCore->agent_startup({agent => $THIS_FILE}); +if ($problem) +{ + $anvil->nice_exit({exit_code => 1}); +} + +if ($anvil->data->{switches}{purge}) +{ + # This can be called when doing bulk-database purges. + my $schema_file = $anvil->data->{path}{directories}{scan_agents}."/".$THIS_FILE."/".$THIS_FILE.".sql"; + $anvil->Database->purge_data({ + debug => 2, + tables => $anvil->Database->get_tables_from_schema({schema_file => $schema_file}), + }); + $anvil->nice_exit({exit_code => 0}); +} + +# Find the block devices on this host. +collect_data($anvil); + +# Load stored data. +read_last_scan($anvil); + +# Loog for changes +find_changes($anvil); + +# Mark that we ran. +$anvil->Database->insert_or_update_updated({updated_by => $THIS_FILE}); + +$anvil->nice_exit({exit_code => 0}); + +############################################################################################################# +# Functions # +############################################################################################################# + +sub find_changes +{ + my ($anvil) = @_; + +=cut + foreach my $scan_filesystem_type (keys %{$anvil->data->{filesystem}{scan_filesystem_type}}) + { + my $scan_filesystem_kernel_name = $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{name}; + my $scan_filesystem_mount_point = $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{used_by_vg}; + my $scan_filesystem_media_type = $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{attributes}; + my $scan_filesystem_size = $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{size}; + my $scan_filesystem_free = $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{free_space}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + scan_filesystem_type => $scan_filesystem_type, + scan_filesystem_kernel_name => $scan_filesystem_kernel_name, + scan_filesystem_mount_point => $scan_filesystem_mount_point, + scan_filesystem_media_type => $scan_filesystem_media_type, + scan_filesystem_size => $anvil->Convert->add_commas({number => $scan_filesystem_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_filesystem_size}), + scan_filesystem_free => $anvil->Convert->add_commas({number => $scan_filesystem_free})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_filesystem_free}), + }}); + + # Have we seen this before? + if (exists $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}) + { + # Yup, anything changed? + my $scan_filesystem_uuid = $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_uuid}; + my $old_scan_filesystem_kernel_name = $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_kernel_name}; + my $old_scan_filesystem_mount_point = $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_mount_point}; + my $old_scan_filesystem_media_type = $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_media_type}; + my $old_scan_filesystem_size = $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_size}; + my $old_scan_filesystem_free = $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_free}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_scan_filesystem_kernel_name => $old_scan_filesystem_kernel_name, + old_scan_filesystem_mount_point => $old_scan_filesystem_mount_point, + old_scan_filesystem_media_type => $old_scan_filesystem_media_type, + old_scan_filesystem_size => $anvil->Convert->add_commas({number => $old_scan_filesystem_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_filesystem_size}), + old_scan_filesystem_free => $anvil->Convert->add_commas({number => $old_scan_filesystem_free})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_filesystem_free}), + }}); + + my $update = 0; + if ($scan_filesystem_kernel_name ne $old_scan_filesystem_kernel_name) + { + $update = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }}); + if ($old_scan_filesystem_kernel_name eq "DELETED") + { + # A lost PV is back + my $variables = { + pv_uuid => $scan_filesystem_type, + pv_name => $scan_filesystem_kernel_name, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_filesystem_alert_0001", variables => $variables}); + $anvil->Alert->register({clear_alert => 1, alert_level => "warning", message => "scan_filesystem_alert_0001", variables => $variables, set_by => $THIS_FILE}); + } + else + { + # Device (name) changed... This shouldn't normally happen. + my $variables = { + pv_uuid => $scan_filesystem_type, + new_name => $scan_filesystem_kernel_name, + old_name => $old_scan_filesystem_kernel_name, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_filesystem_alert_0002", variables => $variables}); + $anvil->Alert->register({alert_level => "warning", message => "scan_filesystem_alert_0002", variables => $variables, set_by => $THIS_FILE}); + } + } + if ($scan_filesystem_mount_point ne $old_scan_filesystem_mount_point) + { + # 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_filesystem_mount_point) + { + # Added to a VG + my $variables = { + pv_uuid => $scan_filesystem_type, + pv_name => $scan_filesystem_kernel_name, + vg_name => $scan_filesystem_mount_point, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_filesystem_alert_0004", variables => $variables}); + $anvil->Alert->register({alert_level => "notice", message => "scan_filesystem_alert_0004", variables => $variables, set_by => $THIS_FILE}); + } + else + { + # The VG was probably renamed. + my $variables = { + pv_uuid => $scan_filesystem_type, + pv_name => $scan_filesystem_kernel_name, + new_vg_name => $scan_filesystem_mount_point, + old_vg_name => $old_scan_filesystem_mount_point, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_filesystem_alert_0005", variables => $variables}); + $anvil->Alert->register({alert_level => "notice", message => "scan_filesystem_alert_0005", variables => $variables, set_by => $THIS_FILE}); + } + } + if ($scan_filesystem_media_type ne $old_scan_filesystem_media_type) + { + # Attribute bits changed. + $update = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }}); + my $variables = { + pv_uuid => $scan_filesystem_type, + pv_name => $scan_filesystem_kernel_name, + new_attributes => $scan_filesystem_media_type, + old_attributes => $old_scan_filesystem_media_type, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_filesystem_alert_0006", variables => $variables}); + $anvil->Alert->register({alert_level => "notice", message => "scan_filesystem_alert_0006", variables => $variables, set_by => $THIS_FILE}); + } + if ($scan_filesystem_size ne $old_scan_filesystem_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_filesystem_type, + pv_name => $scan_filesystem_kernel_name, + new_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_filesystem_size}), + new_size_bytes => $anvil->Convert->add_commas({number => $scan_filesystem_size}), + old_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_filesystem_size}), + old_size_bytes => $anvil->Convert->add_commas({number => $old_scan_filesystem_size}), + }; + if ($scan_filesystem_size > $old_scan_filesystem_size) + { + # Yup + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_filesystem_alert_0007", variables => $variables}); + $anvil->Alert->register({alert_level => "notice", message => "scan_filesystem_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_filesystem_alert_0008", variables => $variables}); + $anvil->Alert->register({alert_level => "warning", message => "scan_filesystem_alert_0008", variables => $variables, set_by => $THIS_FILE}); + } + } + if ($scan_filesystem_free ne $old_scan_filesystem_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_filesystem_type, + pv_name => $scan_filesystem_kernel_name, + new_free => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_filesystem_free}), + new_free_bytes => $anvil->Convert->add_commas({number => $scan_filesystem_free}), + old_free => $anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_filesystem_free}), + old_free_bytes => $anvil->Convert->add_commas({number => $old_scan_filesystem_free}), + }; + if ($scan_filesystem_free < $old_scan_filesystem_free) + { + # Yup + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_filesystem_alert_0009", variables => $variables}); + $anvil->Alert->register({alert_level => "notice", message => "scan_filesystem_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_filesystem_alert_0010", variables => $variables}); + $anvil->Alert->register({alert_level => "warning", message => "scan_filesystem_alert_0010", 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_filesystems +SET + scan_filesystem_kernel_name = ".$anvil->Database->quote($scan_filesystem_kernel_name).", + scan_filesystem_mount_point = ".$anvil->Database->quote($scan_filesystem_mount_point).", + scan_filesystem_media_type = ".$anvil->Database->quote($scan_filesystem_media_type).", + scan_filesystem_size = ".$anvil->Database->quote($scan_filesystem_size).", + scan_filesystem_free = ".$anvil->Database->quote($scan_filesystem_free).", + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_filesystem_uuid = ".$anvil->Database->quote($scan_filesystem_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_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}; + } + else + { + # New PV + my $variables = { + pv_uuid => $scan_filesystem_type, + pv_name => $scan_filesystem_kernel_name, + vg_name => $scan_filesystem_mount_point ? $scan_filesystem_mount_point : "--", + attributes => $scan_filesystem_media_type, + pv_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_filesystem_size}), + pv_size_bytes => $anvil->Convert->add_commas({number => $scan_filesystem_size}), + pv_free => $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_filesystem_free}), + pv_free_bytes => $anvil->Convert->add_commas({number => $scan_filesystem_free}), + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_filesystem_alert_0019", variables => $variables}); + $anvil->Alert->register({alert_level => "notice", message => "scan_filesystem_alert_0019", variables => $variables, set_by => $THIS_FILE}); + + my $scan_filesystem_uuid = $anvil->Get->uuid(); + my $query = " +INSERT INTO + scan_filesystems +( + scan_filesystem_uuid, + scan_filesystem_type, + scan_filesystem_host_uuid, + scan_filesystem_kernel_name, + scan_filesystem_mount_point, + scan_filesystem_media_type, + scan_filesystem_size, + scan_filesystem_free, + modified_date +) VALUES ( + ".$anvil->Database->quote($scan_filesystem_uuid).", + ".$anvil->Database->quote($scan_filesystem_type).", + ".$anvil->Database->quote($anvil->Get->host_uuid).", + ".$anvil->Database->quote($scan_filesystem_kernel_name).", + ".$anvil->Database->quote($scan_filesystem_mount_point).", + ".$anvil->Database->quote($scan_filesystem_media_type).", + ".$anvil->Database->quote($scan_filesystem_size).", + ".$anvil->Database->quote($scan_filesystem_free).", + ".$anvil->Database->quote($anvil->data->{sys}{database}{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_filesystem_type (keys %{$anvil->data->{sql}{scan_filesystems}{scan_filesystem_type}}) + { + # This one is missing. + my $scan_filesystem_uuid = $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_uuid}; + my $old_scan_filesystem_kernel_name = $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_kernel_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:scan_filesystem_type' => $scan_filesystem_type, + 's2:scan_filesystem_uuid' => $scan_filesystem_uuid, + 's3:old_scan_filesystem_kernel_name' => $old_scan_filesystem_kernel_name, + }}); + next if $old_scan_filesystem_kernel_name eq "DELETED"; + + # Register an alert + my $variables = { + pv_uuid => $scan_filesystem_type, + pv_name => $old_scan_filesystem_kernel_name, + }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_filesystem_alert_0003", variables => $variables}); + $anvil->Alert->register({alert_level => "warning", message => "scan_filesystem_alert_0003", variables => $variables, set_by => $THIS_FILE}); + + # Update it PV name to be 'DELTED' + my $query = " +UPDATE + scan_filesystems +SET + scan_filesystem_kernel_name = 'DELETED', + modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." +WHERE + scan_filesystem_uuid = ".$anvil->Database->quote($scan_filesystem_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); + } +=cut + + return(0); +} + +# This reads in the last scan's data. +sub read_last_scan +{ + my ($anvil) = @_; + + # Load disk data. We load all drives, so that we can track removable media. + my $query = " +SELECT + scan_filesystem_uuid, + scan_filesystem_host_uuid, + scan_filesystem_type, + scan_filesystem_kernel_name, + scan_filesystem_mount_point, + scan_filesystem_transport, + scan_filesystem_media_type, + scan_filesystem_vendor, + scan_filesystem_model, + scan_filesystem_serial_number, + scan_filesystem_description, + scan_filesystem_size, + scan_filesystem_used +FROM + scan_filesystems +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + my $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + # We've got an entry in the 'scan_filesystems' table, so now we'll look for data in the node and + # services tables. + my $scan_filesystem_uuid = $row->[0]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_host_uuid} = $row->[1]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_type} = $row->[2]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_kernel_name} = $row->[3]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_mount_point} = $row->[4]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_transport} = $row->[5]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_media_type} = $row->[6]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_vendor} = $row->[7]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_model} = $row->[8]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_serial_number} = $row->[9]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_description} = $row->[10]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_size} = $row->[11]; + $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_used} = $row->[12]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_uuid" => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_uuid}, + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_kernel_name" => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_kernel_name}, + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_mount_point" => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_mount_point}, + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_transport" => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_transport}, + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_media_type" => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_media_type}, + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_vendor" => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_vendor}, + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_model" => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_model}, + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_serial_number" => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_serial_number}, + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_description" => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_description}, + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_size" => $anvil->Convert->add_commas({number => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_size}}), + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_used" => $anvil->Convert->add_commas({number => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_used}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_used}}), + "sql::scan_filesystems::scan_filesystem_uuid::${scan_filesystem_uuid}::scan_filesystem_host_uuid" => $anvil->data->{sql}{scan_filesystems}{scan_filesystem_uuid}{$scan_filesystem_uuid}{scan_filesystem_host_uuid}, + }}); + } + + return(0); +} + +sub collect_data +{ + my ($anvil) = @_; + + ### NOTE: If a drive is unmounted, we can't trust the sizes. + $anvil->Storage->parse_lsblk({debug => 2}); + $anvil->Storage->parse_df({debug => 2}); + foreach my $kernel_device_name (sort {$a cmp $b} keys %{$anvil->{storage}{lsblk}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { kernel_device_name => $kernel_device_name }}); + if ($anvil->{storage}{lsblk}{$kernel_device_name}{type} eq "partition") + { + $anvil->data->{new}{partition}{$kernel_device_name}{type} = $anvil->{storage}{lsblk}{$kernel_device_name}{filesystem_type}; + $anvil->data->{new}{partition}{$kernel_device_name}{mount_point} = $anvil->{storage}{lsblk}{$kernel_device_name}{mount_point}; + $anvil->data->{new}{partition}{$kernel_device_name}{transport} = $anvil->{storage}{lsblk}{$kernel_device_name}{transport}; + $anvil->data->{new}{partition}{$kernel_device_name}{media_type} = $anvil->{storage}{lsblk}{$kernel_device_name}{rotating_drive} ? "platter" : "solid_state"; # This could be network as well someday + $anvil->data->{new}{partition}{$kernel_device_name}{vendor} = $anvil->{storage}{lsblk}{$kernel_device_name}{vendor}; + $anvil->data->{new}{partition}{$kernel_device_name}{model} = $anvil->{storage}{lsblk}{$kernel_device_name}{model}; + $anvil->data->{new}{partition}{$kernel_device_name}{serial_number} = $anvil->{storage}{lsblk}{$kernel_device_name}{serial_number}; + $anvil->data->{new}{partition}{$kernel_device_name}{description} = $anvil->{storage}{lsblk}{$kernel_device_name}{partition_label}; + $anvil->data->{new}{partition}{$kernel_device_name}{size} = 0; + $anvil->data->{new}{partition}{$kernel_device_name}{used} = 0; + if (($anvil->data->{new}{partition}{$kernel_device_name}{mount_point}) && (exists $anvil->{storage}{df}{$kernel_device_name})) + { + # Look for space usage from 'df' + my $df_mount_point = $anvil->{storage}{df}{$kernel_device_name}{mount_point}; + my $df_filesystem_type = $anvil->{storage}{df}{$kernel_device_name}{filesystem_type}; + my $df_size = $anvil->{storage}{df}{$kernel_device_name}{size}; + my $df_used = $anvil->{storage}{df}{$kernel_device_name}{used}; + my $df_free = $anvil->{storage}{df}{$kernel_device_name}{free}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + df_filesystem_type => $df_filesystem_type, + df_mount_point => $df_mount_point, + size => $anvil->Convert->add_commas({number => $df_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $df_size}).")", + used => $anvil->Convert->add_commas({number => $df_used})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $df_used}).")", + free => $anvil->Convert->add_commas({number => $df_free})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $df_free}).")", + }}); + + # This is a check to see if the calculated free space matches the reported free + # space. + $anvil->data->{new}{partition}{$kernel_device_name}{size} = $df_size; + $anvil->data->{new}{partition}{$kernel_device_name}{used} = $df_used; + my $calculated_free = $anvil->data->{new}{partition}{$kernel_device_name}{size} - $anvil->data->{new}{partition}{$kernel_device_name}{used}; + my $difference = $df_free - $calculated_free; + $difference =~ s/^-//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:calculated_free' => $anvil->Convert->add_commas({number => $calculated_free})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $calculated_free}).")", + 's2:difference' => $anvil->Convert->add_commas({number => $difference})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $difference}).")", + }}); + } + + # Record the partition + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:new::partition::${kernel_device_name}::type" => $anvil->data->{new}{partition}{$kernel_device_name}{type}, + "s2:new::partition::${kernel_device_name}::mount_point" => $anvil->data->{new}{partition}{$kernel_device_name}{mount_point}, + "s3:new::partition::${kernel_device_name}::transport" => $anvil->data->{new}{partition}{$kernel_device_name}{transport}, + "s4:new::partition::${kernel_device_name}::media_type" => $anvil->data->{new}{partition}{$kernel_device_name}{media_type}, + "s5:new::partition::${kernel_device_name}::vendor" => $anvil->data->{new}{partition}{$kernel_device_name}{vendor}, + "s6:new::partition::${kernel_device_name}::model" => $anvil->data->{new}{partition}{$kernel_device_name}{model}, + "s7:new::partition::${kernel_device_name}::serial_number" => $anvil->data->{new}{partition}{$kernel_device_name}{serial_number}, + "s8:new::partition::${kernel_device_name}::description" => $anvil->data->{new}{partition}{$kernel_device_name}{description}, + "s9:new::partition::${kernel_device_name}::size" => $anvil->Convert->add_commas({number => $anvil->data->{new}{partition}{$kernel_device_name}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{partition}{$kernel_device_name}{size}}).")", + "s10:new::partition::${kernel_device_name}::used" => $anvil->Convert->add_commas({number => $anvil->data->{new}{partition}{$kernel_device_name}{used}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{partition}{$kernel_device_name}{used}}).")", + }}); + } + } + + return(0); +} + +# This collects data for buses and disk info. +sub collect_bus_data +{ + my ($anvil) = @_; + + my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{lshw}." -class disk -class storage -xml"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # We tried -json, but the output was not validly formatted. + local $@; + my $dom = eval { XML::LibXML->load_xml(string => $output); }; + if ($@) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "warning_0053", variables => { + cib => $output, + error => $@, + }}); + } + + foreach my $node ($dom->findnodes('/list/node')) + { + my $id = $node->{id}; + my $class = $node->{class}; + my $description = $node->findvalue('./description'); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + id => $id, + class => $class, + description => $description, + }}); + foreach my $device ($node->findnodes('./node')) + { + my $dev_id = $device->{id}; + my $dev_class = $device->{class}; + my $bus_info = $device->findvalue('./businfo'); + my $path = $device->findvalue('./logicalname'); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + dev_id => $dev_id, + dev_class => $dev_class, + bus_info => $bus_info, + path => $path, + }}); + } + + + ### NOTE: Full CIB details; + ### - https://clusterlabs.org/pacemaker/doc/en-US/Pacemaker/2.0/html-single/Pacemaker_Explained/index.html + # Successful parse! +# foreach my $nvpair ($dom->findnodes('/cib/configuration/crm_config/cluster_property_set/nvpair')) +# { +# my $nvpair_id = $nvpair->{id}; +# foreach my $variable (sort {$a cmp $b} keys %{$nvpair}) +# { +# next if $variable eq "id"; +# $anvil->data->{cib}{parsed}{configuration}{crm_config}{cluster_property_set}{nvpair}{$nvpair_id}{$variable} = $nvpair->{$variable}; +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { +# "cib::parsed::configuration::crm_config::cluster_property_set::nvpair::${nvpair_id}::${variable}" => $anvil->data->{cib}{parsed}{configuration}{crm_config}{cluster_property_set}{nvpair}{$nvpair_id}{$variable}, +# }}); +# } +# } +# foreach my $node ($dom->findnodes('/cib/configuration/nodes/node')) +# { +# } + } + +# my $json = JSON->new->allow_nonref; +# my $pvs_data = $json->decode($output); +# foreach my $hash_ref (@{$pvs_data->{report}->[0]->{pv}}) +# { +# my $scan_filesystem_type = $hash_ref->{pv_uuid}; +# $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{name} = $hash_ref->{pv_name}; +# $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{used_by_vg} = $hash_ref->{vg_name}; +# $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{attributes} = $hash_ref->{pv_attr}; # TODO: Parse this out +# $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{size} = ($hash_ref->{pv_size} =~ /^(\d+)B/)[0]; +# $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{free_space} = ($hash_ref->{pv_free} =~ /^(\d+)B/)[0]; +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { +# "filesystem::scan_filesystem_uuid::${scan_filesystem_uuid}::name" => $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{name}, +# "filesystem::scan_filesystem_uuid::${scan_filesystem_uuid}::used_by_vg" => $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{used_by_vg}, +# "filesystem::scan_filesystem_uuid::${scan_filesystem_uuid}::attributes" => $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{attributes}, +# "filesystem::scan_filesystem_uuid::${scan_filesystem_uuid}::size" => $anvil->Convert->add_commas({number => $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{size}}).")", +# "filesystem::scan_filesystem_uuid::${scan_filesystem_uuid}::free_space" => $anvil->Convert->add_commas({number => $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{free_space}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{filesystem}{scan_filesystem_type}{$scan_filesystem_type}{free_space}}).")", +# }}); +# } + + return(0); +} + +sub collect_fs_data +{ + my ($anvil) = @_; + + + return(0); +} + diff --git a/scancore-agents/scan-filesystems/scan-filesystems.sql b/scancore-agents/scan-filesystems/scan-filesystems.sql new file mode 100644 index 00000000..63dd1f23 --- /dev/null +++ b/scancore-agents/scan-filesystems/scan-filesystems.sql @@ -0,0 +1,88 @@ +-- This is the database schema for the 'scan-lvm Scan Agent'. + + +-- This table stores physical volume information +CREATE TABLE scan_filesystems ( + scan_filesystem_uuid uuid primary key, -- This comes from the file system's UUID + scan_filesystem_host_uuid uuid not null, -- The host that the file system is mounted on. Note that some FSes, like those from USB, can move between hosts. + scan_filesystem_type text not null, -- This is the name of the file system type. + scan_filesystem_kernel_name text not null, -- This is the backing device of the file system. + scan_filesystem_mount_point text not null, -- This is the name of the mount point. + scan_filesystem_transport text not null, -- Optional description of the drive's transport (usb, nvme, sata, sata, md, raid, optical, sdcard, etc - 'unknown') + scan_filesystem_media_type text not null, -- This is set to 'ssd' for solid state, 'platter' for spinning rust, 'network' for network mounts, etc. + scan_filesystem_vendor text not null, -- Optional vendor of the drive the partition is on + scan_filesystem_model text not null, -- Optional model of the drive the partiton is on + scan_filesystem_serial_number text not null, -- Optional serial number of the drive the partition is on + scan_filesystem_description text not null, -- Free form description of the device. + scan_filesystem_size numeric not null, -- The size of the partition, in bytes + scan_filesystem_used numeric not null, -- The used space, in bytes. + modified_date timestamp with time zone not null, + + FOREIGN KEY(scan_filesystem_host_uuid) REFERENCES hosts(host_uuid) +); +ALTER TABLE scan_filesystems OWNER TO admin; + +CREATE TABLE history.scan_filesystems ( + history_id bigserial, + scan_filesystem_uuid uuid, + scan_filesystem_host_uuid uuid, + scan_filesystem_type text, + scan_filesystem_kernel_name text, + scan_filesystem_mount_point text, + scan_filesystem_transport text, + scan_filesystem_media_type text, + scan_filesystem_vendor text, + scan_filesystem_model text, + scan_filesystem_serial_number text, + scan_filesystem_description text, + scan_filesystem_size numeric, + scan_filesystem_used numeric, + modified_date timestamp with time zone not null +); +ALTER TABLE history.scan_filesystems OWNER TO admin; + +CREATE FUNCTION history_scan_filesystems() RETURNS trigger +AS $$ +DECLARE + history_scan_filesystems RECORD; +BEGIN + SELECT INTO history_scan_filesystems * FROM scan_filesystems WHERE scan_filesystem_uuid=new.scan_filesystem_uuid; + INSERT INTO history.scan_filesystems + (scan_filesystem_uuid, + scan_filesystem_host_uuid, + scan_filesystem_type, + scan_filesystem_kernel_name, + scan_filesystem_mount_point, + scan_filesystem_transport, + scan_filesystem_media_type, + scan_filesystem_vendor, + scan_filesystem_model, + scan_filesystem_serial_number, + scan_filesystem_description, + scan_filesystem_size, + scan_filesystem_used, + modified_date) + VALUES + (history_scan_filesystems.scan_filesystem_uuid, + history_scan_filesystems.scan_filesystem_host_uuid, + history_scan_filesystems.scan_filesystem_type, + history_scan_filesystems.scan_filesystem_kernel_name, + history_scan_filesystems.scan_filesystem_mount_point, + history_scan_filesystems.scan_filesystem_transport, + history_scan_filesystems.scan_filesystem_media_type, + history_scan_filesystems.scan_filesystem_vendor, + history_scan_filesystems.scan_filesystem_model, + history_scan_filesystems.scan_filesystem_serial_number, + history_scan_filesystems.scan_filesystem_description, + history_scan_filesystems.scan_filesystem_size, + history_scan_filesystems.scan_filesystem_used, + history_scan_filesystems.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_scan_filesystems() OWNER TO admin; + +CREATE TRIGGER trigger_scan_filesystems + AFTER INSERT OR UPDATE ON scan_filesystems + FOR EACH ROW EXECUTE PROCEDURE history_scan_filesystems(); diff --git a/scancore-agents/scan-filesystems/scan-filesystems.xml b/scancore-agents/scan-filesystems/scan-filesystems.xml new file mode 100644 index 00000000..8bd61ca2 --- /dev/null +++ b/scancore-agents/scan-filesystems/scan-filesystems.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + Starting: [#!variable!program!#]. + + + + + + + + + diff --git a/scancore-agents/scan-hardware/scan-hardware b/scancore-agents/scan-hardware/scan-hardware index da1e88f0..6288b7fd 100755 --- a/scancore-agents/scan-hardware/scan-hardware +++ b/scancore-agents/scan-hardware/scan-hardware @@ -9,7 +9,7 @@ # 1 = Startup failure (not running as root, no DB, bad file read, etc) # # TODO: -# - +# - Finish System->parse_lwhw(), lots of good stuff in there. # use strict; diff --git a/share/anvil.sql b/share/anvil.sql index 88b490b8..36888399 100644 --- a/share/anvil.sql +++ b/share/anvil.sql @@ -20,6 +20,10 @@ -- Tables can optionally have a '*_host_uuid uuid not null' colum. If this is found, when resync'ing the -- table, the resync will be restricted to the host's 'sys::host_uuid'. -- +-- NOTE: If you have a column that is '_host_uuid', and it's role is to show which host a moveable +-- thing is on (as opposed to a record bound to a host_uuid), be sure to add the table name to the +-- excluded list in Database->_find_behind_databases(). +-- -- Most tables will want to have a matching table in the history schema with an additional -- 'history_id bigserial' column. Match the function and trigger seen elsewhere to copy your data from the -- public schema to the history schema on UPDATE or INSERT. @@ -1229,7 +1233,7 @@ CREATE TABLE servers ( server_user_stop boolean not null default FALSE, -- When set, the server was stopped by a user. The Anvil! will not start a server that has been cleanly stopped. server_start_after_server_uuid uuid, -- This can be the server_uuid of another server. If set, this server will boot 'server_start_delay' seconds after the referenced server boots. A value of '00000000-0000-0000-0000-000000000000' will tell 'anvil-safe-start' to not boot the server at all. If a server is set not to start, any dependent servers will also stay off. server_start_delay integer not null default 0, -- See above. - server_host_uuid uuid not null, -- This is the current hosts -> host_uuid for this server. If the server is off, this will be blank. + server_host_uuid uuid, -- This is the current hosts -> host_uuid for this server. If the server is off, this will be blank. server_state text not null, -- This is the current state of this server, as reported by 'virsh list --all' (see: man virsh -> GENERIC COMMANDS -> --list) server_live_migration boolean not null default TRUE, -- When false, servers will be frozen for a migration, instead of being migrated while the server is migrating. During a cold migration, the server will be unresponsive, so connections to it could time out. However, by being frozen the migration will complete faster. server_pre_migration_file_uuid uuid, -- This is set to the files -> file_uuid of a script to run BEFORE migrating a server. If the file isn't found or can't run, the script is ignored. diff --git a/share/words.xml b/share/words.xml index 6a8e83da..11bf252b 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2319,6 +2319,8 @@ Read UUID: .... [#!variable!read_uuid!#] [ Warning ] - It looks like the postfix daemon is not running. Enabling and starting it now.[ Warning ] - Checking the mail queue after attempting to start postgres appears to have still failed. Output received was: [#!variable!output!#].[ Warning ] - Not installing the Alteeve repo! The package: [#!variable!anvil_role_rpm!#] is already installed. This is OK, but be aware that updates from Alteeve will not be available. To change this, please install: [#!variable!alteeve_repo!#]. + [ Warning ] - Failed to read the JSON formatted output of 'lsblk'. Expected the return code '0' but received: [#!variable!return_code!#]. The output, if any, was: [#!variable!output!#]. + [ Warning ] - Failed to read the XML formatted output of 'lshw'. Expected the return code '0' but received: [#!variable!return_code!#]. The output, if any, was: [#!variable!output!#]. diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index 07142c11..edecc7d2 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -36,6 +36,10 @@ my $anvil = Anvil::Tools->new(); # Read switches $anvil->Get->switches; +### TODO: Remove this before final release +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); +########################################## # Make sure we're running as 'root' # $< == real UID, $> == effective UID @@ -1203,18 +1207,21 @@ AND }); # If we're in a cluster, abort. - my ($problem) = $anvil->Cluster->parse_cib(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); - if ((not $problem) && ($anvil->data->{cib}{parsed}{'local'}{ready})) + if (-e $anvil->data->{path}{exe}{pcs}) { - # We're in a cluster, abort. - $anvil->Job->update_progress({ - progress => 100, - message => "error_0250", - job_uuid => $anvil->data->{job}{uuid}, - }); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0250"}); - $anvil->nice_exit({exit_code => 7}); + my ($problem) = $anvil->Cluster->parse_cib(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); + if ((not $problem) && ($anvil->data->{cib}{parsed}{'local'}{ready})) + { + # We're in a cluster, abort. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0250", + job_uuid => $anvil->data->{job}{uuid}, + }); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0250"}); + $anvil->nice_exit({exit_code => 7}); + } } return(0); diff --git a/tools/anvil-provision-server b/tools/anvil-provision-server index 921524b4..5c2a129f 100755 --- a/tools/anvil-provision-server +++ b/tools/anvil-provision-server @@ -1012,7 +1012,7 @@ sub create_lv my $vg_name = $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_name}; my $extent_size = $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_extent_size}; my $extent_count = int($anvil->data->{job}{storage_size} / $extent_size); - my $shell_call = $anvil->data->{path}{exe}{lvcreate}." -l ".$extent_count." -n ".$anvil->data->{job}{server_name}."_0 ".$vg_name; + my $shell_call = $anvil->data->{path}{exe}{lvcreate}." -l ".$extent_count." -n ".$anvil->data->{job}{server_name}."_0 ".$vg_name." -y"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:vg_name' => $vg_name, 's2:extent_size' => $extent_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $extent_size}).")", @@ -1361,7 +1361,7 @@ sub parse_job_data } # Driver disc is optional. $anvil->data->{new_server}{driver_iso_path} = ""; - if ($anvil->data->{job}{driver_iso_uuid}) + if (($anvil->data->{job}{driver_iso_uuid}) && ($anvil->data->{job}{driver_iso_uuid} ne "none")) { my $driver_iso_uuid = $anvil->data->{job}{driver_iso_uuid}; my $driver_iso = $anvil->data->{files}{file_uuid}{$driver_iso_uuid}{file_directory}."/".$anvil->data->{files}{file_uuid}{$driver_iso_uuid}{file_name}; diff --git a/tools/striker-auto-initialize-all b/tools/striker-auto-initialize-all index f92800f4..a96ac68a 100755 --- a/tools/striker-auto-initialize-all +++ b/tools/striker-auto-initialize-all @@ -35,6 +35,10 @@ if (not $anvil->data->{sys}{database}{connections}) $anvil->data->{switches}{config} = ""; $anvil->data->{switches}{'job-uuid'} = ""; $anvil->Get->switches; +### TODO: Remove this before final release +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); +########################################## # Read in the config file if ((not $anvil->data->{switches}{config}) or (not -f $anvil->data->{switches}{config})) diff --git a/tools/striker-initialize-host b/tools/striker-initialize-host index 8e80e97d..7a909add 100755 --- a/tools/striker-initialize-host +++ b/tools/striker-initialize-host @@ -33,6 +33,10 @@ my $anvil = Anvil::Tools->new(); # Read switches (target ([user@]host[:port]) and the file with the target's password. $anvil->data->{switches}{'job-uuid'} = ""; $anvil->Get->switches; +### TODO: Remove this before final release +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); +########################################## $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'}, @@ -184,7 +188,7 @@ sub add_databases if ($db_host) { my $failed = $anvil->Database->manage_anvil_conf({ - debug => 3, + debug => 2, target => $target, remote_user => "root", password => $anvil->data->{data}{password}, @@ -282,7 +286,7 @@ sub add_databases if ($peer_host) { my $failed = $anvil->Database->manage_anvil_conf({ - debug => 3, + debug => 2, target => $target, remote_user => "root", password => $anvil->data->{data}{password}, @@ -773,7 +777,7 @@ EOF $shell_call = $anvil->data->{path}{exe}{'dnf'}." -y install ".$package; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); ($output, $error, $return_code) = $anvil->Remote->call({ - debug => 3, + debug => 2, shell_call => $shell_call, password => $anvil->data->{data}{password}, port => $anvil->data->{data}{ssh_port},