#!/usr/bin/perl # # This handles moving around and managing files on Anvil! nodes, DR hosts and Striker dashboards. # # When this is called (periodically by the daemon of after an upload / ISO generation); # - 1. Check 'incoming/' for files. For any found, generate an md5sum and see if the file name and sum match # anything in the database from any host; # - If so, update/add an entry in 'file_locations' # - If not, create a new entry in 'files' and then add the first entry in 'file_locations' # - 2. Check 'file_locations' for any files on this system, and verify they exist still. # - If not, check the other files for one with a matching md5sum. If found, handle as a rename. # - If not found at all, search for the file according to the search rules and copy to here if found. # - 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. # - 5. If called with '--is-script=[0|1]', mark as 'script' in the 'files' table and set/remove the executable bit. # # Exit codes; # 0 = Normal exit or md5sum of this program changed and it exited to reload. # 1 = No databases available. # 2 = Another process that is still running has picked up this job. # 3 = No filename specified when needed by another switch. # 4 = Request to change the file name but the new name wasn't given. # 5 = The file specified was not found. # 6 = The file to delete is not under '/mnt/shared/'. # # TODO: # - # # NOTE: # - # use strict; use warnings; use Anvil::Tools; use Data::Dumper; # Disable buffering $| = 1; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; if (($running_directory =~ /^\./) && ($ENV{PWD})) { $running_directory =~ s/^\./$ENV{PWD}/; } my $anvil = Anvil::Tools->new(); $anvil->data->{switches}{'job-uuid'} = ""; $anvil->data->{switches}{'rename'} = ""; $anvil->data->{switches}{'is-script'} = ""; $anvil->data->{switches}{file} = ""; $anvil->data->{switches}{to} = ""; $anvil->data->{switches}{'delete'} = ""; $anvil->data->{switches}{everywhere} = ""; $anvil->Get->switches; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::job-uuid" => $anvil->data->{switches}{'job-uuid'}, "switches::rename" => $anvil->data->{switches}{'rename'}, "switches::is-script" => $anvil->data->{switches}{'is-script'}, "switches::file" => $anvil->data->{switches}{file}, "switches::to" => $anvil->data->{switches}{to}, "switches::delete" => $anvil->data->{switches}{'delete'}, "switches::everywhere" => $anvil->data->{switches}{everywhere}, }}); # Connect or die $anvil->Database->connect; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); if (not $anvil->data->{sys}{database}{connections}) { # No databases, exit. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0003"}); $anvil->nice_exit({exit_code => 1}); } # If we have a job_uuid, pick it up. if ($anvil->data->{switches}{'job-uuid'}) { my $return = $anvil->Job->get_job_details({check => 1, job_uuid => $anvil->data->{switches}{'job-uuid'}}); if ($return == 1) { # It's not a UUID. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { 'return' => $return }}); $anvil->nice_exit({code => 2}); } if ($return == 2) { # This job is being handled by another process that is still alive. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { 'return' => $return }}); $anvil->nice_exit({code => 3}); } # If there's a progress, clear it. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { 'job::job_progress' => $anvil->data->{job}{job_progress} }}); if ($anvil->data->{job}{job_progress}) { $anvil->Job->update_progress({ progress => 1, message => "clear", job_uuid => $anvil->data->{jobs}{'job-uuid'}, }); } } # What are we doing? if ($anvil->data->{switches}{'rename'}) { handle_rename($anvil); } elsif ($anvil->data->{switches}{'delete'})) { handle_delete($anvil); } # We're done $anvil->nice_exit({exit_code => 0}); ############################################################################################################# # Private functions. # ############################################################################################################# # This handles deleting a file. If the requested deletion target doesn't exist, we'll just clear the # database. If that doesn't exist either, we still don't error. This is to handle broad requests to delete a # file everywhere. If we're asked to delete it everywhere, then we'll register a job against all hosts. sub handle_delete { my ($anvil) = @_; if (not $anvil->data->{switches}{file}) { # Um... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0052"}); $anvil->nice_exit({exit_code => 3}); } elsif ($anvil->data->{switches}{file} !~ /^\/mnt\/shared\//) { # We don't do that here... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0053", variables => { file => $anvil->data->{switches}{file} }}); $anvil->nice_exit({exit_code => 6}); } # Does the file exist? if (-e $anvil->data->{switches}{file}) { # Delete it. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0263", variables => { file => $anvil->data->{switches}{file} }}); unlink $anvil->data->{switches}{file}; # Sleep and verify sleep 1; if (-e $anvil->data->{switches}{file}) { # Failed to delete... # TODO: } else { # Deleted successfully. Remove from 'file_locations' ### TODO: Find the file_uuid, then if found, see if we have and entry in file_location and then delete it. } } return(0); } # This handles renaming files. sub handle_rename { my ($anvil) = @_; # Do we have the current file name and the new one? if (not $anvil->data->{switches}{file}) { # Um... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0049"}); $anvil->nice_exit({exit_code => 3}); } elsif (not $anvil->data->{switches}{to}) { # We need a target $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0050", variables => { file => $anvil->data->{switches}{file} }}); $anvil->nice_exit({exit_code => 4}); } elsif (not -f $anvil->data->{switches}{file}) { # The file to rename doesn't exist. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0051", variables => { file => $anvil->data->{switches}{file} }}); $anvil->nice_exit({exit_code => 5}); } elsif (-e $anvil->data->{switches}{to}) { # There's already a file (or directory or something) with that name. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0052", variables => { file => $anvil->data->{switches}{file}, to => $anvil->data->{switches}{to} }}); $anvil->nice_exit({exit_code => 6}); } ### TODO: Left off here return(0); }