Subversion Repositories sysadmin_scripts

Rev

Rev 17 | Rev 19 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 17 Rev 18
Line 1... Line 1...
1
#! /usr/bin/env perl
1
#! /usr/bin/env perl
2
 
2
 
3
# archiveDirectories.pl
3
# archiveDirectories.pl
4
# Author: R. W. Rodolico
4
# Author: R. W. Rodolico
5
# Date: 20180603
5
# Date: 20180603
-
 
6
 
6
# Copyright: 2018, Vanduzen Enterprises, Dallas TX
7
# Copyright (c) 2018, Daily Data, Inc
-
 
8
# All rights reserved.
-
 
9
# 
-
 
10
# Redistribution and use in source and binary forms, with or without
-
 
11
# modification, are permitted provided that the following conditions are met:
-
 
12
# 
-
 
13
# 1. Redistributions of source code must retain the above copyright notice, this
-
 
14
#    list of conditions and the following disclaimer.
-
 
15
# 2. Redistributions in binary form must reproduce the above copyright notice,
-
 
16
#    this list of conditions and the following disclaimer in the documentation
-
 
17
#    and/or other materials provided with the distribution.
-
 
18
# 
-
 
19
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-
 
20
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-
 
21
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-
 
22
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-
 
23
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-
 
24
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-
 
25
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-
 
26
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 
27
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-
 
28
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 
29
# 
-
 
30
# The views and conclusions contained in the software and documentation are those
-
 
31
# of the authors and should not be interpreted as representing official policies,
-
 
32
# either expressed or implied, of the <project name> project.
7
 
33
 
8
# Script designed to be run from a cron job, which checks if any directories
34
# Script designed to be run from a cron job, which checks if any directories
9
# are ready to be archived. A directory is defined as a directory under
35
# are ready to be archived. A directory is defined as a directory under
10
# the root of $config{'local root dir'}.
36
# the root of $config{'local root dir'}.
11
 
37
 
Line 19... Line 45...
19
# $config{'target final directory'}.
45
# $config{'target final directory'}.
20
# After the copy and move, the directory and its MD5 sum file are moved
46
# After the copy and move, the directory and its MD5 sum file are moved
21
# to the $config{'local trash dir'} (which is cleaned on the next invocation of
47
# to the $config{'local trash dir'} (which is cleaned on the next invocation of
22
# the script).
48
# the script).
23
 
49
 
24
# Script does NOT handle the situation where directories are being moved
-
 
25
# while the script is running, so the script should be run at a time
-
 
26
# when there is no other activity on the server.
-
 
27
#
50
#
28
# Version: 1.0
51
# Version: 1.0
29
 
52
 
30
use warnings;
53
use warnings;
31
use strict;
54
use strict;
32
use Cwd qw();
55
use Cwd qw();
33
use File::Copy qw(move);
56
use File::Copy qw(move);
34
use File::Basename;
57
use File::Basename;
35
use File::stat;
58
use File::stat;
36
 
59
 
-
 
60
our $VERSION = '1.0';
-
 
61
 
37
my $DEBUG = 5;
62
my $DEBUG = 0;
38
 
63
 
39
my %config;
64
my %config;
40
 
65
 
41
my @DirectoriesToMove;
66
my @DirectoriesToMove;
42
 
67
 
Line 54... Line 79...
54
   } else {
79
   } else {
55
      die "Could not locate config file $configFileName\n";
80
      die "Could not locate config file $configFileName\n";
56
   } # if..else
81
   } # if..else
57
} #loadConfig
82
} #loadConfig
58
 
83
 
59
# simply read the entire fiel into a string
84
# simply read the entire file into a string
60
sub slurpFile {
85
sub slurpFile {
61
   my $filename = shift;
86
   my $filename = shift;
62
   return '' unless -e $filename;
87
   return '' unless -e $filename;
63
   open TEMP, "<$filename" or die "could not read $filename: $!\n";
88
   open TEMP, "<$filename" or die "could not read $filename: $!\n";
64
   my @contents = <TEMP>;
89
   my @contents = <TEMP>;
Line 72... Line 97...
72
   open TEMP, ">$filename" or die "could not write to $filename: $!\n";
97
   open TEMP, ">$filename" or die "could not write to $filename: $!\n";
73
   print TEMP join( '', @_ );
98
   print TEMP join( '', @_ );
74
   close TEMP;
99
   close TEMP;
75
}
100
}
76
 
101
 
-
 
102
# returns how many seconds ago a file was created
-
 
103
sub fileAge {
-
 
104
   my $filename = shift;
-
 
105
   my $age = stat( $filename );
-
 
106
   $age = $$age[9];
-
 
107
   print "$age\t$filename" if $DEBUG > 3;
-
 
108
   return time - $age;
-
 
109
}
-
 
110
   
-
 
111
 
77
# look in the directories to move directory and see if there is anything 
112
# look in the directories to move directory and see if there is anything 
78
# new in there. If so, check MD5 Sum file (create if necessary) and ensure
113
# new in there. If so, check MD5 Sum file (create if necessary) and ensure
79
# we have waited long enough and the sums match
114
# we have waited long enough and the sums match
80
sub getDirectories {
115
sub getDirectories {
81
   my $rootDir = shift;
116
   my $rootDir = shift;
Line 91... Line 126...
91
      print "\tFound Dir $fullyQualified with MD5 of $md5\n" if $DEBUG > 2;
126
      print "\tFound Dir $fullyQualified with MD5 of $md5\n" if $DEBUG > 2;
92
      # let's look for the md5 checksum file and compare if it exist
127
      # let's look for the md5 checksum file and compare if it exist
93
      my $md5Name = "$fullyQualified.$config{'md5 suffix'}";
128
      my $md5Name = "$fullyQualified.$config{'md5 suffix'}";
94
      if ( -e $md5Name ) {
129
      if ( -e $md5Name ) {
95
         # find out when it was last written to
130
         # find out when it was last written to
96
         my $lastModification = stat( $md5Name );
-
 
97
         $lastModification = $$lastModification[9];
-
 
98
         my $howOld = time - $lastModification;
-
 
99
         print "\tFound existing MD5 file $md5Name written to at $lastModification, or $howOld seconds ago\n" if $DEBUG > 3;
131
         print "\tFound existing MD5 file $md5Name\n" if $DEBUG > 3;
100
         # and blow it off if it is too recent
132
         # and blow it off if it is too recent
101
         if ( $howOld < $config{'quiesent seconds'} ) {
133
         if ( &fileAge( $md5Name) < $config{'quiesent seconds'} ) {
102
            print "\t\tBlowing it off because $howOld is less than $config{'quiesent seconds'}\n" if $DEBUG > 4;
134
            print "\t\tBlowing it off because it is less than $config{'quiesent seconds'} seconds old\n" if $DEBUG > 4;
103
            next;
135
            next;
104
         }
136
         }
105
         my $oldMD5 = &slurpFile( $md5Name );
137
         my $oldMD5 = &slurpFile( $md5Name );
106
         if ( $md5 eq $oldMD5 ) {
138
         if ( $md5 eq $oldMD5 ) {
107
            print "\t\tAdding, md5 not changed, $md5 same as $oldMD5\n" if $DEBUG > 4;
139
            print "\t\tAdding, md5 not changed, $md5 same as $oldMD5\n" if $DEBUG > 4;
Line 202... Line 234...
202
   }
234
   }
203
   return ('', 0);
235
   return ('', 0);
204
}
236
}
205
      
237
      
206
   
238
   
207
# simply remove everything from the trash directory
-
 
208
sub cleanTrash {
-
 
209
   my ( $trashDir, $age ) = @_;
-
 
210
   `mkdir -p $trashDir` unless -d $trashDir;
-
 
211
   `rm -fR $trashDir/*`;
-
 
212
}
-
 
213
 
-
 
214
sub copyToRemote {
239
sub copyToRemote {
215
   my ( $path, $dirname, $remoteServer, $remotePath ) = @_;
240
   my ( $path, $dirname, $remoteServer, $remotePath ) = @_;
216
   # first, copy the file
241
   # first, copy the file
217
   #print "rsync -a $path/$dirname $remoteServer:$remotePath > /tmp/lastrsync.log";
242
   #print "rsync -a $path/$dirname $remoteServer:$remotePath > /tmp/lastrsync.log";
218
   #die;
243
   #die;
219
   qx"rsync -a $path/$dirname $remoteServer:$remotePath > /tmp/lastrsync.log";
244
   qx"rsync -a $path/$dirname $remoteServer:$remotePath > /tmp/lastrsync.log";
220
   return 'rsync failed with error :' . $? & 127 if $? & 127;
245
   return 'rsync failed with error :' . $? & 127 if $? & 127;
221
   return '';
246
   return '';
222
}
247
}
223
 
248
 
-
 
249
# simply remove everything from the trash directory over $age seconds old
-
 
250
sub cleanTrash {
-
 
251
   my ( $trashDir, $age ) = @_;
-
 
252
   my $md5Suffix = $config{'md5 suffix'};
-
 
253
   my @toRemove = ();
-
 
254
   if ( opendir( my $dh, $trashDir ) ) {
-
 
255
      # get all the md5sum files which are older than $age seconds old
-
 
256
      @toRemove = grep { &fileAge( "$_" ) > $age  } map{ "$trashDir/$_" }  grep{ /$md5Suffix$/ } readdir( $dh);
-
 
257
      closedir( $dh );
-
 
258
   }
-
 
259
   print "You should remove the following files\n" if $DEBUG > 1;
-
 
260
   foreach my $thisDir ( @toRemove ) {
-
 
261
      $thisDir =~ m/(.*)\.$md5Suffix/;
-
 
262
      $thisDir = $1;
-
 
263
      qx/rm -fR $thisDir $thisDir.$md5Suffix/;
-
 
264
   }
-
 
265
}
-
 
266
 
-
 
267
 
-
 
268
 
224
###############################################################################
269
###############################################################################
225
# Main
270
# Main
226
###############################################################################
271
###############################################################################
227
 
272
 
228
&loadConfig();
273
&loadConfig();
Line 234... Line 279...
234
   `mkdir -p $config{'local root dir'}`;
279
   `mkdir -p $config{'local root dir'}`;
235
   `chmod 777 $config{'local root dir'}`;
280
   `chmod 777 $config{'local root dir'}`;
236
}
281
}
237
# clean the trash if $config{ 'trash cleanup' } is non-zero
282
# clean the trash if $config{ 'trash cleanup' } is non-zero
238
&cleanTrash( $config{'local trash dir'}, $config{ 'trash cleanup' } ) if $config{ 'trash cleanup' };
283
&cleanTrash( $config{'local trash dir'}, $config{ 'trash cleanup' } ) if $config{ 'trash cleanup' };
239
   
284
 
240
# Check if we have any directories which are ready to be moved.
285
# Check if we have any directories which are ready to be moved.
241
@DirectoriesToMove = &getDirectories( $config{'local root dir'} );
286
@DirectoriesToMove = &getDirectories( $config{'local root dir'} );
242
 
287
 
243
print "Processing\n\t" . join( "\n\t", @DirectoriesToMove ) . "\n";
288
print "Processing\n\t" . join( "\n\t", @DirectoriesToMove ) . "\n" if $DEBUG > 1;
244
 
289
 
245
foreach my $directory ( @DirectoriesToMove ) {
290
foreach my $directory ( @DirectoriesToMove ) {
246
   my $fullPath = $config{'local root dir'} . "/$directory";
291
   my $fullPath = $config{'local root dir'} . "/$directory";
247
   my $logFile = "$fullPath.$config{'log suffix'}";
292
   my $logFile = "$fullPath.$config{'log suffix'}";
248
   my $errorFile = "$fullPath.$config{'error suffix'}";
293
   my $errorFile = "$fullPath.$config{'error suffix'}";
Line 269... Line 314...
269
opendir( my $dh, $config{'local staging area'} ) or die "Could not read $config{'local staging area'}: $!\n";
314
opendir( my $dh, $config{'local staging area'} ) or die "Could not read $config{'local staging area'}: $!\n";
270
my @directories;
315
my @directories;
271
# get all the .md5 files
316
# get all the .md5 files
272
my @toMove = grep { /$config{'md5 suffix'}$/ } readdir( $dh );
317
my @toMove = grep { /$config{'md5 suffix'}$/ } readdir( $dh );
273
my $targetPath = "$config{'target server'}:$config{'target staging area'}/";
318
my $targetPath = "$config{'target server'}:$config{'target staging area'}/";
274
print "Copying the following to $targetPath\n\t" . join ("\n\t", @toMove ) . "\n";
319
print "Copying the following to $targetPath\n\t" . join ("\n\t", @toMove ) . "\n" if $DEBUG > 1;
275
# create the target directory on the server if it doesn't exist
320
# create the target directory on the server if it doesn't exist
276
&runRemoteCommand( $config{'target server'},
321
&runRemoteCommand( $config{'target server'},
277
   "[ ! -d $config{'target staging area'} ] && mkdir -p $config{'target staging area'}",
322
   "[ ! -d $config{'target staging area'} ] && mkdir -p $config{'target staging area'}",
278
   "[ ! -d $config{'target final directory'} ] && mkdir -p $config{'target final directory'}"
323
   "[ ! -d $config{'target final directory'} ] && mkdir -p $config{'target final directory'}"
279
   );
324
   );
Line 299... Line 344...
299
   &logit( $dirname, $config{'log suffix'}, $rsync );
344
   &logit( $dirname, $config{'log suffix'}, $rsync );
300
   if ( system ( $rsync ) == 0 ) { # we succeeded
345
   if ( system ( $rsync ) == 0 ) { # we succeeded
301
      if ( &validateTarget( $config{'target server'}, $config{'target staging area'}, $config{'target final directory'}, $dirname, $md5sum ) ) {
346
      if ( &validateTarget( $config{'target server'}, $config{'target staging area'}, $config{'target final directory'}, $dirname, $md5sum ) ) {
302
         `mkdir -p $config{'local trash dir'}` unless -d $config{'local trash dir'};
347
         `mkdir -p $config{'local trash dir'}` unless -d $config{'local trash dir'};
303
         move( "$config{'local staging area'}/$dirname", "$config{'local trash dir'}/$dirname" );
348
         move( "$config{'local staging area'}/$dirname", "$config{'local trash dir'}/$dirname" );
304
         $dirname .= $config{'md5 suffix'};
349
         my $md5File = $dirname . '.' . $config{'md5 suffix'};
305
         move( "$config{'local staging area'}/$dirname", "$config{'local trash dir'}/$dirname" );
350
         move( "$config{'local staging area'}/$md5File", "$config{'local trash dir'}/$md5File" );
306
         &logit( $dirname, $config{'log suffix'}, "Successfully moved directory $dirname to $config{'target server'}" );
351
         &logit( $dirname, $config{'log suffix'}, "Successfully moved directory $dirname to $config{'target server'}" );
307
      } else {
352
      } else {
308
         &logit( $dirname, $config{'error suffix'}, "Unable to validate target for $dirname" );
353
         &logit( $dirname, $config{'error suffix'}, "Unable to validate target for $dirname" );
309
      }
354
      }
310
   } else {
355
   } else {