#!/usr/bin/perl # # This runs on striker dashboards and syncs files under /mnt/shared on all known systems. It reaches out and # pulls over any files under /mnt/shared/files/ to the same on the local system. It then pushes files out to # all members of the same Anvil!. # # If this is called with a job-uuid, file-specific tasks will be handled, like moving files uploaded over a # browser or deleting / purging a file. # # NOTE: This file is NOT responsible for sync'ing definition files! That is handles in scan-server. # # TODO: # - Handle deleting files by user input, or if a given file that was on an Anvil! has been removed for both # nodes and DR, where applicable. # - use strict; use warnings; use Anvil::Tools; use Data::Dumper; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; if (($running_directory =~ /^\./) && ($ENV{PWD})) { $running_directory =~ s/^\./$ENV{PWD}/; } # Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. $| = 1; my $anvil = Anvil::Tools->new(); # Read switches (target ([user@]host[:port]) and the file with the target's password. $anvil->data->{switches}{'job-uuid'} = ""; $anvil->Get->switches; ### TODO: Remove this $anvil->Log->level({set => 2}); $anvil->Log->secure({set => 1}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }}); # Connect to the database(s). $anvil->Database->connect; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0132"}); # If we have a job-uuid, process it. if ($anvil->data->{switches}{'job-uuid'}) { # Load the job data. $anvil->Database->get_anvils({debug => 3}); $anvil->Job->get_job_details({debug => 3}); $anvil->Job->clear({debug => 3}); $anvil->data->{sys}{progress} = 1; if ($anvil->data->{jobs}{job_name} eq "storage::move_incoming") { process_incoming_file($anvil); } if ($anvil->data->{jobs}{job_name} eq "storage::pull_file") { process_pull_file($anvil); } if ($anvil->data->{jobs}{job_name} eq "storage::purge") { process_purge_file($anvil); } if ($anvil->data->{jobs}{job_name} eq "storage::rename") { process_rename_file($anvil); } if ($anvil->data->{jobs}{job_name} eq "storage::check_mode") { process_file_mode($anvil); } } $anvil->nice_exit({exit_code => 0}); ############################################################################################################# # Functions # ############################################################################################################# sub process_file_mode { my ($anvil) = @_; $anvil->Job->update_progress({ progress => $anvil->data->{sys}{progress}, message => "message_0205", }); # We have to include deleted because purges will already have the file flagged as deleted. $anvil->Database->get_files({debug => 3, include_deleted => 1}); $anvil->Database->get_file_locations({debug => 3}); my $file_uuid = ($anvil->data->{jobs}{job_data} =~ /file_uuid=(.*)$/)[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_uuid => $file_uuid }}); if (not $file_uuid) { # Can't do anything, file wasn't parsed. $anvil->Job->update_progress({ progress => 100, message => "error_0185,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0185", variables => { job_uuid => $anvil->data->{switches}{'job-uuid'} }}); $anvil->nice_exit({exit_code => 1}); } elsif (not exists $anvil->data->{files}{file_uuid}{$file_uuid}) { # File UUID doesn't appear to be valid. $anvil->Job->update_progress({ progress => 100, message => "error_0186,!!file_uuid!".$file_uuid."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0186", variables => { file_uuid => $file_uuid }}); $anvil->nice_exit({exit_code => 1}); } my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name}; my $file_directory = $anvil->data->{files}{file_uuid}{$file_uuid}{file_directory}; my $file_path = $file_directory."/".$file_name; my $file_type = $anvil->data->{files}{file_uuid}{$file_uuid}{file_type}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:file_name' => $file_name, 's2:file_directory' => $file_directory, 's3:file_path' => $file_path, 's4:file_type' => $file_type, }}); # From here, we'll unlink if it exists. If it doesn't exist, we still exit sucessfully. if (-e $file_path) { # Change the mode, if need it. my $new_mode = "a-x"; if ($file_type eq "script") { $new_mode = "a+x"; } $anvil->Storage->change_mode({ path => $file_path, mode => $new_mode, }); $anvil->Job->update_progress({ progress => 100, message => "job_0145,!!file_path!".$file_path."!!,!!new_mode!".$new_mode."!!", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "job_0145", variables => { file_path => $file_path, new_mode => $new_mode, }}); $anvil->nice_exit({exit_code => 0}); } else { # Doesn't exist, nothing to do. $anvil->Job->update_progress({ progress => 100, message => "job_0146,!!file_path!".$file_path."!!", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "job_0146", variables => { file_path => $file_path }}); $anvil->nice_exit({exit_code => 0}); } return(0); } sub process_rename_file { my ($anvil) = @_; $anvil->Job->update_progress({ progress => $anvil->data->{sys}{progress}, message => "message_0204", }); $anvil->Database->get_files({debug => 3}); $anvil->Database->get_file_locations({debug => 3}); my $file_uuid = ""; my $old_name = ""; my $new_name = ""; foreach my $line (split/\n/, $anvil->data->{jobs}{job_data}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); if ($line =~ /file_uuid=(.*)$/) { $file_uuid = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_uuid => $file_uuid }}); } if ($line =~ /old_name=(.*)$/) { $old_name = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_name => $old_name }}); } if ($line =~ /new_name=(.*)$/) { $new_name = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_name => $new_name }}); } } if (not $file_uuid) { # Can't do anything, file wasn't parsed. $anvil->Job->update_progress({ progress => 100, message => "error_0181,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0181", variables => { job_uuid => $anvil->data->{switches}{'job-uuid'} }}); $anvil->nice_exit({exit_code => 1}); } elsif (not exists $anvil->data->{files}{file_uuid}{$file_uuid}) { # File UUID doesn't appear to be valid. $anvil->Job->update_progress({ progress => 100, message => "error_0182,!!file_uuid!".$file_uuid."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0182", variables => { file_uuid => $file_uuid }}); $anvil->nice_exit({exit_code => 1}); } my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name}; my $file_directory = $anvil->data->{files}{file_uuid}{$file_uuid}{file_directory}; my $old_file_path = $file_directory."/".$old_name; my $new_file_path = $file_directory."/".$new_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:file_name' => $file_name, 's2:file_directory' => $file_directory, 's3:old_file_path' => $old_file_path, 's4:new_file_path' => $new_file_path, }}); if (not $new_name) { # Can't do anything, file wasn't parsed. $anvil->Job->update_progress({ progress => 100, message => "error_0183,!!file_name!".$new_file_path."!!,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0183", variables => { file_name => $new_file_path, job_uuid => $anvil->data->{switches}{'job-uuid'}, }}); $anvil->nice_exit({exit_code => 1}); } # If the file doesn't exist, there's nothing to do (and that's OK). if (-e $old_file_path) { # Move the file. $anvil->Job->update_progress({ progress => 50, message => "job_0141,!!old_file!".$old_file_path."!!,!!new_file!".$new_file_path."!!", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "job_0141", variables => { old_file => $old_file_path, new_file => $new_file_path, }}); $anvil->Storage->move_file({ source_file => $old_file_path, target_file => $new_file_path, }); if ((not -e $old_file_path) && (-e $new_file_path)) { # Success! $anvil->Job->update_progress({ progress => 100, message => "job_0142", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "job_0142"}); $anvil->nice_exit({exit_code => 0}); } elsif ((-e $old_file_path) && (not -e $new_file_path)) { # Move failed $anvil->Job->update_progress({ progress => 1, message => "error_0184", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0184"}); sleep 60; $anvil->nice_exit({exit_code => 1}); } } else { # Nothing to do $anvil->Job->update_progress({ progress => 100, message => "job_0140,!!file_path!".$old_file_path."!!", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "job_0140", variables => { file_path => $old_file_path }}); $anvil->nice_exit({exit_code => 0}); } return(0); } sub process_purge_file { my ($anvil) = @_; $anvil->Job->update_progress({ progress => $anvil->data->{sys}{progress}, message => "message_0203", }); # We have to include deleted because purges will already have the file flagged as deleted. $anvil->Database->get_files({debug => 3, include_deleted => 1}); $anvil->Database->get_file_locations({debug => 3}); my $file_uuid = ($anvil->data->{jobs}{job_data} =~ /file_uuid=(.*)$/)[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_uuid => $file_uuid }}); if (not $file_uuid) { # Can't do anything, file wasn't parsed. $anvil->Job->update_progress({ progress => 100, message => "error_0178,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0178", variables => { job_uuid => $anvil->data->{switches}{'job-uuid'} }}); $anvil->nice_exit({exit_code => 1}); } elsif (not exists $anvil->data->{files}{file_uuid}{$file_uuid}) { # File UUID doesn't appear to be valid. $anvil->Job->update_progress({ progress => 100, message => "error_0179,!!file_uuid!".$file_uuid."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0179", variables => { file_uuid => $file_uuid }}); $anvil->nice_exit({exit_code => 1}); } my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name}; my $file_directory = $anvil->data->{files}{file_uuid}{$file_uuid}{file_directory}; my $file_path = $file_directory."/".$file_name; my $file_type = $anvil->data->{files}{file_uuid}{$file_uuid}{file_type}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:file_name' => $file_name, 's2:file_directory' => $file_directory, 's3:file_path' => $file_path, 's4:file_type' => $file_type, }}); # From here, we'll unlink if it exists. If it doesn't exist, we still exit sucessfully. if (-e $file_path) { # Remove it unlink $file_path; if (-e $file_path) { # Failed. my $error = $!; $anvil->Job->update_progress({ progress => 100, message => "error_0180,!!file_path!".$file_path."!!,!!error!".$error."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0180", variables => { file_path => $file_path, error => $error, }}); $anvil->nice_exit({exit_code => 1}); } else { # Success! $anvil->Job->update_progress({ progress => 100, message => "job_0134,!!file_path!".$file_path."!!", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "job_0134", variables => { file_path => $file_path }}); $anvil->nice_exit({exit_code => 0}); } } else { # Doesn't exist, nothing to do. $anvil->Job->update_progress({ progress => 100, message => "job_0135,!!file_path!".$file_path."!!", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "job_0135", variables => { file_path => $file_path }}); $anvil->nice_exit({exit_code => 0}); } return(0); } sub process_incoming_file { my ($anvil) = @_; $anvil->Job->update_progress({ progress => $anvil->data->{sys}{progress}, message => "message_0191", }); my $file = ($anvil->data->{jobs}{job_data} =~ /file=(.*)$/)[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }}); if (not $file) { # Can't do anything, file wasn't parsed. $anvil->Job->update_progress({ progress => 100, message => "error_0170,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0170", variables => { job_uuid => $anvil->data->{switches}{'job-uuid'} }}); $anvil->nice_exit({exit_code => 1}); } elsif (not -e $file) { # Can't do anything, file doesn't exist $anvil->Job->update_progress({ progress => 100, message => "error_0171,!!file!".$file."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0171", variables => { file => $file }}); $anvil->nice_exit({exit_code => 1}); } # Make sure the file actually done uploading. $anvil->data->{sys}{progress} = 5; $anvil->Job->update_progress({ progress => $anvil->data->{sys}{progress}, message => "message_0309,!!file!".$file."!!", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0309", variables => { file => $file }}); $anvil->Storage->_wait_if_changing({ debug => 2, file => $file, }); # Move it over to files. $anvil->data->{sys}{progress} = 5; $anvil->Job->update_progress({ progress => $anvil->data->{sys}{progress}, message => "message_0192,!!file!".$file."!!", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0192", variables => { file => $file }}); $anvil->Storage->move_file({ debug => 2, overwrite => 1, source_file => $file, target_file => $anvil->data->{path}{directories}{shared}{files}."/", }); my $file_name = ($file =~ /\/.*\/(.*?)$/)[0]; my $target_file = $anvil->data->{path}{directories}{shared}{files}."/".$file_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_name => $file_name, target_file => $target_file, }}); if (not -e $target_file) { # Failed to move. $anvil->Job->update_progress({ progress => 100, message => "error_0172,!!file!".$file."!!,!!target_directory!".$anvil->data->{path}{directories}{shared}{files}."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0171", variables => { file => $file }}); $anvil->nice_exit({exit_code => 1}); } # Change the owner as it'll be striker-ui-api, which won't be a valid users on anvil members. $anvil->Storage->change_owner({ debug => 2, path => $target_file, user => "root", group => "root", }); # Calculate the md5sum. $anvil->data->{sys}{progress} = 20; $anvil->Job->update_progress({ progress => $anvil->data->{sys}{progress}, message => "message_0193", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0193"}); my ($string, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{md5sum}." ".$target_file}); my $md5sum = ($string =~ /^(.*?)\s/)[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { string => $string, md5sum => $md5sum, return_code => $return_code, }}); # Store the file details! $anvil->data->{sys}{progress} = 30; $anvil->Job->update_progress({ progress => $anvil->data->{sys}{progress}, message => "message_0194,!!md5sum!".$md5sum."!!", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0194", variables => { md5sum => $md5sum }}); $anvil->Storage->get_file_stats({ debug => 2, file_path => $target_file, }); my $file_mimetype = $anvil->data->{file_stat}{$target_file}{mimetype}; my $file_size = $anvil->data->{file_stat}{$target_file}{size}; my $file_mtime = $anvil->data->{file_stat}{$target_file}{modified_time}; my $executable = -x $target_file ? 1 : 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_mimetype => $file_mimetype, file_size => $file_size." (".$anvil->Convert->bytes_to_human_readable({"bytes" => $file_size}).")", file_mtime => $file_mtime, executable => $executable, }}); # This is the file's type/purpose. The expected values are 'iso', 'rpm', 'script', 'disk-image', or # 'other'. If set to 'DELETED', the file will be removed from disk. my $file_type = "other"; if ($file_mimetype =~ /cd-image/) { $file_type = "iso"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_type => $file_type }}); } # This will need to be expanded over time elsif (($executable) or ($file_mimetype =~ /perl/) or ($file_mimetype =~ /python/)) { $file_type = "script"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_type => $file_type }}); # Change the mode to be executable $anvil->Storage->change_mode({ debug => 2, path => $target_file, mode => "0755", }); } elsif ($file_mimetype =~ /raw-disk-image/) { $file_type = "image"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_type => $file_type }}); } my $file_uuid = $anvil->Database->insert_or_update_files({ debug => 2, file_name => $file_name, file_directory => $anvil->data->{path}{directories}{shared}{files}, file_size => $file_size, file_md5sum => $md5sum, file_type => $file_type, file_mtime => $file_mtime, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_uuid => $file_uuid }}); # Now copy this to our peers. We're going to do this serially so that we don't overwhelm the system, # Any hosts not currently online will have a job registered. $anvil->Storage->push_file({ debug => 2, file => $target_file, file_uuid => $file_uuid, }); # Call track_files, it'll make sure the file_locations are setup. $anvil->Database->track_files({debug => 2}); # Done! $anvil->Job->update_progress({ progress => 100, message => "message_0197", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0197"}); return(0); } # This pulls files from dashboards onto the running host. sub process_pull_file { my ($anvil) = @_; $anvil->Job->update_progress({ progress => $anvil->data->{sys}{progress}, message => "message_0198", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0198" }); # Collect some data $anvil->Database->get_anvils({debug => 3}); $anvil->Database->get_files({debug => 3}); $anvil->Database->get_file_locations({debug => 3}); my $file_uuid = ($anvil->data->{jobs}{job_data} =~ /file_uuid=(.*)$/)[0]; my $anvil_uuid = $anvil->Cluster->get_anvil_uuid({debug => 2}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid, file_uuid => $file_uuid, }}); if (not $file_uuid) { # Can't do anything, file wasn't parsed. $anvil->Job->update_progress({ progress => 100, message => "error_0173,!!job_uuid!".$anvil->data->{switches}{'job-uuid'}."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0173", variables => { job_uuid => $anvil->data->{switches}{'job-uuid'} }}); $anvil->nice_exit({exit_code => 1}); } elsif (not exists $anvil->data->{files}{file_uuid}{$file_uuid}) { # File UUID doesn't appear to be valid. $anvil->Job->update_progress({ progress => 100, message => "error_0174,!!file_uuid!".$file_uuid."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0174", variables => { file_uuid => $file_uuid }}); $anvil->nice_exit({exit_code => 1}); } my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name}; my $file_directory = $anvil->data->{files}{file_uuid}{$file_uuid}{file_directory}; my $file_path = $file_directory."/".$file_name; my $file_size = $anvil->data->{files}{file_uuid}{$file_uuid}{file_size}; my $file_md5sum = $anvil->data->{files}{file_uuid}{$file_uuid}{file_md5sum}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:file_name' => $file_name, 's2:file_directory' => $file_directory, 's3:file_path' => $file_path, 's4:file_size' => $file_size." (".$anvil->Convert->bytes_to_human_readable({"bytes" => $file_size}).")", 's5:file_md5sum' => $file_md5sum, }}); if (not $anvil_uuid) { # Uhhh... $anvil->Job->update_progress({ progress => 100, message => "error_0175,!!file!".$file_path."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0175", variables => { file => $file_path }}); $anvil->nice_exit({exit_code => 1}); } # How many Strikers are up and have the file we're looking for? $anvil->data->{target_strikers} = []; foreach my $host_uuid (keys %{$anvil->data->{database}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }}); my $host_name = $anvil->Get->host_name_from_uuid({debug => 2, host_uuid => $host_uuid}); my $target = $anvil->data->{database}{$host_uuid}{host}; my $password = $anvil->data->{database}{$host_uuid}{password}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name, target => $target, password => $anvil->Log->is_secure($password), }}); # If the file exists, the return code is '0'. If the file isn't found, '1' is returned. # When found, the size in bytes followed by the file name is returned. my $shell_call = $anvil->data->{path}{exe}{wc}." -c ".$file_path; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); my ($output, $error, $return_code) = $anvil->Remote->call({ debug => 3, shell_call => $shell_call, target => $target, password => $password, remote_user => "root", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, error => $error, output => $output, }}); if ($output =~ /^(\d+)\s+$file_path$/) { my $size_on_peer = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { size_on_peer => $size_on_peer." (".$anvil->Convert->bytes_to_human_readable({"bytes" => $size_on_peer}).")" }}); # For now, we only do a size check as md5sums can take a long time. if ($size_on_peer eq $file_size) { # We can pull from this striker! push @{$anvil->data->{target_strikers}}, { host_name => $host_name, host_uuid => $host_uuid, target => $target, password => $password, }; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name, host_uuid => $host_uuid, target => $target, password => $anvil->Log->is_secure($password), }}); } else { # The file doesn't exist or we couldn't contact the Striker, so we'll skip # it. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0576", variables => { file_path => $file_path, host_name => $host_name, }}); } } } my $anvil_node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; my $anvil_node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_node1_host_uuid => $anvil_node1_host_uuid, anvil_node2_host_uuid => $anvil_node2_host_uuid, }}); # Where we pull from will depend on which machine we are and how many strikers we have. If we have # one Anvil!, sub-node 1 and 2 download at the same time. If there are two strikers, Each node will # download from a different striker (if possible). my $i_am = "node1"; if ($anvil->Get->host_uuid eq $anvil_node2_host_uuid) { $i_am = "node2"; } my $striker_count = @{$anvil->data->{target_strikers}}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { i_am => $i_am, striker_count => $striker_count, }}); if (not $striker_count) { # No available Strikers. $anvil->Job->update_progress({ progress => 1, message => "warning_0072,!!file_path!".$file_path."!!", job_status => "failed", }); sleep 60; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "warning_0072", variables => { file_path => $file_path }}); $anvil->nice_exit({exit_code => 2}); } my $use = 0; if ($striker_count >= 3) { if ($i_am eq "node1") { $use = 0; } elsif ($i_am eq "node2") { $use = 1; } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'use' => $use }}); } elsif ($striker_count == 2) { # Two strikers, each node will use the other Striker if ($i_am eq "node1") { $use = 0; } elsif ($i_am eq "node2") { $use = 1; } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'use' => $use }}); } elsif ($striker_count == 1) { # Only 1 Striker if ($i_am eq "node1") { $use = 0; } elsif ($i_am eq "node2") { $use = 0; } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'use' => $use }}); } # Now proceed with the download! my $target_host_name = $anvil->data->{target_strikers}->[$use]->{host_name}; my $target_host_uuid = $anvil->data->{target_strikers}->[$use]->{host_uuid}; my $target_host = $anvil->data->{target_strikers}->[$use]->{target}; my $target_password = $anvil->data->{target_strikers}->[$use]->{password}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_host_name => $target_host_name, target_host_uuid => $target_host_uuid, target_host => $target_host, target_password => $anvil->Log->is_secure($target_password), }}); # Rsync the file. my $say_source_file = "root\@".$target_host.":".$file_path; my $target_directory = $file_directory."/"; $anvil->Job->update_progress({ progress => 50, message => "message_0200,!!source_file!".$say_source_file."!!,!!target_directory!".$target_directory."!!", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0200", variables => { source_file => $say_source_file, target_directory => $target_directory, }}); $anvil->Storage->rsync({ debug => 2, source => $say_source_file, destination => $target_directory, try_again => 1, }); if (-e $file_path) { # Calculate the md5sum. $anvil->Job->update_progress({ progress => 75, message => "message_0201", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0201"}); my $local_md5sum = $anvil->Get->md5sum({file => $file_path}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_md5sum => $local_md5sum }}); if ($file_md5sum eq $local_md5sum) { $anvil->Job->update_progress({ progress => 100, message => "message_0202", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0202"}); $anvil->nice_exit({exit_code => 0}); } else { # Unlink the file. The perioding sync call can try again later. unlink $file_path; $anvil->Job->update_progress({ progress => 1, message => "error_0176,!!local_md5sum!".$local_md5sum."!!,!!file_md5sum!".$file_md5sum."!!", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0176", variables => { local_md5sum => $local_md5sum, file_md5sum => $file_md5sum, }}); sleep 60; $anvil->nice_exit({exit_code => 1}); } } else { # Failed... $anvil->Job->update_progress({ progress => 1, message => "error_0177", job_status => "failed", }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => 'err', key => "error_0177" }); sleep 60; $anvil->nice_exit({exit_code => 1}); } return(0); } # This takes a host and job UUID and determines if we're still waiting on the target. sub wait_on_host { my ($anvil, $host_uuid, $job_uuid) = @_; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid." (".$anvil->Get->host_name_from_uuid({host_uuid => $host_uuid}).")", job_uuid => $job_uuid, }}); my $waiting = 1; # Look up the job progress. my $query = "SELECT job_progress FROM jobs WHERE job_uuid = ".$anvil->Database->quote($job_uuid).";"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); my $progress = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { progress => $progress }}); if ($progress == 100) { $waiting = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); } else { # Can I ping the node? my $pinged = 0; foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$host_uuid}{interface}}) { my $target_ip = $anvil->data->{network}{$host_uuid}{interface}{$interface}{ip}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface, target_ip => $target_ip, }}); ($pinged, my $average_time) = $anvil->Network->ping({ ping => $target_ip, count => 1, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { pinged => $pinged }}); last if $pinged; } if (not $pinged) { # Stop waiting, it looks to be offline. $waiting = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); } } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); return($waiting) }