From be84a239244c4bad1989b2b60c798ebe1d5544ca Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 8 Aug 2022 21:31:56 -0400 Subject: [PATCH 1/8] * There were still references in anvil-manage-files to 'file_locations' -> 'file_location_host_uuid'. Had to rework some logic to get things working. More testing needed, but so far at least the "missing file" function is working again. * Added missing always-available switchs in Get->switches * Create Storage->_wait_if_changing() to check to see if a file's size is changing and, if so, not return until it stops. Signed-off-by: Digimer --- Anvil/Tools/Get.pm | 4 +- Anvil/Tools/Storage.pm | 102 ++++++ man/anvil-manage-files.8 | 38 +++ share/words.xml | 5 +- tools/anvil-manage-files | 664 +++++++++++++++------------------------ 5 files changed, 394 insertions(+), 419 deletions(-) create mode 100644 man/anvil-manage-files.8 diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 11c38cc8..6b56ef5d 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -2297,12 +2297,14 @@ sub switches next if $set_switch eq "?"; next if $set_switch eq "h"; next if $set_switch eq "help"; + next if $set_switch eq "log-secure"; + next if $set_switch eq "log-db-transactions"; next if $set_switch eq "raw"; + next if $set_switch eq "resync-db"; next if $set_switch eq "v"; next if $set_switch eq "vv"; next if $set_switch eq "vvv"; next if $set_switch eq "vvvv"; - next if $set_switch eq "log-secure"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { set_switch => $set_switch }}); my $found = 0; diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index 0626d229..654a2e33 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -46,6 +46,7 @@ my $THIS_FILE = "Storage.pm"; # update_file # write_file # _create_rsync_wrapper +# _wait_if_changing =pod @@ -5151,6 +5152,7 @@ fi"; # Private functions # ############################################################################################################# + =head2 This does the actual work of creating the C<< expect >> wrapper script and returns the path to that wrapper for C<< rsync >> calls. @@ -5227,4 +5229,104 @@ expect eof return($wrapper_script); } + +=head3 _wait_if_changing + +This takes a full path to a file, and watches it for at specified number of seconds to see if the size is changing. If it is, this method waits until the file size stops changing. + +Parameters; + +=head3 file (required) + +This is the full path to the file. If the file is not found, C<< !!error!! >> is returned. + +=head3 delay (optional, default '2') + +This is how long to wait before checking to see if the file has changed. + +=head3 last_size (optional) + +If this is set, it's the first size we compare against. If not passed, the size will be checked. + +=cut +sub _wait_if_changing +{ + 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->_create_rsync_wrapper()" }}); + + # Check my parameters. + my $file = defined $parameter->{file} ? $parameter->{file} : ""; + my $delay = defined $parameter->{delay} ? $parameter->{delay} : ""; + my $last_size = defined $parameter->{last_size} ? $parameter->{last_size} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + file => $file, + delay => $delay, + last_size => $last_size, + }}); + + if (not $delay) + { + $delay = 2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { delay => $delay }}); + } + elsif (($delay =~ /\D/) or ($delay == 0)) + { + $delay = 2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { delay => $delay }}); + } + + if (not -e $file) + { + return("!!error!!"); + } + + if (not $last_size) + { + $last_size = (stat($file))[7]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + last_size => $last_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $last_size}).")", + }}); + } + + my $waiting = 1; + while ($waiting) + { + sleep $delay; + my $new_size = (stat($file))[7]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + file => $file, + last_size => $last_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $last_size}).")", + }}); + if ($new_size == $last_size) + { + # Size seems stable + $waiting = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + } + else + { + # Might still be updating, wait. + my $difference = $new_size - $last_size; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0724", variables => { + file => $file, + old_size_bytes => $anvil->Convert->add_commas({number => $last_size}), + old_size_hr => $anvil->Convert->bytes_to_human_readable({'bytes' => $last_size}), + new_size_bytes => $anvil->Convert->add_commas({number => $new_size}), + new_size_hr => $anvil->Convert->bytes_to_human_readable({'bytes' => $new_size}), + difference_bytes => $anvil->Convert->add_commas({number => $difference}), + difference_hr => $anvil->Convert->bytes_to_human_readable({'bytes' => $difference}), + }}); + + $last_size = $new_size; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { last_size => $last_size }}); + } + } + + return(0); +} + 1; diff --git a/man/anvil-manage-files.8 b/man/anvil-manage-files.8 new file mode 100644 index 00000000..141a5c03 --- /dev/null +++ b/man/anvil-manage-files.8 @@ -0,0 +1,38 @@ +.\" Manpage for the Anvil! server removal tool +.\" Contact mkelly@alteeve.com to report issues, concerns or suggestions. +.TH anvil-manage-files "8" "August 02 2022" "Anvil! Intelligent Availability™ Platform" +.SH NAME +anvil-manage-files \- This program manages the files sync'ed across machines in the Anvil! cluster +.SH SYNOPSIS +.B anvil-manage-files +\fI\, \/\fR[\fI\,options\/\fR] +.SH DESCRIPTION +This handles synchronizing files, typically ISO used to build new servers and scripts used to manage them, across Anvil! nodes. +.TP +.SH OPTIONS +.TP +\-?, \-h, \fB\-\-help\fR +Show this man page. +.TP +\fB\-\-log-secure\fR +When logging, record sensitive data, like passwords. +.TP +\-v, \-vv, \-vvv +Set the log level to 1, 2 or 3 respectively. Be aware that level 3 generates a significant amount of log data. +.SS "Commands:" +.TP +\fB\-\-delete\fR +This will delete the \fB\-\-file\fR from the entire Anvil! cluster. +.TP +This action is permanent! +.TP +\fB\-\-job-uuid\fR +The program is normally run as a job, with data on how to configure the host defined in the job. This switch allows the running of a specific job. If this is not set, the program will search for a job that has not yet been picked up by another process. If found, that job UUID is used automatically. +.IP +.SH AUTHOR +Written by Madison Kelly, Alteeve staff and the Anvil! project contributors. +.SH "REPORTING BUGS" +Report bugs to users@clusterlabs.org + + +", "download", "everywhere", "file", "is-script", "job-uuid", "rename", "to \ No newline at end of file diff --git a/share/words.xml b/share/words.xml index 26d75a35..f71947ee 100644 --- a/share/words.xml +++ b/share/words.xml @@ -1664,8 +1664,8 @@ The fingerprint of: [#!variable!machine!#] has changed! Updating it's entry in k The md5sum of file: [#!variable!file!#] failed to match. Discarding the downloaded file. Failed to download: [#!variable!file!#] from: [#!variable!host_name!# (#!variable!ip!#). Will look on other hosts (if any left). The file: [#!variable!file!#] on: [#!variable!host_name!# (#!variable!ip!#]) doesn't match the file we're looking for. -- Wanted; md5sum: [#!variable!file_md5sum!#], size: [#!variable!say_file_size!# (#!variable!file_size!# bytes)] -- Found; md5sum: [#!variable!remote_md5sum!#], size: [#!variable!say_remote_size!# (#!variable!remote_size!# bytes)] +- Wanted; size: [#!variable!say_file_size!# (#!variable!file_size!# bytes)] +- Found; size: [#!variable!say_remote_size!# (#!variable!remote_size!# bytes)] We will keep looking. Already searched: [#!variable!host_name!# using another IP address, skipping this IP: [#!variable!ip!#]. Done. @@ -2151,6 +2151,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: The server: [#!variable!server!#] is ready to boot. The server: [#!variable!server!#] was found to be running already, but it wasn't marked as booted. Marking it as if it just booted to handle any dependent servers. The server: [#!variable!server!#] is configured to stay off, ignoring it. + The file: [#!variable!file!#] needs to be added to the database, but since the last scan it's size grew from: [#!variable!old_size_bytes!# (#!variables!old_size_hr!#)] to: [#!variable!new_size_bytes!# (#!variables!new_size_hr!#)]. A difference of: [#!variable!difference_bytes!# (#!variables!difference_hr!#)]. It might still be being uploaded, so we'll keep checking periodocally until the size stops changing. The host name: [#!variable!target!#] does not resolve to an IP address. diff --git a/tools/anvil-manage-files b/tools/anvil-manage-files index 380fa4e5..9197cbed 100755 --- a/tools/anvil-manage-files +++ b/tools/anvil-manage-files @@ -13,10 +13,9 @@ # - If not found anywhere, remove it from 'file_locations' and send an alert. # - If found, check the size. If it differs, recalculate the md5sum. # - 3. If called with '--rename --file --to ', rename the file and update 'files'. -# - 4. If called with '--delete', remove from 'file_locations' and then remove from the local storage. If -# also used with '--everywhere', then all copies on all systems we know about will be deleted. This is -# done by registering a job against all known hosts. As such, if this is called and the target file -# doesn't exist, it just clears the job and then exits. +# - 4. If called with '--delete', remove from 'file_locations' and all copies on all systems. This is done by +# registering a job against all known hosts. As such, if this is called and the target file doesn't exist, +# it just clears the job and then exits. # - 5. If called with '--is-script=[0|1]', mark as 'script' in the 'files' table and set/remove the executable bit. # # Exit codes; @@ -32,7 +31,7 @@ # - # # NOTE: -# - +# - remove unsyncs, add syncs. # use strict; @@ -52,25 +51,11 @@ if (($running_directory =~ /^\./) && ($ENV{PWD})) my $anvil = Anvil::Tools->new(); -$anvil->data->{switches}{'delete'} = ""; -$anvil->data->{switches}{download} = ""; -$anvil->data->{switches}{everywhere} = ""; -$anvil->data->{switches}{file} = ""; -$anvil->data->{switches}{'is-script'} = ""; -$anvil->data->{switches}{'job-uuid'} = ""; -$anvil->data->{switches}{'rename'} = ""; -$anvil->data->{switches}{to} = ""; -$anvil->Get->switches; -$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "switches::delete" => $anvil->data->{switches}{'delete'}, - "switches::download" => $anvil->data->{switches}{download}, - "switches::everywhere" => $anvil->data->{switches}{everywhere}, - "switches::file" => $anvil->data->{switches}{file}, - "switches::is-script" => $anvil->data->{switches}{'is-script'}, - "switches::job-uuid" => $anvil->data->{switches}{'job-uuid'}, - "switches::rename" => $anvil->data->{switches}{'rename'}, - "switches::to" => $anvil->data->{switches}{to}, -}}); +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); + +$anvil->Get->switches({list => ["delete", "download", "file", "is-script", "job-uuid", "rename", "remove", "add", "to"], man => $THIS_FILE}); +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); # Connect or die $anvil->Database->connect; @@ -171,59 +156,59 @@ sub find_missing_files # What am I? This will impact how missing files are found. my $query = " SELECT - a.file_uuid, - a.file_directory, - a.file_name, - a.file_size, - a.file_md5sum + file_uuid, + file_directory, + file_name, + file_size, + file_md5sum FROM - files a, - hosts b, - file_locations c + files WHERE - b.host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -AND - a.file_uuid = c.file_location_file_uuid -AND - b.host_uuid = c.file_location_host_uuid + file_type != 'DELETED' ORDER BY - a.file_directory ASC, - a.file_name ASC, - b.host_name ASC + file_directory ASC, + file_name ASC ;"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }}); + $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 => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { - my $file_uuid = $row->[0]; - my $file_directory = $row->[1]; - my $file_name = $row->[2]; - my $file_size = $row->[3]; - my $file_md5sum = $row->[4]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + my $file_uuid = $row->[0]; + my $file_directory = $row->[1]; + my $file_name = $row->[2]; + my $file_size = $row->[3]; + my $file_md5sum = $row->[4]; + my $full_path = $file_directory."/".$file_name; + $full_path =~ s/\/\//\//g; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:file_uuid' => $file_uuid, 's2:file_directory' => $file_directory, 's3:file_name' => $file_name, + 's4:file_size' => $file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}).")", + 's5:file_md5sum' => $file_md5sum, + 's6:full_path' => $full_path, }}); - my $test_file = $file_directory."/".$file_name; - $test_file =~ s/\/\//\//g; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { test_file => $test_file }}); - - if (not -e $test_file) + # If we're a striker, we want all files. + my $host_type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); + if ($host_type eq "striker") { - # Missing file! - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0269", variables => { file => $test_file }}); - - # Find what target, if any, we'll the file from. - my ($found) = find_file($anvil, $file_uuid, $test_file, $file_size, $file_md5sum); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + if (not -e $full_path) + { + # Missing file! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0269", variables => { file => $full_path }}); + + # Find what target, if any, we'll the file from. + my ($found) = find_file($anvil, $file_uuid, $full_path, $file_size, $file_md5sum); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + } } } @@ -232,338 +217,167 @@ ORDER BY return(0); } -### TODO: Add sorting by preferred target # This looks for a file on another system. The exact order of search depends on what kind of machine we are. sub find_file { my ($anvil, $file_uuid, $full_path, $file_size, $file_md5sum) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:file_uuid' => $file_uuid, + 's2:full_path' => $full_path, + 's3:file_size' => $file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}).")", + 's4:file_md5sum' => $file_md5sum, + }}); my $found = 0; - # What are my IPs? - my $local_host = $anvil->Get->short_host_name(); - $anvil->Network->get_ips(); - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}}) + # We want to search Striker's first, DR hosts second and nodes third. + $anvil->Database->get_hosts; + my $host_order = []; + foreach my $type ("striker", "dr", "node") { - next if not $anvil->data->{network}{$local_host}{interface}{$interface}{ip}; - next if not $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}; - my $ip = $anvil->data->{network}{$local_host}{interface}{$interface}{ip}; - my $subnet_mask = $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}; - my $network = $anvil->Network->get_network({ip => $ip, subnet_mask => $subnet_mask}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - 's1:interface' => $interface, - 's2:ip' => $ip, - 's3:subnet_mask' => $subnet_mask, - 's4:network' => $network, - }}); - - my $type = "other"; - my $sort = $interface; - if ($interface =~ /^((?:bc|s|if)n)(\d+)/) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_name}}) { - $type = $1; - $sort = $2; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - 's1:type' => $type, - 's2:sort' => $sort, + my $host_uuid = $anvil->data->{sys}{hosts}{by_name}{$host_name}; + my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:host_name' => $host_name, + 's2:host_type' => $host_type, + 's3:host_uuid' => $host_uuid, }}); + + next if $host_type ne $type; + next if $host_uuid eq $anvil->Get->host_uuid; + + push @{$host_order}, $host_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }}); } - $anvil->data->{local_ip}{by_network}{$network}{type} = $type; - $anvil->data->{local_ip}{by_network}{$network}{'sort'} = $sort; - $anvil->data->{local_ip}{by_network}{$network}{interface} = $interface; - $anvil->data->{local_ip}{by_network}{$network}{ip} = $ip; - $anvil->data->{local_ip}{by_network}{$network}{subnet_mask} = $subnet_mask; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "s1:local_ip::by_network::${network}::type" => $anvil->data->{local_ip}{by_network}{$network}{type}, - "s1:local_ip::by_network::${network}::sort" => $anvil->data->{local_ip}{by_network}{$network}{'sort'}, - "s2:local_ip::by_network::${network}::interface" => $anvil->data->{local_ip}{by_network}{$network}{interface}, - "s3:local_ip::by_network::${network}::ip" => $anvil->data->{local_ip}{by_network}{$network}{ip}, - "s4:local_ip::by_network::${network}::subnet_mask" => $anvil->data->{local_ip}{by_network}{$network}{subnet_mask}, - }}); } - # Create a hash we can sort through that are on the same subnet_mask as us. - my $query = " -SELECT - a.host_uuid, - a.host_name, - a.host_type, - b.file_directory, - b.file_name, - b.file_size, - b.file_md5sum -FROM - hosts a, - files b, - file_locations c -WHERE - a.host_uuid = c.file_location_host_uuid -AND - b.file_uuid = c.file_location_file_uuid -AND - b.file_uuid = ".$anvil->Database->quote($file_uuid)." -AND - a.host_uuid != ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -ORDER BY - file_mtime DESC; -;"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }}); - my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); - my $count = @{$results}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - results => $results, - count => $count, - }}); - foreach my $row (@{$results}) + # Now search. + my $file_found = 0; + foreach my $search_host_uuid (@{$host_order}) { - my $host_uuid = $row->[0]; - my $host_name = $row->[1]; - my $host_type = $row->[2]; - my $file_directory = $row->[3]; - my $file_name = $row->[4]; - my $file_size = $row->[5]; - my $file_md5sum = $row->[6]; - my $test_file = $file_directory."/".$file_name; - $test_file =~ s/\/\//\//g; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - host_uuid => $host_uuid, - host_name => $host_name, - host_type => $host_type, - file_directory => $file_directory, - file_name => $file_name, - file_size => $file_size, - file_md5sum => $file_md5sum, - test_file => $test_file, + last if $file_found; + my $target_host = $anvil->data->{hosts}{host_uuid}{$search_host_uuid}{short_host_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:search_host_uuid' => $search_host_uuid, + 's2:target_host' => $target_host, }}); - # What IP addresses are on this machine? - my $query = " -SELECT - ip_address_address, - ip_address_subnet_mask -FROM - ip_addresses -WHERE - ip_address_note != 'DELETED' -AND - ip_address_host_uuid = ".$anvil->Database->quote($host_uuid)." -;"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }}); - my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); - my $count = @{$results}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - results => $results, - count => $count, + my $target_ip = $anvil->Network->find_target_ip({host_uuid => $search_host_uuid}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_ip => $target_ip }}); + next if not $target_ip; + + # See if the file is on the target and, if so, if it matches. + ### NOTE: If we want to use md5sum again, use '--with-md5sum' + my $shell_call = $anvil->data->{path}{exe}{'anvil-file-details'}." --file ".$full_path.$anvil->Log->switches; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + # Test access + my $access = $anvil->Remote->test_access({target => $target_ip}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }}); + next if not $access; + + my $remote_size = 0; + my ($output, $error, $return_code) = $anvil->Remote->call({ + shell_call => $shell_call, + target => $target_ip, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + error => $error, + output => $output, + return_code => $return_code, }}); - foreach my $row (@{$results}) + foreach my $line (split/\n/, $output) { - my $ip_address_address = $row->[0]; - my $ip_address_subnet_mask = $row->[1]; - my $network = $anvil->Network->get_network({ip => $ip_address_address, subnet_mask => $ip_address_subnet_mask}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - ip_address_address => $ip_address_address, - ip_address_subnet_mask => $ip_address_subnet_mask, - network => $network, - }}); - - # Are we on the same subnet? - if (exists $anvil->data->{local_ip}{by_network}{$network}) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^size: \[(\d+)\]$/) { - # We're on the same subnet! - my $type = $anvil->data->{local_ip}{by_network}{$network}{type}; - my $sort = $anvil->data->{local_ip}{by_network}{$network}{'sort'}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "s1:type" => $type, - "s2:sort" => $sort, - }}); - - # Record. - $anvil->data->{peer_ip}{$host_type}{$type}{$sort}{ip} = $ip_address_address; - $anvil->data->{peer_ip}{$host_type}{$type}{$sort}{name} = $host_name; - $anvil->data->{peer_ip}{$host_type}{$type}{$sort}{host_uuid} = $host_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "s1:peer_ip::${host_type}::${type}::${sort}::name" => $anvil->data->{peer_ip}{$host_type}{$type}{$sort}{name}, - "s2:peer_ip::${host_type}::${type}::${sort}::ip" => $anvil->data->{peer_ip}{$host_type}{$type}{$sort}{ip}, - "s3:peer_ip::${host_type}::${type}::${sort}::host_uuid" => $anvil->data->{peer_ip}{$host_type}{$type}{$sort}{host_uuid}, + $remote_size = $1; + $found = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + remote_size => $remote_size, + found => $found, }}); } } - } - - ### TODO: Do this according to what we are. - # Sort through what we've found. - my $file_found = 0; - my $searched_hosts = {}; - foreach my $host_type (sort {$a cmp $b} keys %{$anvil->data->{peer_ip}}) - { - last if $file_found; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { host_type => $host_type }}); - foreach my $type (sort {$a cmp $b} keys %{$anvil->data->{peer_ip}{$host_type}}) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:found' => $found, + 's2:remote_size' => $remote_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $remote_size}).")", + 's3:file_size' => $file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}).")", + }}); + next if not $found; + + if ($remote_size eq $file_size) { - last if $file_found; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type => $type }}); - foreach my $sort (sort {$a cmp $b} keys %{$anvil->data->{peer_ip}{$host_type}{$type}}) + # Pull it over! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0276", variables => { + file => $full_path, + host_name => $target_host, + ip => $target_ip, + }}); + my $failed = $anvil->Storage->rsync({ + debug => 2, + destination => $full_path, + source => "root\@".$target_ip.":".$full_path, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); + + if (-f $full_path) { - last if $file_found; - my $ip = $anvil->data->{peer_ip}{$host_type}{$type}{$sort}{ip}; - my $name = $anvil->data->{peer_ip}{$host_type}{$type}{$sort}{name}; - my $host_uuid = $anvil->data->{peer_ip}{$host_type}{$type}{$sort}{host_uuid}; - my $remote_user = "admin"; - my $password = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:host_type' => $host_type, - 's2:type' => $type, - 's3:sort' => $sort, - 's4:name' => $name, - 's5:ip' => $ip, - 's6:host_uuid' => $host_uuid, - 's7:remote_user' => $remote_user, - 's8:password' => $password, - }}); - - if ((exists $searched_hosts->{$name}) && ($searched_hosts->{$name})) - { - # Already searched this host, this is just a different IP. Skip it. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "log_0282", variables => { - host_name => $name, - ip => $ip, - }}); - next; - } - $searched_hosts->{$name} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { "searched_hosts->{$name}" => $searched_hosts->{$name} }}); + # Got it! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0277", variables => { file => $full_path }}); - ### NOTE: There's a bug in Net::SSH2 on RHEL8 where passwordless SSH doesn't - ### work. So for now, we'll manually pull in passwords from the - ### anvil.conf using 'hosts::::password' or - ### 'hosts::::password'. This will be removed when the bug - ### is fixed. - if ((exists $anvil->data->{hosts}{$host_uuid}{password}{$remote_user}) && ($anvil->data->{hosts}{$host_uuid}{password}{$remote_user})) - { - $password = $anvil->data->{hosts}{$host_uuid}{password}{$remote_user}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 1, list => { password => $password }}); - } - elsif ((exists $anvil->data->{hosts}{$name}{password}{$remote_user}) && ($anvil->data->{hosts}{$name}{password}{$remote_user})) - { - $password = $anvil->data->{hosts}{$host_uuid}{password}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 1, list => { password => $password }}); - } - - ### NOTE: This might take a while for the call to return if we're md5sum'ing - ### a large file like an ISO. - ### TODO: Should we ask for the size, then follow up with the md5sum for - ### files that are over a certain size? Or will this get called rarely - ### enough in practice that it doesn't really matter? - # If the file is found, we'll parse these out. - my $remote_size = 0; - my $remote_md5sum = ""; - my ($output, $error, $return_code) = $anvil->Remote->call({ - shell_call => $anvil->data->{path}{exe}{'anvil-file-details'}." --file ".$full_path." --with-md5sum".$anvil->Log->switches, - remote_user => $remote_user, - password => $password, - target => $ip, - }); + # Verify the md5sum. + my $local_md5sum = $anvil->Get->md5sum({file => $full_path}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - error => $error, - output => $output, - return_code => $return_code, + local_md5sum => $local_md5sum, + file_md5sum => $file_md5sum, }}); - foreach my $line (split/\n/, $output) + if ($local_md5sum eq $file_md5sum) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); - if ($line =~ /^size: \[(\d+)\]$/) - { - $remote_size = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { remote_size => $remote_size }}); - } - if ($line =~ /^md5sum: \[(.*)\]$/) - { - $remote_md5sum = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { remote_md5sum => $remote_md5sum }}); - } - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:remote_size' => $remote_size, - 's2:file_size' => $file_size, - 's3:remote_md5sum' => $remote_md5sum, - 's4:file_md5sum' => $file_md5sum, - }}); - - ### Do I really need to match sizes if the md5sum is the same? - if (($remote_size eq $file_size) && ($remote_md5sum eq $file_md5sum)) - { - # Pull it over! - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0276", variables => { - file => $full_path, - host_name => $name, - ip => $ip, - }}); - my $failed = $anvil->Storage->rsync({ - debug => 2, - destination => $full_path, - password => $password, - source => $remote_user."\@".$ip.":".$full_path, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); + # Success! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0278", variables => { file => $full_path }}); - if (-f $full_path) - { - # Got it! - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0277", variables => { file => $full_path }}); - - # Verify the md5sum. - my $local_md5sum = $anvil->Get->md5sum({file => $full_path}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - local_md5sum => $local_md5sum, - file_md5sum => $file_md5sum, - }}); - if ($local_md5sum eq $file_md5sum) - { - # Success! - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0278", variables => { file => $full_path }}); - - $file_found = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_found => $file_found }}); - last; - } - else - { - # Failed. :( - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0279", variables => { file => $full_path }}); - unlink $full_path; - } - } - else - { - # Failed to rsync. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0280", variables => { - file => $full_path, - host_name => $name, - ip => $ip, - }}); - } + $file_found = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_found => $file_found }}); + last; } else { - # Doesn't match what we're looking for. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0281", variables => { - file => $full_path, - host_name => $name, - ip => $ip, - remote_md5sum => $remote_md5sum, - file_md5sum => $file_md5sum, - file_size => $file_size, - say_file_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}), - remote_size => $remote_size, - say_remote_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $remote_size}), - }}); + # Failed. :( + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0279", variables => { file => $full_path }}); + unlink $full_path; } } + else + { + # Failed to rsync. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0280", variables => { + file => $full_path, + host_name => $target_host, + ip => $target_ip, + }}); + } + } + else + { + # Doesn't match what we're looking for. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0281", variables => { + file => $full_path, + host_name => $target_host, + ip => $target_ip, + file_size => $file_size, + say_file_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}), + remote_size => $remote_size, + say_remote_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $remote_size}), + }}); } } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); - return($found); + return($file_found); } @@ -577,6 +391,7 @@ sub check_incoming { delete $anvil->data->{scan}{directories}; } + # Read any files in '/mnt/shared/incoming'. $anvil->Storage->scan_directory({ debug => 3, @@ -600,13 +415,15 @@ sub check_incoming }}); next if $file_type ne "file"; - my $file_name = $anvil->data->{scan}{directories}{$full_path}{name}; - my $file_directory = $anvil->data->{scan}{directories}{$full_path}{directory}; - my $file_size = $anvil->data->{scan}{directories}{$full_path}{size}; - my $file_mtime = $anvil->data->{scan}{directories}{$full_path}{mtime}; - my $file_mimetype = $anvil->data->{scan}{directories}{$full_path}{mimetype}; - my $file_executable = $anvil->data->{scan}{directories}{$full_path}{executable} = -x $full_path ? 1 : 0; - my $say_mimetype = convert_mimetype($anvil, $file_mimetype, $full_path, $file_executable); + my $file_name = $anvil->data->{scan}{directories}{$full_path}{name}; + my $file_directory = $anvil->data->{scan}{directories}{$full_path}{directory}; + my $file_size = $anvil->data->{scan}{directories}{$full_path}{size}; + my $file_mtime = $anvil->data->{scan}{directories}{$full_path}{mtime}; + my $file_mimetype = $anvil->data->{scan}{directories}{$full_path}{mimetype}; + my $file_executable = $anvil->data->{scan}{directories}{$full_path}{executable} = -x $full_path ? 1 : 0; + my $say_mimetype = convert_mimetype($anvil, $file_mimetype, $full_path, $file_executable); + my $full_path = $file_directory."/".$file_name; + $full_path =~ s/\/\//\//g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file_name => $file_name, file_size => $file_size, @@ -614,6 +431,7 @@ sub check_incoming file_mimetype => $file_mimetype, file_executable => $file_executable, say_mimetype => $say_mimetype, + full_path => $full_path, }}); # Do I know about this file? If so, is the file the same size? If either is no, calculate the md5sum. @@ -626,11 +444,22 @@ sub check_incoming }}); # Calculate the md5sum? - my $file_md5sum = $recorded_md5sum; + my $file_md5sum = $recorded_md5sum; if ((not $file_uuid) or ($file_size != $recorded_size)) { - # Yes. But first, do we have a size mismatch? If so, see if we need to pull a newer - # version down from elsewhere. + # It's possible the file is still uploading, so sleep for 2 seconds and see if the + # size is still changing. + my $last_size = $file_size; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + last_size => $last_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $last_size}).")", + }}); + $anvil->Storage->_wait_if_changing({ + file => $full_path, + last_size => $file_size, + }); + + # Yes, caluclate md5sum, but first, do we have a size mismatch? If so, see if we need + # to pull a newer version down from elsewhere. if (($file_uuid) && ($file_mtime <= $recorded_mtime)) { # We've got an older file, we need to update. @@ -675,14 +504,6 @@ sub check_incoming $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file_uuid => $file_uuid }}); next if not $file_uuid; - # Make sure we know about this file on this system - my ($file_locatiom_uuid) = $anvil->Database->insert_or_update_file_locations({ - debug => 3, - file_location_file_uuid => $file_uuid, - file_location_host_uuid => $anvil->data->{sys}{host_uuid}, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file_locatiom_uuid => $file_locatiom_uuid }}); - # Are we in the incoming directory? If so, move the file. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { full_path => $full_path, @@ -694,14 +515,21 @@ sub check_incoming # 'path::directories::shared::definitions', otherwise we'll move it to # 'path::directories::shared::files'. my $target = $say_mimetype eq "definition" ? $anvil->data->{path}{directories}{shared}{definitions} : $anvil->data->{path}{directories}{shared}{files}; - $target .= "/"; - $target =~ s/\/\//\//g; + $target .= "/"; + $target =~ s/\/\//\//g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { target => $target }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0268", variables => { file => $full_path, target => $target, }}); + + # Wait in case it's still being uploaded. + $anvil->Storage->_wait_if_changing({ + file => $full_path, + last_size => $file_size, + }); + $anvil->Storage->move_file({ debug => 3, source_file => $full_path, @@ -975,47 +803,31 @@ sub convert_mimetype return($say_mimetype); } -# This looks for any files with the file_type of 'DELETED' and that has an entry in file_locations for this -# machine. Any that are found will have their file deleted and the file_locations entry deleted. +# This looks for any files with the file_type of 'DELETED'. Any that are found will be deleted. sub check_for_deletes { my ($anvil) = @_; - my $query = " -SELECT - a.file_uuid, - b.file_location_uuid, - a.file_directory || '/' || a.file_name AS full_path -FROM - files a, - file_locations b -WHERE - a.file_uuid = b.file_location_file_uuid -AND - a.file_type = 'DELETED' -AND - b.file_location_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -;"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }}); + # Get a list of files. + my $query = "SELECT file_uuid, file_directory || '/' || file_name AS full_path FROM files WHERE file_type = 'DELETED';"; + $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 => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { - my $file_uuid = $row->[0]; - my $file_location_uuid = $row->[1]; - my $full_path = $row->[2]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - 's1:file_uuid' => $file_uuid, - 's2:file_location_uuid' => $file_location_uuid, - 's3:full_path' => $full_path, + my $file_uuid = $row->[0]; + my $full_path = $row->[1]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:file_uuid' => $file_uuid, + 's2:full_path' => $full_path, }}); - # Get rid of it (if it actually exists) and then remove it from file_locations. + # Get rid of it (if it actually exists). if (-e $full_path) { # Delete it. @@ -1038,10 +850,35 @@ AND } } - # Delete the entry from file_locations, if needed. - $query = "DELETE FROM file_locations WHERE file_location_uuid = ".$anvil->Database->quote($file_location_uuid).";"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); - $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); + # If we're a Striker, check for any file_locations that point to this file and DELETE them. + my $host_type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); + if ($host_type eq "striker") + { + my $query = "SELECT file_location_uuid FROM file_locations WHERE file_location_file_uuid = ".$anvil->Database->quote($file_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); + my $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + results => $results, + count => $count, + }}); + foreach my $row (@{$results}) + { + my $file_location_uuid = $row->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_location_uuid => $file_location_uuid }}); + + # Delete the entry from file_locations, if needed. + my $query = "DELETE FROM history.file_locations WHERE file_location_uuid = ".$anvil->Database->quote($file_location_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); + + $query = "DELETE FROM file_locations WHERE file_location_uuid = ".$anvil->Database->quote($file_location_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); + } + } } return(0); @@ -1061,7 +898,7 @@ sub handle_delete # Um... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0052"}); $anvil->Job->update_progress({ - progress => 0, + progress => 100, message => "error_0052", job_uuid => $anvil->data->{jobs}{'job-uuid'}, }); @@ -1072,7 +909,7 @@ sub handle_delete # We don't do that here... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0053", variables => { file => $full_path }}); $anvil->Job->update_progress({ - progress => 0, + progress => 100, message => "error_0053,!!file!".$full_path."!!", job_uuid => $anvil->data->{jobs}{'job-uuid'}, }); @@ -1126,7 +963,7 @@ AND # database. This way, if anything goes wrong below, future runs will try (again) to delete the file # itself. If it's only beind deleted locally, and it fails for some reason, there will be no attempt # to try again. - if (($file_uuid) && ($anvil->data->{switches}{everywhere})) + if ($file_uuid) { # Yup. ($file_uuid) = $anvil->Database->insert_or_update_files({ @@ -1164,18 +1001,13 @@ AND } } - # Now, if I have a file_uuid, delete it from file_locations if it exists. + # Now, if I have a file_uuid, delete it from file_locations if it exists. It's ok if peers in an + # Anvil! haven't deleted yet, as they'll see the file marked as 'DELETED' and purge their local + # copies. if ($file_uuid) { # Delete the entry from file_locations, if needed. - my $query = " -DELETE FROM - file_locations -WHERE - file_location_file_uuid = ".$anvil->Database->quote($file_uuid)." -AND - file_location_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -;"; + my $query = "DELETE FROM file_locations WHERE file_location_file_uuid = ".$anvil->Database->quote($file_uuid).";"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); } From e7cf8ac789bdaff1b6dfce1050144e349df19658 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 9 Aug 2022 00:08:19 -0400 Subject: [PATCH 2/8] * Got more work done on anvil-manage-files. It now picks up new files on nodes/dr hosts in an Anvil! and downloads them if needed. * Updated anvil-daemon to call anvil-manage-files on a per-minute basis to handle files added outside of the WebUI. Signed-off-by: Digimer --- Anvil/Tools.pm | 1 + Anvil/Tools/Database.pm | 4 +-- share/words.xml | 2 +- tools/anvil-daemon | 78 ++++++++-------------------------------- tools/anvil-manage-files | 71 ++++++++++++++++++++++++++++++++---- 5 files changed, 83 insertions(+), 73 deletions(-) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index f10dd624..aecb7394 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1111,6 +1111,7 @@ sub _set_paths 'anvil-join-anvil' => "/usr/sbin/anvil-join-anvil", 'anvil-maintenance-mode' => "/usr/sbin/anvil-maintenance-mode", 'anvil-manage-dr' => "/usr/sbin/anvil-manage-dr", + 'anvil-manage-files' => "/usr/sbin/anvil-manage-files", 'anvil-manage-firewall' => "/usr/sbin/anvil-manage-firewall", 'anvil-manage-keys' => "/usr/sbin/anvil-manage-keys", 'anvil-manage-power' => "/usr/sbin/anvil-manage-power", diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 1d41a8ab..217cf7ab 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -381,7 +381,7 @@ sub backup_database =head2 check_file_locations -This method checks to see that there is a corresponding entry in C<< file_locations >> for all Anvil! systems and files in the database. Any that are found to be missing will be set to C<< file_location_active >> -> c<< false >>. +This method checks to see that there is a corresponding entry in C<< file_locations >> for all Anvil! systems and files in the database. Any that are found to be missing will be set to C<< file_location_active >> -> c<< true >>. This method takes no parameters. @@ -420,7 +420,7 @@ sub check_file_locations debug => $debug, file_location_file_uuid => $file_uuid, file_location_anvil_uuid => $anvil_uuid, - file_location_active => 0, + file_location_active => 1, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_location_uuid => $file_location_uuid }}); } diff --git a/share/words.xml b/share/words.xml index f71947ee..2bec97df 100644 --- a/share/words.xml +++ b/share/words.xml @@ -1670,7 +1670,7 @@ We will keep looking. Already searched: [#!variable!host_name!# using another IP address, skipping this IP: [#!variable!ip!#]. Done. [ Error ] - Failed to remove the file: [#!variable!file!#]! Please check the permissions or for SELinux denials. - As requested by another machine, we will now delete the file: [#!variable!file!#]. + The file: [#!variable!file!#] is marked as not sync'ed to this Anvil!, removing it now. [ Error ] - The URL: [#!variable!url!#] to download appears to be invalid. [ Error ] - The requested URL: [#!variable!url!#] was not found on the remote server. [ Error ] - The requested URL: [#!variable!url!#] does not resolve to a known domain. diff --git a/tools/anvil-daemon b/tools/anvil-daemon index e6a2524c..bcac6dd9 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -582,7 +582,7 @@ sub handle_periodic_tasks my $problem = $anvil->Email->check_config({debug => 3}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { problem => $problem }}); - # Check if any files have been uploaded to /mnt/shared/incoming on striker + # Check if anything is needed to be done in /mnt/shared. check_incoming($anvil); # Check for stale db_in_use states. @@ -823,73 +823,23 @@ AND return(0); } -# On dashboards, this checks to see if any files are in /mnt/shared/incoming and, if so, that they've been processed. +# This checks to see if any files in /mnt/shared need to be dealt with, like incorporating files in +# /mnt/shared/incoming, etc. sub check_incoming { my ($anvil) = @_; - my $system_type = $anvil->Get->host_type(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { system_type => $system_type }}); - if ($system_type eq "striker") - { - # Look for files in /mnt/shared/incoming that are not yet in the database. - my $directory = $anvil->data->{path}{directories}{shared}{incoming}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }}); - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }}); - local(*DIRECTORY); - opendir(DIRECTORY, $directory); - while(my $file = readdir(DIRECTORY)) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }}); - next if $file eq "."; - next if $file eq ".."; - next if $file =~ /^\./; # This is files being rsync'ed still - my $full_path = $directory."/".$file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }}); - - # Skip anything that is not a file. - next if not -f $full_path; - - # Is this file already in the DB? - my $query = "SELECT file_uuid FROM files WHERE file_name = ".$anvil->Database->quote($file).";"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { 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, - }}); - if (not $count) - { - # Add it to the database. - my $size = (stat($full_path))[7]; - my $say_size_human = $anvil->Convert->bytes_to_human_readable({'bytes' => $size}); - my $say_size_comma = $anvil->Convert->add_commas({number => $size}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - size => $size, - say_size_human => $say_size_human, - say_size_comma => $say_size_comma, - }}); - - # Register a job to call anvil-sync-shared - my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ - file => $THIS_FILE, - line => __LINE__, - job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'}, - job_data => "file=".$full_path, - job_name => "storage::move_incoming", - job_title => "job_0132", - job_description => "job_0133", - job_progress => 0, - job_host_uuid => $anvil->data->{sys}{host_uuid}, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); - } - - } - closedir(DIRECTORY); - } + my $shell_call = $anvil->data->{path}{exe}{'anvil-manage-files'}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + my ($output, $return_code) = $anvil->System->call({ + shell_call => $shell_call, + source => $THIS_FILE, + line => __LINE__, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); return(0); } diff --git a/tools/anvil-manage-files b/tools/anvil-manage-files index 9197cbed..31fe37fc 100755 --- a/tools/anvil-manage-files +++ b/tools/anvil-manage-files @@ -51,9 +51,6 @@ if (($running_directory =~ /^\./) && ($ENV{PWD})) my $anvil = Anvil::Tools->new(); -$anvil->Log->level({set => 2}); -$anvil->Log->secure({set => 1}); - $anvil->Get->switches({list => ["delete", "download", "file", "is-script", "job-uuid", "rename", "remove", "add", "to"], man => $THIS_FILE}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); @@ -154,6 +151,8 @@ sub find_missing_files my ($anvil) = @_; # What am I? This will impact how missing files are found. + $anvil->Database->get_anvils(); + my $query = " SELECT file_uuid, @@ -209,11 +208,68 @@ ORDER BY my ($found) = find_file($anvil, $file_uuid, $full_path, $file_size, $file_md5sum); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); } + + # If we're a Striker, see if any Anvil! systems exist that don't know about this file. + $anvil->Database->check_file_locations({debug => 2}); + } + else + { + # Check to see if we're supposed to have this file. + $anvil->Database->get_file_locations(); + my $anvil_uuid = $anvil->Cluster->get_anvil_uuid(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }}); + + # Nothing to do if we're not in an Anvil! yet. + next if not $anvil_uuid; + + # Do we have a file_location_uuid? If not, there will be soon but nothing to do until + # then. + my $file_location_uuid = $anvil->data->{file_locations}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_location_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_location_uuid => $file_location_uuid }}); + next if not $file_location_uuid; + + # Should we have it? + my $file_location_active = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_location_active => $file_location_active }}); + + if ($file_location_active) + { + # Make sure it exists, and add it if not. + if (not -e $full_path) + { + # Find and copy it. + my ($found) = find_file($anvil, $file_uuid, $full_path, $file_size, $file_md5sum); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + } + } + else + { + # If it exists, remove it. + if (-e $full_path) + { + # Delete it. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0285", variables => { file => $full_path }}); + + unlink $full_path; + + # Sleep and verify + sleep 1; + if (-e $full_path) + { + # Failed to delete... + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0284", variables => { file => $full_path }}); + return(""); + } + else + { + # Deleted successfully. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0283"}); + } + } + } } } - ### TODO: Left off here. - return(0); } @@ -400,7 +456,7 @@ sub check_incoming }); my $incoming_directory = $anvil->data->{path}{directories}{shared}{incoming}; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0264"}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0264"}); foreach my $full_path (sort {$a cmp $b} keys %{$anvil->data->{scan}{directories}}) { # Skip this if it's under '/mnt/shared/temp' (that's used for files being downloaded, etc) @@ -511,6 +567,9 @@ sub check_incoming }}); if ($full_path =~ /^$incoming_directory/) { + # Ignore files starting with '.', they're often in-progress rsync's. + next if $file_name =~ /^\./; + # If it's a definition file, we'll move it to # 'path::directories::shared::definitions', otherwise we'll move it to # 'path::directories::shared::files'. From a81478f2bc9f38ce5a4b9ec7c96bed2cf778689d Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 9 Aug 2022 00:29:03 -0400 Subject: [PATCH 3/8] * Updated 'db_in_use' state to add the caller's name to the state name. This is pulled out when logging stale locks that are being reaped, to help debug where stale locks are coming from. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 2 +- share/words.xml | 2 +- tools/anvil-daemon | 19 +++++++++++++++---- tools/anvil-manage-files | 2 +- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 217cf7ab..284c77dd 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -15382,7 +15382,7 @@ sub mark_active # Record that we're using each available striker DB UUID. foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) { - my $state_name = "db_in_use::".$uuid."::".$$; + my $state_name = "db_in_use::".$uuid."::".$$."::".$ENV{_}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { set => $set, state_name => $state_name, diff --git a/share/words.xml b/share/words.xml index 2bec97df..aa3f4939 100644 --- a/share/words.xml +++ b/share/words.xml @@ -3249,7 +3249,7 @@ We will sleep a bit and try again. [ Warning ] - Timed out waiting for the connections to the peers, and the local resource(s) is not in 'UpToDate' state. Booting the server will likely fail. [ Warning ] - Timed out waiting for the connections to the peers. [ Warning ] - We're using: [#!variable!ram_used!#] (#!variable!ram_used_bytes!# Bytes). but there is a job: [#!variable!job_command!#] is runnng, which might be why the RAM is high. NOT exiting while this program is running. - [ Warning ] - A no-longer active PID: [#!variable!pid!#] had marked the database: [#!variable!db!#] as "in_use", but the PID is gone now. Reaping the flag. + [ Warning ] - A no-longer active PID: [#!variable!pid!#] (used by: [#!variable!caller!#] had marked the database: [#!variable!db!#] as "in_use", but the PID is gone now. Reaping the flag. [ Warning ] - We waited for: [#!variable!wait_time!#] seconds for all users of the local database to exit. Giving up waiting and taking the database down now. [ Warning ] - The command: [#!variable!command!#] is still using our database. [ Warning ] - While evaluating database shutdown, the host UUID: [#!variable!host_uuid!#] was not yet found in the database on host: [#!variable!db_uuid!#]. DB shutdown will not happen until all hosts are in all DBs. diff --git a/tools/anvil-daemon b/tools/anvil-daemon index bcac6dd9..1aca4513 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -799,18 +799,29 @@ AND 's3:state_note' => $state_note, }}); - my ($db_uuid, $state_pid) = ($state_name =~ /db_in_use::(.*?)::(\d+)$/); + my $caller = ""; + my ($db_uuid, $state_pid) = ($state_name =~ /db_in_use::(.*?)::(.*)$/); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:db_uuid' => $anvil->Get->host_name_from_uuid({host_uuid => $db_uuid})." (".$db_uuid.")", - 's4:state_pid' => $state_pid, + 's2:state_pid' => $state_pid, }}); + if ($state_pid =~ /(\d+)::(.*)$/) + { + $state_pid = $1; + $caller = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:state_pid' => $state_pid, + 's2:caller' => $caller, + }}); + } if (not exists $anvil->data->{pids}{$state_pid}) { # Reap the 'db_is_use'. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0140", variables => { - db => $anvil->Get->host_name_from_uuid({host_uuid => $db_uuid})." (".$db_uuid.")", - pid => $state_pid, + db => $anvil->Get->host_name_from_uuid({host_uuid => $db_uuid})." (".$db_uuid.")", + pid => $state_pid, + 'caller' => $caller, }}); my $query = "DELETE FROM states WHERE state_uuid = ".$anvil->Database->quote($state_uuid).";"; diff --git a/tools/anvil-manage-files b/tools/anvil-manage-files index 31fe37fc..0e13beac 100755 --- a/tools/anvil-manage-files +++ b/tools/anvil-manage-files @@ -456,7 +456,7 @@ sub check_incoming }); my $incoming_directory = $anvil->data->{path}{directories}{shared}{incoming}; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0264"}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0264"}); foreach my $full_path (sort {$a cmp $b} keys %{$anvil->data->{scan}{directories}}) { # Skip this if it's under '/mnt/shared/temp' (that's used for files being downloaded, etc) From 21738ab0d4535159b5c16ad6c65a0b4ae9bc1f16 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 9 Aug 2022 01:02:59 -0400 Subject: [PATCH 4/8] Added a bit more logging to the Database->mark_active method. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 5 ++++- tools/anvil-daemon | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 284c77dd..bdb405f5 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -15379,10 +15379,13 @@ sub mark_active return(0); } + my $caller = $ENV{_}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'caller' => $caller }}); + # Record that we're using each available striker DB UUID. foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) { - my $state_name = "db_in_use::".$uuid."::".$$."::".$ENV{_}; + my $state_name = "db_in_use::".$uuid."::".$$."::".$caller; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { set => $set, state_name => $state_name, diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 1aca4513..74ab578f 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -818,6 +818,7 @@ AND if (not exists $anvil->data->{pids}{$state_pid}) { # Reap the 'db_is_use'. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { state_name => $state_name }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0140", variables => { db => $anvil->Get->host_name_from_uuid({host_uuid => $db_uuid})." (".$db_uuid.")", pid => $state_pid, From ef3ac861628410acec611cd755ad60e63005ac15 Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 9 Aug 2022 15:45:10 -0400 Subject: [PATCH 5/8] * Fixed a bug where setting the db_in_use flag without a valid $ENV{_}. * Added a nice_exit call to tools/striker-access-database Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 2 +- scancore-agents/scan-lvm/scan-lvm | 1 + tools/anvil-daemon | 2 +- tools/anvil-manage-files | 19 +++++++++++++++++-- tools/striker-access-database | 1 + 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index bdb405f5..35b9a8a0 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -15379,7 +15379,7 @@ sub mark_active return(0); } - my $caller = $ENV{_}; + my $caller = $ENV{_} ? $ENV{_} : "unknown"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'caller' => $caller }}); # Record that we're using each available striker DB UUID. diff --git a/scancore-agents/scan-lvm/scan-lvm b/scancore-agents/scan-lvm/scan-lvm index 872f63a0..9b41a252 100755 --- a/scancore-agents/scan-lvm/scan-lvm +++ b/scancore-agents/scan-lvm/scan-lvm @@ -86,6 +86,7 @@ find_changes($anvil); # Shut down. $anvil->ScanCore->agent_shutdown({agent => $THIS_FILE}); +$anvil->nice_exit({exit_code => 0}); ############################################################################################################# diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 74ab578f..8312cbb8 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -841,7 +841,7 @@ sub check_incoming { my ($anvil) = @_; - my $shell_call = $anvil->data->{path}{exe}{'anvil-manage-files'}; + my $shell_call = $anvil->data->{path}{exe}{'anvil-manage-files'}." --check"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); my ($output, $return_code) = $anvil->System->call({ shell_call => $shell_call, diff --git a/tools/anvil-manage-files b/tools/anvil-manage-files index 0e13beac..083153c8 100755 --- a/tools/anvil-manage-files +++ b/tools/anvil-manage-files @@ -51,7 +51,7 @@ if (($running_directory =~ /^\./) && ($ENV{PWD})) my $anvil = Anvil::Tools->new(); -$anvil->Get->switches({list => ["delete", "download", "file", "is-script", "job-uuid", "rename", "remove", "add", "to"], man => $THIS_FILE}); +$anvil->Get->switches({list => ["add", "check", "delete", "download", "file", "is-script", "job-uuid", "rename", "remove", "to"], man => $THIS_FILE}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); # Connect or die @@ -106,7 +106,7 @@ elsif ($anvil->data->{switches}{'is-script'}) { handle_script($anvil); } -else +elsif ($anvil->data->{switches}{check}) { # Check for files scheduled for deletion. check_for_deletes($anvil); @@ -117,6 +117,11 @@ else # Check for files we should have but don't yet have. find_missing_files($anvil); } +else +{ + # Show the list of all files we know about. + show_files($anvil); +} # We're done $anvil->nice_exit({exit_code => 0}); @@ -126,6 +131,16 @@ $anvil->nice_exit({exit_code => 0}); # Private functions. # ############################################################################################################# +# This lists all files. +sub show_files +{ + my ($anvil) = @_; + + + + return(0); +} + # This looks to see if there are any entries in 'file_locations' for us that, the pointed to file, doesn't # exist on this machine. For those entries, we will search for the file on other machines. The one exception # is server definition files. For those, we write the file out from the server's 'definition' table entry. diff --git a/tools/striker-access-database b/tools/striker-access-database index 3aa82f9f..81768545 100755 --- a/tools/striker-access-database +++ b/tools/striker-access-database @@ -74,3 +74,4 @@ else $anvil->nice_exit({ exit_code => 1 }); } +$anvil->nice_exit({ exit_code => 0 }); From 4ecc6097d33092a627c0b1a559a9a8567a1b7634 Mon Sep 17 00:00:00 2001 From: Digimer Date: Fri, 12 Aug 2022 16:32:20 -0400 Subject: [PATCH 6/8] * Cleaned up some old 'die' calls with better nice_exit() calls to help avoid dangling db_in_use flags. * Reworked Network->bridge_info() to use 'ip' to get the list of bridges, and 'bridge' to find interfaces connected to the bridge. * Added 'test' messages to Words->string(). * Fixed a bug in scan-lvm where mdadm based PVs didn't read the sector size properly. Signed-off-by: Digimer --- Anvil/Tools.pm | 7 +- Anvil/Tools/Database.pm | 9 +- Anvil/Tools/Get.pm | 12 +- Anvil/Tools/Log.pm | 14 +- Anvil/Tools/Network.pm | 123 +++++++++++++++--- Anvil/Tools/Remote.pm | 9 +- Anvil/Tools/Words.pm | 63 +++++++-- scancore-agents/scan-drbd/scan-drbd | 12 +- scancore-agents/scan-drbd/scan-drbd.xml | 4 + scancore-agents/scan-ipmitool/scan-ipmitool | 13 +- .../scan-ipmitool/scan-ipmitool.xml | 3 + scancore-agents/scan-lvm/scan-lvm | 91 ++++++++++--- scancore-agents/scan-lvm/scan-lvm.xml | 3 + scancore-agents/scan-network/scan-network | 23 +--- scancore-agents/scan-network/scan-network.xml | 2 + tools/anvil-update-states | 14 -- 16 files changed, 298 insertions(+), 104 deletions(-) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index aecb7394..2335d59b 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -415,6 +415,7 @@ sub nice_exit $anvil->data->{HANDLE}{'log'}{main} = ""; } + #print "Exiting with RC: [".$exit_code."]\n"; exit($exit_code); } @@ -772,7 +773,11 @@ sub _get_hash_reference my $parameter = shift; my $anvil = $self; - die "$THIS_FILE ".__LINE__."; The hash key string: [".$parameter->{key}."] doesn't seem to be valid. It should be a string in the format 'foo::bar::baz'.\n" if $parameter->{key} !~ /::/; + if ($parameter->{key} !~ /::/) + { + print "$THIS_FILE ".__LINE__."; The hash key string: [".$parameter->{key}."] doesn't seem to be valid. It should be a string in the format 'foo::bar::baz'.\n"; + $anvil->nice_exit({exit_code => 1}); + } # Split up the keys. my $key = $parameter->{key} ? $parameter->{key} : ""; diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 35b9a8a0..ca529f15 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -1644,7 +1644,6 @@ sub connect query => $query, }}); $anvil->nice_exit({exit_code => 1}); - die; } # Check to see if the schema needs to be loaded. @@ -2711,7 +2710,7 @@ WHERE next if not exists $anvil->data->{files}{file_uuid}{$file_uuid}; my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_uuid => $file_uuid, file_name => $file_name, }}); @@ -2723,7 +2722,7 @@ WHERE $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_size}; $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_md5sum} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_md5sum}; $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_type}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_name" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_name}, "anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_directory" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_directory}, "anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_size" => $anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size}})." (".$anvil->Convert->add_commas({number => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size}}).")", @@ -2733,7 +2732,7 @@ WHERE # Make it so that we can list the files by name. $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid} = $file_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "anvils::anvil_uuid::${anvil_uuid}::file_name::${file_name}::file_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid}, }}); } @@ -16447,7 +16446,6 @@ sub resync_databases { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0114", variables => { query => $query }}); $anvil->nice_exit({exit_code => 1}); - die; } # If we don't have a row uuid, something has also gone wrong... @@ -16458,7 +16456,6 @@ sub resync_databases query => $query, }}); $anvil->nice_exit({exit_code => 1}); - die; } # Record this in the unified and local hashes. diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 6b56ef5d..e272bda2 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -791,11 +791,11 @@ sub bridges if (not $test) { # JSON parse failed. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "error_0140", variables => { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "error_0140", variables => { json => $output, error => $@, }}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0519"}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0519"}); # NOTE: This is not design to be normally used. It was created as a stop-gap while waiting # for resolution on: https://bugzilla.redhat.com/show_bug.cgi?id=1868467 @@ -1027,7 +1027,7 @@ sub cgi if (not $cgi->upload('upload_file')) { # Empty file passed, looks like the user forgot to select a file to upload. - $anvil->Log->entry({log_level => 2, message_key => "log_0242", file => $THIS_FILE, line => __LINE__}); + $anvil->Log->entry({level => 2, message_key => "log_0242", file => $THIS_FILE, line => __LINE__}); } else { @@ -1183,11 +1183,13 @@ sub date_and_time # Are things sane? if ($use_time =~ /D/) { - die "Get->date_and_time() was called with 'use_time' set to: [$use_time]. Only a unix timestamp is allowed.\n"; + warn "Get->date_and_time() was called with 'use_time' set to: [$use_time]. Only a unix timestamp is allowed.\n"; + $anvil->nice_exit({exit_code => 1}); } if ($offset =~ /D/) { - die "Get->date_and_time() was called with 'offset' set to: [$offset]. Only real number is allowed.\n"; + warn "Get->date_and_time() was called with 'offset' set to: [$offset]. Only real number is allowed.\n"; + $anvil->nice_exit({exit_code => 1}); } # Do my initial calculation. diff --git a/Anvil/Tools/Log.pm b/Anvil/Tools/Log.pm index 088628d4..d93b6a22 100644 --- a/Anvil/Tools/Log.pm +++ b/Anvil/Tools/Log.pm @@ -481,7 +481,7 @@ sub entry my $shell_call = $log_file; print $THIS_FILE." ".__LINE__."; shell_call: [".$shell_call."]\n" if $test; # NOTE: Don't call '$anvil->Log->entry()' here, it will cause a loop! - open (my $file_handle, ">>", $shell_call) or die "Failed to open: [$shell_call] for writing. The error was: $!\n"; + open (my $file_handle, ">>", $shell_call) or die "Failed to open: [".$shell_call."] for writing. The error was: $!\n"; $file_handle->autoflush(1); $anvil->data->{HANDLE}{'log'}{main} = $file_handle; binmode($anvil->data->{HANDLE}{'log'}{main}, ':encoding(utf-8)'); @@ -494,7 +494,8 @@ sub entry if (not $anvil->data->{HANDLE}{'log'}{main}) { # NOTE: This can't be a normal error because we can't write to the logs. - die $THIS_FILE." ".__LINE__."; log main file handle doesn't exist, but it should by now.\n"; + print $THIS_FILE." ".__LINE__."; log main file handle doesn't exist, but it should by now.\n"; + exit 1; } # The handle has to be wrapped in a block to make 'print' happy as it doesn't like non-scalars for file handles @@ -533,7 +534,8 @@ sub entry if (not $anvil->data->{HANDLE}{'log'}{alert}) { # NOTE: This can't be a normal error because we can't write to the logs. - die $THIS_FILE." ".__LINE__."; log alert file handle doesn't exist, but it should by now.\n"; + print $THIS_FILE." ".__LINE__."; log alert file handle doesn't exist, but it should by now.\n"; + exit 1; } # The handle has to be wrapped in a block to make 'print' happy as it doesn't like non-scalars for file handles @@ -871,11 +873,13 @@ sub variables #die if $test; if (not defined $level) { - die $THIS_FILE." ".__LINE__."; Log->variables() called without 'level': [".$level."] defined from: [$source : $line]\n"; + warn $THIS_FILE." ".__LINE__."; Log->variables() called without 'level': [".$level."] defined from: [$source : $line]\n"; + $anvil->nice_exit({exit_code => 1}); } elsif (not defined $anvil->Log->level) { - die $THIS_FILE." ".__LINE__."; Log->variables() called without Log->level: [".$anvil->Log->level."] defined from: [$source : $line]\n"; + warn $THIS_FILE." ".__LINE__."; Log->variables() called without Log->level: [".$anvil->Log->level."] defined from: [$source : $line]\n"; + $anvil->nice_exit({exit_code => 1}); } print "level: [$level], logging: [".$anvil->Log->level."], secure: [$secure], logging secure: [".$anvil->Log->secure."]\n" if $test; if ($level > $anvil->Log->level) diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 3307dfae..82fdd94d 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -159,8 +159,80 @@ sub bridge_info target => $target, }}); - my $shell_call = $anvil->data->{path}{exe}{bridge}." -json -pretty link show"; - my $output = ""; + my $host = $target ? $target : $anvil->Get->short_host_name(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host => $host }}); + + # First get the list of bridges. + my $shell_call = $anvil->data->{path}{exe}{ip}." link show type bridge"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + + my $output = ""; + if ($anvil->Network->is_local({host => $target})) + { + # Local call. + ($output, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:output' => $output, + 's2:return_code' => $return_code, + }}); + } + else + { + # Remote call + ($output, my $error, my $return_code) = $anvil->Remote->call({ + debug => $debug, + shell_call => $shell_call, + target => $target, + user => $remote_user, + password => $password, + remote_user => $remote_user, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:output' => $output, + 's2:error' => $error, + 's3:return_code' => $return_code, + }}); + } + + # Find the bridge interfaces + my $bridge = ""; + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + + if ($line =~ /^\d+:\s+(.*?):/) + { + $bridge = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { bridge => $bridge }}); + + $anvil->data->{bridge}{$host}{$bridge}{found} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "bridge::${host}::${bridge}::found" => $anvil->data->{bridge}{$host}{$bridge}{found}, + }}); + } + next if not $bridge; + + if ($line =~ /mtu (\d+) /) + { + $anvil->data->{bridge}{$host}{$bridge}{mtu} = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "bridge::${host}::${bridge}::mtu" => $anvil->data->{bridge}{$host}{$bridge}{mtu}, + }}); + } + if ($line =~ /link\/ether (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w) /) + { + $anvil->data->{bridge}{$host}{$bridge}{mac} = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "bridge::${host}::${bridge}::mac" => $anvil->data->{bridge}{$host}{$bridge}{mac}, + }}); + } + } + + # Now use bridge to find the interfaces connected to the bridges. + $shell_call = $anvil->data->{path}{exe}{bridge}." -json -pretty link show"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); + + $output = ""; if ($anvil->Network->is_local({host => $target})) { # Local call. @@ -201,33 +273,46 @@ sub bridge_info foreach my $hash_ref (@{$bridge_data}) { next if not defined $hash_ref->{master}; - my $bridge = $hash_ref->{master}; + my $master = $hash_ref->{master}; # This can be the bond name for bond members. my $interface = $hash_ref->{ifname}; - my $host = $target ? $target : $anvil->Get->short_host_name(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 's1:bridge' => $bridge, + 's1:master' => $master, 's2:interface' => $interface, - 's3:host' => $host, }}); - if ((not exists $anvil->data->{bridge}{$host}{$bridge}) or (ref($anvil->data->{bridge}{$host}{$bridge}{interfaces}) ne "ARRAY")) - { - $anvil->data->{bridge}{$host}{$bridge}{interfaces} = []; - $anvil->data->{bridge}{$host}{$bridge}{found} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bridge::${host}::${bridge}::interfaces" => $anvil->data->{bridge}{$host}{$bridge}{interfaces}, - "bridge::${host}::${bridge}::found" => $anvil->data->{bridge}{$host}{$bridge}{found}, - }}); - } - push @{$anvil->data->{bridge}{$host}{$bridge}{interfaces}}, $interface; + + # If the 'master' wasn't found in the call above, the 'master' is not a bridge. + next if not exists $anvil->data->{bridge}{$host}{$master}; + + # Record this interface as being connected to this bridge. + $anvil->data->{bridge}{$host}{$master}{interface}{$interface}{found} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "bridge::${host}::${master}::interface::${interface}::found" => $anvil->data->{bridge}{$host}{$master}{interface}{$interface}{found}, + }}); # Now store the rest of the data. foreach my $key (sort {$a cmp $b} keys %{$hash_ref}) { next if $key eq "master"; next if $key eq "ifname"; - $anvil->data->{bridge}{$host}{$bridge}{$interface}{$key} = $hash_ref->{$key}; + $anvil->data->{bridge}{$host}{$master}{interface}{$interface}{$key} = $hash_ref->{$key}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "bridge::${host}::${master}::interface::${interface}::${key}" => $anvil->data->{bridge}{$host}{$master}{interface}{$interface}{$key}, + }}); + } + } + + # Make it easy to find the bridge an interface is in. + delete $anvil->data->{interface_to_bridge} if exists $anvil->data->{interface_to_bridge}; + foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{bridge}{$host}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { bridge_name => $bridge_name }}); + foreach my $interface_name (sort {$a cmp $b} keys %{$anvil->data->{bridge}{$host}{$bridge_name}{interface}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface_name => $interface_name }}); + + $anvil->data->{interface_to_bridge}{$interface_name} = $bridge_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bridge::${host}::${bridge}::${interface}::${key}" => $anvil->data->{bridge}{$host}{$bridge}{$interface}{$key}, + "interface_to_bridge::${interface_name}" => $anvil->data->{interface_to_bridge}{$interface_name}, }}); } } @@ -1185,7 +1270,7 @@ sub find_matches source => $source, line => $line, }}); - die; + $anvil->nice_exit({exit_code => 1}); return(""); } } diff --git a/Anvil/Tools/Remote.pm b/Anvil/Tools/Remote.pm index 9e2ee521..aa9582b0 100644 --- a/Anvil/Tools/Remote.pm +++ b/Anvil/Tools/Remote.pm @@ -789,21 +789,24 @@ sub read_snmp_oid { # Um, what are we supposed to read? $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Remote->read_snmp_oid()", parameter => "oid" }}); - die; + $anvil->nice_exit({exit_code => 1}); + return("!!error!!"); } if (not $target) { # Who ya gonna call? No, seriously, I have no idea... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Remote->read_snmp_oid()", parameter => "target" }}); - die; + $anvil->nice_exit({exit_code => 1}); + return("!!error!!"); } if (($mib) && (not -r $mib)) { # Bad MIB path $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0163", variables => { mib => $mib }}); - die; + $anvil->nice_exit({exit_code => 1}); + return("!!error!!"); } diff --git a/Anvil/Tools/Words.pm b/Anvil/Tools/Words.pm index 672ebd15..a038e879 100644 --- a/Anvil/Tools/Words.pm +++ b/Anvil/Tools/Words.pm @@ -579,7 +579,7 @@ sub parse_banged_string } print $THIS_FILE." ".__LINE__."; Failed to parse the pair from: [".$variable_string."]\n"; print $THIS_FILE." ".__LINE__."; Was parsing message: [".$message."] from key string: [".$key_string."]\n"; - die; + $anvil->nice_exit({exit_code => 1}); } my ($variable, $value) = ($pair =~ /^!!(.*?)!(.*?)!!$/); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { @@ -958,6 +958,7 @@ sub string # We've got a string and variables from the caller, so inject them as needed. my $loops = 0; my $limit = $anvil->data->{defaults}{limits}{string_loops} =~ /^\d+$/ ? $anvil->data->{defaults}{limits}{string_loops} : 1000; + print $THIS_FILE." ".__LINE__."; limit: [".$limit."]\n" if $test; # If the user didn't pass in any variables, then we're in trouble. if (($string =~ /#!variable!(.+?)!#/s) && ((not $variables) or (ref($variables) ne "HASH"))) @@ -966,17 +967,21 @@ sub string while ($string =~ /#!variable!(.+?)!#/s) { $string =~ s/#!variable!(.*?)!#/!!variable!$1!!/s; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; # Die if I've looped too many times. $loops++; + print $THIS_FILE." ".__LINE__."; loops: [".$loops."]\n" if $test; if ($loops > $limit) { # If we're in a web environment, print the HTML header. + print $THIS_FILE." ".__LINE__."; environment: [".$anvil->environment."]\n" if $test; if ($anvil->environment eq "html") { print "Content-type: text/html; charset=utf-8\n\n"; } - die "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + print "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + $anvil->nice_exit({exit_code => 1}); } } my $error = "[ Error ] - The method Words->string() was asked to process the string: [".$string."] which has insertion variables, but nothing was passed to the 'variables' parameter."; @@ -994,24 +999,29 @@ sub string # restore them once we're out of this loop. foreach my $check ($string =~ /#!([^\s]+?)!#/) { + print $THIS_FILE." ".__LINE__."; check: [".$check."]\n" if $test; if (($check !~ /^data/) && ($check !~ /^string/) && ($check !~ /^variable/)) { # Simply invert the '#!...!#' to '!#...#!'. $string =~ s/#!($check)!#/!#$1#!/g; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; } # Die if I've looped too many times. $loops++; + print $THIS_FILE." ".__LINE__."; loops: [".$loops."], limit: [".$limit."]\n" if $test; if ($loops > $limit) { # If we're in a web environment, print the HTML header. + print $THIS_FILE." ".__LINE__."; environment: [".$anvil->environment."]\n" if $test; if ($anvil->environment eq "html") { print "Content-type: text/html; charset=utf-8\n\n"; } - die "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language]. Is there a bad '#!!!# replacement key? Exiting.\n"; + print "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language]. Is there a bad '#!!!# replacement key? Exiting.\n"; + $anvil->nice_exit({exit_code => 1}); } } @@ -1024,26 +1034,32 @@ sub string language => $language, file => $file, }); + print $THIS_FILE." ".__LINE__."; string: [".$string."], key: [".$key."], this_string: [".$this_string."]\n" if $test; if ($this_string eq "#!not_found!#") { # The key was bad... $string =~ s/#!string!$key!#/!!e[$key]!!/; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; } else { $string =~ s/#!string!$key!#/$this_string/; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; } # Die if I've looped too many times. $loops++; + print $THIS_FILE." ".__LINE__."; loops: [".$loops."], limit: [".$limit."]\n" if $test; if ($loops > $limit) { # If we're in a web environment, print the HTML header. + print $THIS_FILE." ".__LINE__."; environment: [".$anvil->environment."]\n" if $test; if ($anvil->environment eq "html") { print "Content-type: text/html; charset=utf-8\n\n"; } - die "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + print "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + $anvil->nice_exit({exit_code => 1}); } } @@ -1051,17 +1067,20 @@ sub string while ($string =~ /#!variable!(.+?)!#/s) { my $variable = $1; + print $THIS_FILE." ".__LINE__."; string: [".$string."], variable: [".$variable."]\n" if $test; # Sometimes, #!variable!*!# is used in explaining things to users. So we need # to escape it. It will be restored later in '_restore_protected()'. if ($variable eq "*") { $string =~ s/#!variable!\*!#/!#variable!*#!/; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; next; } if ($variable eq "") { $string =~ s/#!variable!\*!#/!#variable!#!/; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; next; } @@ -1070,24 +1089,29 @@ sub string # I can't expect there to always be a defined value in the variables # array at any given position so if it is blank qw blank the key. $string =~ s/#!variable!$variable!#//; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; } else { my $value = $variables->{$variable}; chomp $value; $string =~ s/#!variable!$variable!#/$value/; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; } # Die if I've looped too many times. $loops++; + print $THIS_FILE." ".__LINE__."; loops: [".$loops."], limit: [".$limit."]\n" if $test; if ($loops > $limit) { # If we're in a web environment, print the HTML header. + print $THIS_FILE." ".__LINE__."; environment: [".$anvil->environment."]\n" if $test; if ($anvil->environment eq "html") { print "Content-type: text/html; charset=utf-8\n\n"; } - die "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + print "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + $anvil->nice_exit({exit_code => 1}); } } @@ -1095,61 +1119,77 @@ sub string while ($string =~ /#!data!(.+?)!#/) { my $id = $1; + print $THIS_FILE." ".__LINE__."; string: [".$string."], id: [".$id."]\n" if $test; if ($id =~ /::/) { # Multi-dimensional hash. + print $THIS_FILE." ".__LINE__."; multi-dimensional\n" if $test; my $value = $anvil->_get_hash_reference({ key => $id }); + print $THIS_FILE." ".__LINE__."; value: [".$value."]\n" if $test; if (not defined $value) { $string =~ s/#!data!$id!#/!!a[$id]!!/; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; } else { $string =~ s/#!data!$id!#/$value/; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; } } else { # One dimension + print $THIS_FILE." ".__LINE__."; one dimension\n" if $test; if (not defined $anvil->data->{$id}) { $string =~ s/#!data!$id!#/!!b[$id]!!/; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; } else { my $value = $anvil->data->{$id}; $string =~ s/#!data!$id!#/$value/; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; } } # Die if I've looped too many times. $loops++; + print $THIS_FILE." ".__LINE__."; loops: [".$loops."], limit: [".$limit."]\n" if $test; if ($loops > $limit) { # If we're in a web environment, print the HTML header. + print $THIS_FILE." ".__LINE__."; environment: [".$anvil->environment."]\n" if $test; if ($anvil->environment eq "html") { print "Content-type: text/html; charset=utf-8\n\n"; } - die "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + print "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + $anvil->nice_exit({exit_code => 1}); } } $loops++; + print $THIS_FILE." ".__LINE__."; loops: [".$loops."], limit: [".$limit."]\n" if $test; if ($loops > $limit) { # If we're in a web environment, print the HTML header. + print $THIS_FILE." ".__LINE__."; environment: [".$anvil->environment."]\n" if $test; if ($anvil->environment eq "html") { print "Content-type: text/html; charset=utf-8\n\n"; } - die "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + print "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + $anvil->nice_exit({exit_code => 1}); } # If there are no replacement keys left, exit the loop. + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; if ($string !~ /#!([^\s]+?)!#/) { $loop = 0; + print $THIS_FILE." ".__LINE__."; loop: [".$loop."]\n" if $test; } } @@ -1159,27 +1199,34 @@ sub string while ($loop) { $string =~ s/!#([^\s]+?)#!/#!$1!#/g; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; $loops++; + print $THIS_FILE." ".__LINE__."; loops: [".$loops."], limit: [".$limit."]\n" if $test; if ($loops > $limit) { # If we're in a web environment, print the HTML header. + print $THIS_FILE." ".__LINE__."; environment: [".$anvil->environment."]\n" if $test; if ($anvil->environment eq "html") { print "Content-type: text/html; charset=utf-8\n\n"; } - die "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + print "$THIS_FILE ".__LINE__."; Infinite loop detected while processing the string: [".$string."] from the key: [$key] in language: [$language], exiting.\n"; + $anvil->nice_exit({exit_code => 1}); } + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; if ($string !~ /!#[^\s]+?#!/) { $loop = 0; + print $THIS_FILE." ".__LINE__."; loop: [".$loop."]\n" if $test; } } } # In some multi-line strings, the last line will be '\t\t'. We clean this up. $string =~ s/\t\t$//; + print $THIS_FILE." ".__LINE__."; string: [".$string."]\n" if $test; #print $THIS_FILE." ".__LINE__."; [ Debug ] - string: [$string]\n"; return($string); diff --git a/scancore-agents/scan-drbd/scan-drbd b/scancore-agents/scan-drbd/scan-drbd index 060060f5..9776b3fc 100755 --- a/scancore-agents/scan-drbd/scan-drbd +++ b/scancore-agents/scan-drbd/scan-drbd @@ -336,7 +336,11 @@ sub process_resource "s5:new_scan_drbd_resource_xml" => $new_scan_drbd_resource_xml, }}); - die if not defined $old_scan_drbd_resource_xml; + if (not defined $old_scan_drbd_resource_xml) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_drbd_warning_0001"}); + $anvil->nice_exit({exit_code => 1}); + } my $update = 0; if ($scan_drbd_resource_name ne $old_scan_drbd_resource_name) @@ -759,7 +763,11 @@ WHERE scan_drbd_peer_scan_drbd_volume_uuid => $scan_drbd_peer_scan_drbd_volume_uuid, }}); - die if not $scan_drbd_peer_scan_drbd_volume_uuid; + if (not $scan_drbd_peer_scan_drbd_volume_uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_drbd_warning_0002"}); + $anvil->nice_exit({exit_code => 1}); + } my $query = " INSERT INTO diff --git a/scancore-agents/scan-drbd/scan-drbd.xml b/scancore-agents/scan-drbd/scan-drbd.xml index c74aaa5c..f46d9b80 100644 --- a/scancore-agents/scan-drbd/scan-drbd.xml +++ b/scancore-agents/scan-drbd/scan-drbd.xml @@ -19,6 +19,10 @@ NOTE: All string keys MUST be prefixed with the agent name! ie: 'scan_server_log DRBD is not configured on this host, exiting. + + [ Warning ] - The variable 'old_scan_drbd_resource_xml' is undefined, which should never be the case. This is likely a program error. + [ Warning ] - The variable 'scan_drbd_peer_scan_drbd_volume_uuid' is empty, which should never be the case. This is likely a program error. + Starting The: [#!variable!program!#] DRBD resource agent. diff --git a/scancore-agents/scan-ipmitool/scan-ipmitool b/scancore-agents/scan-ipmitool/scan-ipmitool index 1b45e77d..8cb79f25 100755 --- a/scancore-agents/scan-ipmitool/scan-ipmitool +++ b/scancore-agents/scan-ipmitool/scan-ipmitool @@ -811,9 +811,16 @@ INSERT INTO next; } - ### TODO: Make this ia log entry - die "No IPMI units for sensor: [".$scan_ipmitool_sensor_name."]." if not $new_scan_ipmitool_sensor_units; - die "No IPMI value for sensor: [".$new_scan_ipmitool_value_sensor_value."]." if not $new_scan_ipmitool_value_sensor_value; + if (not $new_scan_ipmitool_sensor_units) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_ipmitool_warn_0001", variables => { sensor => $scan_ipmitool_sensor_name }}); + next; + } + if (not $new_scan_ipmitool_value_sensor_value) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_ipmitool_warn_0001", variables => { sensor => $new_scan_ipmitool_value_sensor_value }}); + next; + } # If the value is "" and it's a digit-based value, switch it to '0' if ((($new_scan_ipmitool_sensor_units eq "C") or ($new_scan_ipmitool_sensor_units eq "F") or ($new_scan_ipmitool_sensor_units eq "RPM")) && ($new_scan_ipmitool_value_sensor_value eq "")) diff --git a/scancore-agents/scan-ipmitool/scan-ipmitool.xml b/scancore-agents/scan-ipmitool/scan-ipmitool.xml index 9f512bdd..366da3ce 100644 --- a/scancore-agents/scan-ipmitool/scan-ipmitool.xml +++ b/scancore-agents/scan-ipmitool/scan-ipmitool.xml @@ -116,5 +116,8 @@ The new sensor: [#!variable!sensor_name!#] has been found on the machine: [#!var The sensor named: [#!variable!sensor_name!#] appears to have vanished, but this is the first scan that it vanished. This is generally harmless and just a sensor read issue. The sensor named: [#!variable!sensor_name!#] has returned. + + [ Warning ] - No IPMI units for sensor: [#!variable!sensor!#]. + diff --git a/scancore-agents/scan-lvm/scan-lvm b/scancore-agents/scan-lvm/scan-lvm index 9b41a252..8e17eb86 100755 --- a/scancore-agents/scan-lvm/scan-lvm +++ b/scancore-agents/scan-lvm/scan-lvm @@ -1088,14 +1088,27 @@ 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 }}); + my $shell_call = $anvil->data->{path}{exe}{pvscan}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $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 ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); - my $json = JSON->new->allow_nonref; - my $pvs_data = $json->decode($output); + $shell_call = $anvil->data->{path}{exe}{pvs}." --noheadings --units b --reportformat json -o pv_uuid,pv_name,vg_name,pv_attr,pv_size,pv_free"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + my $json = JSON->new->allow_nonref; + my $pvs_data = $json->decode($output); + my $default_sector_size = 512; foreach my $hash_ref (@{$pvs_data->{report}->[0]->{pv}}) { my $scan_lvm_pv_internal_uuid = $hash_ref->{pv_uuid}; @@ -1125,15 +1138,19 @@ sub collect_pvs_data my $sector_size = 0; until ($sector_size) { - chop $partition; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { partition => $partition }}); if (not $partition) { # Weird... Default to 512. - $sector_size = 512; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sector_size => $sector_size }}); - die; + $sector_size = $default_sector_size; + my $original_partition = $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{name}; + my $sector_path = $directory."/".$original_partition."/queue/hw_sector_size"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_warning_0001", variables => { + device => $original_partition, + sector_path => $sector_path, + sector_size => $sector_size, + }}); } my $sector_size_file = $directory."/".$partition."/queue/hw_sector_size"; @@ -1147,11 +1164,19 @@ sub collect_pvs_data if ((not $sector_size) or ($sector_size =~ /\D/)) { # Something went wrong, default to 512. - $sector_size = 512; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sector_size => $sector_size }}); - die; + $sector_size = $default_sector_size; + my $original_partition = $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{name}; + my $sector_path = $directory."/".$original_partition."/queue/hw_sector_size"; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_lvm_warning_0001", variables => { + device => $original_partition, + sector_path => $sector_path, + sector_size => $sector_size, + }}); } } + + # Take a number off and try again. + chop $partition; } $anvil->data->{lvm}{scan_lvm_pv_internal_uuid}{$scan_lvm_pv_internal_uuid}{sector_size} = $sector_size; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { @@ -1166,11 +1191,23 @@ 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 }}); + my $shell_call = $anvil->data->{path}{exe}{vgscan}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $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 ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + $shell_call = $anvil->data->{path}{exe}{vgs}." --noheadings --units b --reportformat json -o vg_uuid,vg_name,vg_attr,vg_extent_size,vg_size,vg_free"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); my $json = JSON->new->allow_nonref; my $vgs_data = $json->decode($output); @@ -1198,11 +1235,23 @@ 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 }}); + my $shell_call = $anvil->data->{path}{exe}{lvscan}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $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 => 3, list => { output => $output, return_code => $return_code }}); + my ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + $shell_call = $anvil->data->{path}{exe}{lvs}." --noheadings --units b --reportformat json -o lv_name,vg_name,lv_attr,lv_size,lv_uuid,lv_path,devices"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + + ($output, $return_code) = $anvil->System->call({timeout => 15, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); my $json = JSON->new->allow_nonref; my $lvs_data = $json->decode($output); diff --git a/scancore-agents/scan-lvm/scan-lvm.xml b/scancore-agents/scan-lvm/scan-lvm.xml index eebdffae..9bb7cfea 100644 --- a/scancore-agents/scan-lvm/scan-lvm.xml +++ b/scancore-agents/scan-lvm/scan-lvm.xml @@ -223,6 +223,9 @@ The attribute bits are: Starting: [#!variable!program!#]. + + + [ Warning ] - Failed to find the sector size for: [#!variable!device!#] This should be in the path: [#!variable!sector_path!#]. Assuming the sector size of: [#!variable!sector_size!#], but this could be incorrect. diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index cac8ef99..adbce66d 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -931,22 +931,7 @@ sub collect_data closedir(DIRECTORY); # Find what interfaces are connected to which bridges - $anvil->Network->bridge_info({debug => 3}); - delete $anvil->data->{interface_to_bridge} if exists $anvil->data->{interface_to_bridge}; - foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{bridge}{$local_host}}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_name => $bridge_name }}); - foreach my $interface_name (sort {$a cmp $b} @{$anvil->data->{bridge}{$local_host}{$bridge_name}{interfaces}}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface_name => $interface_name }}); - - $anvil->data->{interface_to_bridge}{$interface_name} = $bridge_name; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface_to_bridge::${interface_name}" => $anvil->data->{interface_to_bridge}{$interface_name}, - }}); - } - } - + $anvil->Network->bridge_info({debug => 2}); foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}}) { my $ip_address = $anvil->data->{network}{$local_host}{interface}{$interface}{ip}; @@ -4060,7 +4045,11 @@ sub check_bridges foreach my $bridge_uuid (keys %{$anvil->data->{old}{bridges}{bridge_uuid}}) { # Skip if already deleted. - die if not $bridge_uuid; + if (not $bridge_uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_warning_0001"}); + $anvil->nice_exit({exit_code => 1}); + } my $bridge_name = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_name}; my $bridge_id = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}; diff --git a/scancore-agents/scan-network/scan-network.xml b/scancore-agents/scan-network/scan-network.xml index c512841c..04908108 100644 --- a/scancore-agents/scan-network/scan-network.xml +++ b/scancore-agents/scan-network/scan-network.xml @@ -219,5 +219,7 @@ This mode is NOT supported by the Anvil! Intelligent Availability™ platform! The old bond: [#!variable!name!#] was marked as deleted more than: [#!variable!age!#] hours ago. Purging it from the database. The old bridge: [#!variable!name!#] was marked as deleted more than: [#!variable!age!#] hours ago. Purging it from the database. The old IP address: [#!variable!ip!#] was marked as deleted more than: [#!variable!age!#] hours ago. Purging it from the database. + + There was an empty bridge_uuid in the hash 'old::bridges::bridge_uuid' hash. This is a program error. diff --git a/tools/anvil-update-states b/tools/anvil-update-states index 7299aa38..85c55290 100755 --- a/tools/anvil-update-states +++ b/tools/anvil-update-states @@ -553,20 +553,6 @@ sub update_network # Find what interfaces are connected to which bridges $anvil->Network->bridge_info({debug => 2}); - delete $anvil->data->{interface_to_bridge} if exists $anvil->data->{interface_to_bridge}; - foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{bridge}{$local_host}}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bridge_name => $bridge_name }}); - foreach my $interface_name (sort {$a cmp $b} @{$anvil->data->{bridge}{$local_host}{$bridge_name}{interfaces}}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { interface_name => $interface_name }}); - - $anvil->data->{interface_to_bridge}{$interface_name} = $bridge_name; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "interface_to_bridge::${interface_name}" => $anvil->data->{interface_to_bridge}{$interface_name}, - }}); - } - } # We need to record bridges first so we know their UUIDs when looking at bonds and interfaces that # might be connected to them. Then we need to look at bonds so that their UUIDs are available when From 7b1771e4987adaa8e60738d4069cd7a5424c3406 Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 15 Aug 2022 13:59:35 -0400 Subject: [PATCH 7/8] Updated anvil-provision-server to wait until the local machine is a full cluster member before proceeding. Signed-off-by: Digimer --- tools/anvil-provision-server | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/tools/anvil-provision-server b/tools/anvil-provision-server index 6375cf9d..4584ab42 100755 --- a/tools/anvil-provision-server +++ b/tools/anvil-provision-server @@ -11,7 +11,7 @@ # TODO: Support cloning; Example # - virt-clone --original-xml /mnt/shared/definitions/.xml --name --file --check path_exists=off # - Make VNC default -# +# - Don't provision until in the cluster! use strict; use warnings; @@ -168,12 +168,26 @@ sub run_jobs } else { - $waiting = 0; - $anvil->Job->update_progress({ - progress => 8, - message => "job_0276", - }); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0276"}); + # Make sure we're actually in the cluster now. + if ($anvil->data->{cib}{parsed}{'local'}{ready}) + { + # We're ready! + $waiting = 0; + $anvil->Job->update_progress({ + progress => 8, + message => "job_0276", + }); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0276"}); + } + else + { + # Cluster is coming up, but it's not up yet. + $anvil->Job->update_progress({ + progress => 6, + message => "job_0278", + }); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0278"}); + } } } From cbb441759ef7c553c0d0e9edb8a964e0a7491caf Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 15 Aug 2022 23:27:40 -0400 Subject: [PATCH 8/8] * Fixed a couple bugs in anvil-manage-files where a file moved from incoming to files or definitions wasn't having the directory updated properly in the database. Also made an explicit check when looking for missing files to check to see if the file exists in another managed directory and, if so and if a striker, update the DB. Signed-off-by: Digimer --- share/words.xml | 1 + tools/anvil-manage-files | 83 +++++++++++++++++++++++++++--------- tools/anvil-provision-server | 2 +- tools/anvil-sync-shared | 72 ------------------------------- 4 files changed, 66 insertions(+), 92 deletions(-) diff --git a/share/words.xml b/share/words.xml index aa3f4939..f9731b44 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2152,6 +2152,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: The server: [#!variable!server!#] was found to be running already, but it wasn't marked as booted. Marking it as if it just booted to handle any dependent servers. The server: [#!variable!server!#] is configured to stay off, ignoring it. The file: [#!variable!file!#] needs to be added to the database, but since the last scan it's size grew from: [#!variable!old_size_bytes!# (#!variables!old_size_hr!#)] to: [#!variable!new_size_bytes!# (#!variables!new_size_hr!#)]. A difference of: [#!variable!difference_bytes!# (#!variables!difference_hr!#)]. It might still be being uploaded, so we'll keep checking periodocally until the size stops changing. + Found the missing file: [#!variable!file!#] in the directory: [#!variable!directory!#]. Updating the database now. The host name: [#!variable!target!#] does not resolve to an IP address. diff --git a/tools/anvil-manage-files b/tools/anvil-manage-files index 083153c8..d07cb7be 100755 --- a/tools/anvil-manage-files +++ b/tools/anvil-manage-files @@ -299,7 +299,40 @@ sub find_file 's4:file_md5sum' => $file_md5sum, }}); - my $found = 0; + # Before we do anything, see if the file is shown as being in a directory other than 'files' in the + # database, but actually in files on disk. If so, update the database. + my $host_type = $anvil->Get->host_type(); + my $file_directory = $anvil->data->{files}{file_uuid}{$file_uuid}{file_directory}; + my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name}; + my $files_full_path = $anvil->data->{path}{directories}{shared}{files}."/".$file_name; + $files_full_path =~ s/\/\//\//g; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:file_directory' => $file_directory, + 's2:file_name' => $file_name, + 's3:files_full_path' => $files_full_path, + }}); + + if (($full_path ne $files_full_path) && (-e $files_full_path) && ($host_type eq "striker")) + { + ### TODO: Add checks to see if anything other than the directory needs updating. + # It's in 'files' now, update the database. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0725", variables => { + file => $full_path, + directory => $anvil->data->{path}{directories}{shared}{files}, + }}); + $anvil->Database->insert_or_update_files({ + debug => 2, + file_uuid => $file_uuid, + file_name => $anvil->data->{files}{file_uuid}{$file_uuid}{file_name}, + file_directory => $anvil->data->{path}{directories}{shared}{files}, + file_size => $anvil->data->{files}{file_uuid}{$file_uuid}{file_size}, + file_md5sum => $anvil->data->{files}{file_uuid}{$file_uuid}{file_md5sum}, + file_mtime => $anvil->data->{files}{file_uuid}{$file_uuid}{file_mtime}, + file_type => $anvil->data->{files}{file_uuid}{$file_uuid}{file_type}, + }); + + return(1); + } # We want to search Striker's first, DR hosts second and nodes third. $anvil->Database->get_hosts; @@ -326,14 +359,15 @@ sub find_file } # Now search. - my $file_found = 0; + my $found_on_host = 0; # Found the file on a target + my $file_found = 0; # Actually have the file locally. foreach my $search_host_uuid (@{$host_order}) { last if $file_found; my $target_host = $anvil->data->{hosts}{host_uuid}{$search_host_uuid}{short_host_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:search_host_uuid' => $search_host_uuid, - 's2:target_host' => $target_host, + 's1:target_host' => $target_host, + 's2:search_host_uuid' => $search_host_uuid, }}); my $target_ip = $anvil->Network->find_target_ip({host_uuid => $search_host_uuid}); @@ -365,20 +399,20 @@ sub find_file $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); if ($line =~ /^size: \[(\d+)\]$/) { - $remote_size = $1; - $found = 1; + $remote_size = $1; + $found_on_host = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - remote_size => $remote_size, - found => $found, + remote_size => $remote_size, + found_on_host => $found_on_host, }}); } } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:found' => $found, - 's2:remote_size' => $remote_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $remote_size}).")", - 's3:file_size' => $file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}).")", + 's1:found_on_host' => $found_on_host, + 's2:remote_size' => $remote_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $remote_size}).")", + 's3:file_size' => $file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}).")", }}); - next if not $found; + next if not $found_on_host; if ($remote_size eq $file_size) { @@ -447,7 +481,7 @@ sub find_file } } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_found => $file_found }}); return($file_found); } @@ -470,16 +504,28 @@ sub check_incoming recursive => 1, }); - my $incoming_directory = $anvil->data->{path}{directories}{shared}{incoming}; + my $archives_directory = $anvil->data->{path}{directories}{shared}{archives}; + my $definitions_directory = $anvil->data->{path}{directories}{shared}{definitions}; + my $incoming_directory = $anvil->data->{path}{directories}{shared}{incoming}; + my $provision_directory = $anvil->data->{path}{directories}{shared}{provision}; + my $temp_directory = $anvil->data->{path}{directories}{shared}{temp}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + archives_directory => $archives_directory, + definitions_directory => $definitions_directory, + incoming_directory => $incoming_directory, + provision_directory => $provision_directory, + temp_directory => $temp_directory, + }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0264"}); foreach my $full_path (sort {$a cmp $b} keys %{$anvil->data->{scan}{directories}}) { - # Skip this if it's under '/mnt/shared/temp' (that's used for files being downloaded, etc) - next if $full_path =~ /^\/mnt\/shared\/temp\//; + # Skip this if it's under a directory managed elsewhere, or that we don't care about. + next if $full_path =~ /^$temp_directory/; + next if $full_path =~ /^$provision_directory/; + next if $full_path =~ /^$definitions_directory/; # Skip if this isn't a file. my $file_type = $anvil->data->{scan}{directories}{$full_path}{type}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { full_path => $full_path, file_type => $file_type, @@ -611,12 +657,11 @@ sub check_incoming }); # Update the file_directory. - my $say_directory =~ s/\/$//; ($file_uuid) = $anvil->Database->insert_or_update_files({ debug => 3, file_uuid => $file_uuid, file_name => $file_name, - file_directory => $say_directory, + file_directory => $target, file_size => $file_size, file_md5sum => $file_md5sum, file_mtime => $file_mtime, diff --git a/tools/anvil-provision-server b/tools/anvil-provision-server index 4584ab42..76229bfc 100755 --- a/tools/anvil-provision-server +++ b/tools/anvil-provision-server @@ -11,7 +11,7 @@ # TODO: Support cloning; Example # - virt-clone --original-xml /mnt/shared/definitions/.xml --name --file --check path_exists=off # - Make VNC default -# - Don't provision until in the cluster! +# use strict; use warnings; diff --git a/tools/anvil-sync-shared b/tools/anvil-sync-shared index a1cb6965..a802d90b 100755 --- a/tools/anvil-sync-shared +++ b/tools/anvil-sync-shared @@ -77,12 +77,6 @@ if ($anvil->data->{switches}{'job-uuid'}) process_file_mode($anvil); } } -else -{ - # This checks to see if there are any files that need to be pulled, renamed, removed, or mode - # updated. - #run_checks($anvil); -} $anvil->nice_exit({exit_code => 0}); @@ -91,72 +85,6 @@ $anvil->nice_exit({exit_code => 0}); # Functions # ############################################################################################################# -### TODO: Left off here. Run periodic checks for files that need to be pulled/removed, mode changed, -### etc. For 3.0, we'll ignore files people add manually though later we'll probably want to -### auto-sync them. -### NOTE: When finding new files, check the size, sleep for 30 seconds, and check again. If a file's -### size changed, skip it, it's likely still being updated. -### NOTE: This isn't finished, and likely won't be for a while. -sub run_checks -{ - my ($anvil) = @_; - - # First, get a list of files we're expected to have. - $anvil->Database->get_files({debug => 3, include_deleted => 1}); - $anvil->Database->get_file_locations({debug => 3}); - - if ($anvil->Get->host_type eq "striker") - { - # Look for files to add - } - else - { - # Are we an Anvil! member? - my $anvil_uuid = $anvil->Cluster->get_anvil_uuid(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }}); - - if (not $anvil_uuid) - { - # Nothing to do. - $anvil->nice_exit({exit_code => 0}); - } - - # What files should we have? - foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{files}{file_name}}) - { - # TODO: Once per day, calculate the md5sums and compare against the DB. - my $file_uuid = $anvil->data->{files}{file_name}{$file_name}{file_uuid}; - my $file_directory = $anvil->data->{files}{file_name}{$file_name}{file_directory}; - my $file_size = $anvil->data->{files}{file_name}{$file_name}{file_size}; - my $file_type = $anvil->data->{files}{file_name}{$file_name}{file_type}; - my $file_path = $file_directory."/".$file_name; - my $file_location_uuid = $anvil->data->{file_locations}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_location_uuid}; - my $file_location_active = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - file_uuid => $file_uuid, - file_name => $file_name, - file_directory => $file_directory, - file_size => $file_size." (".$anvil->Convert->bytes_to_human_readable({"bytes" => $file_size}).")", - file_type => $file_type, - file_path => $file_path, - file_location_uuid => $file_location_uuid, - file_location_active => $file_location_active, - }}); - - if (-e $file_path) - { - # File exists, should it? - } - else - { - # File doesn't exist, should it? - } - } - } - - return(0); -} - sub process_file_mode { my ($anvil) = @_;