Subversion Repositories zfs_utils

Rev

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

Rev 43 Rev 44
Line 45... Line 45...
45
 
45
 
46
use FindBin;
46
use FindBin;
47
use lib "$FindBin::Bin/..";
47
use lib "$FindBin::Bin/..";
48
use Data::Dumper;
48
use Data::Dumper;
49
use ZFS_Utils qw(loadConfig shredFile logMsg makeReplicateCommands mountDriveByLabel unmountDriveByLabel mountGeli runCmd sendReport fatalError cleanDirectory $logFileName $displayLogsOnConsole);
49
use ZFS_Utils qw(loadConfig shredFile logMsg makeReplicateCommands mountDriveByLabel unmountDriveByLabel mountGeli runCmd sendReport fatalError cleanDirectory $logFileName $displayLogsOnConsole);
-
 
50
use Getopt::Long qw(GetOptions);
-
 
51
Getopt::Long::Configure ("bundling");
50
 
52
 
51
my $scriptDirectory = $FindBin::RealBin;
53
my $scriptDirectory = $FindBin::RealBin;
52
my $scriptFullPath = "$scriptDirectory/" . $FindBin::Script;
54
my $scriptFullPath = "$scriptDirectory/" . $FindBin::Script;
53
 
55
 
54
 
-
 
55
# if set, will not actually write files to disk
-
 
56
my $DEBUG = 1;
-
 
57
 
-
 
58
# display all log messages on console in addition to the log file
56
# display all log messages on console in addition to the log file
59
$displayLogsOnConsole = 1;
57
$displayLogsOnConsole = 1;
60
 
58
 
61
my $configFileName = "$scriptFullPath.conf.yaml";
59
my $configFileName = "$scriptFullPath.conf.yaml";
62
 
60
 
63
my $config = {
61
my $config = {
-
 
62
   'dryrun' => 0,
-
 
63
   'verbosity' => 1,
64
   # file created on source server to track last copyed dataset
64
   # file created on source server to track last copyed dataset
65
   'status_file' => "$scriptFullPath.status",
65
   'status_file' => "$scriptFullPath.status",
66
   'log_file' => "$scriptFullPath.log",
66
   'log_file' => "$scriptFullPath.log",
67
   #information about source server
67
   #information about source server
68
   'source' => {
68
   'source' => {
Line 201... Line 201...
201
   my ($config, $statusList) = @_;
201
   my ($config, $statusList) = @_;
202
   my $newStatus = [];
202
   my $newStatus = [];
203
   foreach my $dataset ( sort keys %{$config->{datasets}} ) {
203
   foreach my $dataset ( sort keys %{$config->{datasets}} ) {
204
      logMsg("Processing dataset '$dataset'");
204
      logMsg("Processing dataset '$dataset'");
205
      # get list of all snapshots on dataset
205
      # get list of all snapshots on dataset
-
 
206
      my $sourceList;
-
 
207
      if ( -e "$scriptDirectory/test.status") {
206
      my $root = $config->{datasets}->{$dataset}->{source} . '/' . $config->{datasets}->{$dataset}->{dataset};
208
         $sourceList = getStatusFile( "$scriptDirectory/test.status" );
-
 
209
      } else {
207
      my $sourceList = [ runCmd( "zfs list -rt snap -H -o name $root" ) ];
210
         $sourceList = [ runCmd( "zfs list -rt snap -H -o name $config->{datasets}-{$dataset}->{source}" ) ];
-
 
211
      }
-
 
212
      
208
      # remove the parent part, leave the dataset itself
213
      # remove the parent part, leave the dataset itself
209
      $sourceList =~ s|$config->{datasets}->{$dataset}->{source}/||;
214
      $sourceList =~ s|/||;
210
      # process dataset here
215
      # process dataset here
211
      my $commands = makeReplicateCommands( $sourceList, $statusList, $newStatus );
216
      my $commands = makeReplicateCommands( 
212
 
-
 
-
 
217
                        $sourceList,
-
 
218
                        $statusList,
-
 
219
                        $dataset,
-
 
220
                        $config->{datasets}->{$dataset}->{source},
-
 
221
                        $config->{datasets}->{$dataset}->{target},
-
 
222
                        $newStatus
-
 
223
                     );
213
      if ( %$commands ) {
224
      if ( %$commands ) {
214
         foreach my $cmd ( keys %$commands ) {
225
         foreach my $cmd ( keys %$commands ) {
215
            my $command = $commands->{$cmd};
226
            my $command = $commands->{$cmd};
216
            my $outputFile = $cmd;
227
            my $outputFile = $cmd;
217
            $outputFile =~ s/^$root//;
228
            #$outputFile =~ s/^$root//;
218
            $outputFile = replaceSlashWithDot($outputFile);
229
            $outputFile = replaceSlashWithDot($outputFile);
219
            #$command .= " | openssl enc -aes-256-cbc -K $config->{transport}->{encryption}->{key} -iv $config->{transport}->{encryption}->{IV} " if $config->{transport}->{encryption}->{key};
230
            #$command .= " | openssl enc -aes-256-cbc -K $config->{transport}->{encryption}->{key} -iv $config->{transport}->{encryption}->{IV} " if $config->{transport}->{encryption}->{key};
220
            $command .= " > $config->{transport}->{mount_point}/" . $outputFile;
231
            $command .= " > $config->{transport}->{mount_point}/" . $cmd;
221
            logMsg("Running command: $command");
232
            logMsg("Running command: $command");
222
            runCmd(  $command  ) unless $DEBUG;
233
            runCmd(  $command  ) unless $config->{dryrun};
223
         }
234
         }
224
      } else {
235
      } else {
225
         logMsg( "Nothing to do for $dataset" ); 
236
         logMsg( "Nothing to do for $dataset" ); 
226
      }
237
      }
227
   }
238
   }
Line 241... Line 252...
241
   chomp $servername;
252
   chomp $servername;
242
   logMsg( "Zpools on server $servername:\n" . join( "\n", runCmd( "zpool list" ) ) . "\n" );
253
   logMsg( "Zpools on server $servername:\n" . join( "\n", runCmd( "zpool list" ) ) . "\n" );
243
   $config->{$config->{runningAs}}->{report}->{subject} //= "Replication Report for $config->{runningAs} server $servername";
254
   $config->{$config->{runningAs}}->{report}->{subject} //= "Replication Report for $config->{runningAs} server $servername";
244
   $message //= "Replication completed on $config->{runningAs} server $servername.";
255
   $message //= "Replication completed on $config->{runningAs} server $servername.";
245
   # unmount the sneakernet drive
256
   # unmount the sneakernet drive
246
   unmountDriveByLabel( $config->{transport} );
257
   unmountDriveByLabel( $config->{transport} ) unless $config->{dryrun};
247
   sendReport( $config->{$config->{runningAs}}->{report}, $message, $config->{log_file} );
258
   sendReport( $config->{$config->{runningAs}}->{report}, $message, $config->{log_file} );
248
   # If they have requested shutdown, do it now
259
   # If they have requested shutdown, do it now
249
   if ( $config->{$config->{runningAs}}->{shutdown_after_replication} ) {
260
   if ( $config->{$config->{runningAs}}->{shutdown_after_replication} ) {
250
      logMsg( "Shutting down target server as per configuration" );
261
      logMsg( "Shutting down target server as per configuration" );
251
      runCmd( "shutdown -p now" ) unless $DEBUG;
262
      runCmd( "shutdown -p now" ) unless $config->{dryrun};
252
   }
263
   }
253
}
264
}
254
 
265
 
255
# update the target datasets from the files on the transport drive
266
# update the target datasets from the files on the transport drive
256
sub updateTarget {
267
sub updateTarget {
Line 268... Line 279...
268
 
279
 
269
# If a YAML config file exists next to the script, load and merge it
280
# If a YAML config file exists next to the script, load and merge it
270
$config = loadConfig($configFileName, $config );
281
$config = loadConfig($configFileName, $config );
271
exit 1 unless keys %$config;
282
exit 1 unless keys %$config;
272
 
283
 
-
 
284
# parse CLI options
-
 
285
GetOptions( $config,
-
 
286
   'dryrun|n',
-
 
287
   'verbose|v+',
-
 
288
   'version|V',
-
 
289
   'help|h',
-
 
290
) or do { print "Invalid options\n"; exit 2 };
-
 
291
if (defined ($config->{help})) {
-
 
292
   print "Usage: $FindBin::Script [--dryrun] [--verbose] [--help]\n";
-
 
293
   print "  --dryrun, -n   Run in dry-run mode (no writes)\n";
-
 
294
   print "  --verbose, -v  Run in verbose mode (more v's mean more verbose)\n";
-
 
295
   print "  --version, -V  Display version number\n";
-
 
296
   exit 0;
-
 
297
} elsif (defined $config->{version}) {
-
 
298
   print "$FindBin::Script v$VERSION\n";
-
 
299
   exit 0;
-
 
300
}
-
 
301
 
273
# set some defaults
302
# set some defaults
274
$config->{'status_file'} //= "$scriptFullPath.status";
303
$config->{'status_file'} //= "$scriptFullPath.status";
275
# set log file name for sub logMsg in ZFS_Utils, and remove the old log if it exists
304
# set log file name for sub logMsg in ZFS_Utils, and remove the old log if it exists
276
# Log file is only valid for one run
305
# Log file is only valid for one run
277
$logFileName = $config->{'log_file'} //= "$scriptFullPath.log";
306
$logFileName = $config->{'log_file'} //= "$scriptFullPath.log";
Line 288... Line 317...
288
 
317
 
289
#cleanup( $config, "Testing" );
318
#cleanup( $config, "Testing" );
290
 
319
 
291
# mount the transport drive, fatal error if we can not find it
320
# mount the transport drive, fatal error if we can not find it
292
fatalError( "Unable to mount tranport drive with label $config->{transport}->{disk_label}", $config, \&cleanup )
321
fatalError( "Unable to mount tranport drive with label $config->{transport}->{disk_label}", $config, \&cleanup )
293
   unless $config->{transport}->{mount_point} =  mountDriveByLabel( $config->{transport} );
322
   unless $config->{dryrun} or $config->{transport}->{mount_point} =  mountDriveByLabel( $config->{transport} );
294
 
323
 
295
# mail program logic
324
# main program logic
296
if ( $config->{runningAs} eq 'source' ) {
325
if ( $config->{runningAs} eq 'source' ) {
297
    logMsg "Running as source server";
326
    logMsg "Running as source server";
298
    # remove all files from transport disk, but leave all subdirectories alone
327
    # remove all files from transport disk, but leave all subdirectories alone
299
   fatalError( "Failed to clean transport directory $config->{transport}->{mount_point}", $config, \&cleanup )
328
   fatalError( "Failed to clean transport directory $config->{transport}->{mount_point}", $config, \&cleanup )
300
      unless cleanDirectory( $config->{transport}->{mount_point} );
329
      unless $config->{dryrun} or cleanDirectory( $config->{transport}->{mount_point} );
301
    my $statusList = getStatusFile($config->{status_file});
330
    my $statusList = getStatusFile($config->{status_file});
302
    $statusList = doSourceReplication($config, $statusList); 
331
    $statusList = doSourceReplication($config, $statusList); 
303
    writeStatusFile($config->{status_file}, $statusList);
332
    writeStatusFile($config->{status_file}, $statusList) unless $config->{dryrun};
304
} elsif ( $config->{runningAs} eq 'target' ) {
333
} elsif ( $config->{runningAs} eq 'target' ) {
305
    logMsg "Running as target server";
334
    logMsg "Running as target server";
306
    mountGeli( $config->{target}->{geli} ) if ( defined $config->{target}->{geli} );
335
    mountGeli( $config->{target}->{geli} ) if ( defined $config->{target}->{geli} );
307
    updateTarget( $config );
336
    updateTarget( $config );
308
} else {
337
} else {