Subversion Repositories zfs_utils

Rev

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

Rev 45 Rev 46
Line 41... Line 41...
41
use strict;
41
use strict;
42
use warnings;
42
use warnings;
43
 
43
 
44
our $VERSION = '0.1';
44
our $VERSION = '0.1';
45
 
45
 
-
 
46
use File::Basename;
46
use FindBin;
47
use FindBin;
47
use lib "$FindBin::Bin/..";
48
use lib "$FindBin::Bin/..";
48
use Data::Dumper;
49
use Data::Dumper;
49
use ZFS_Utils qw(loadConfig shredFile logMsg makeReplicateCommands mountDriveByLabel unmountDriveByLabel mountGeli runCmd sendReport fatalError cleanDirectory $logFileName $displayLogsOnConsole);
50
use ZFS_Utils qw(loadConfig shredFile logMsg makeReplicateCommands mountDriveByLabel unmountDriveByLabel mountGeli runCmd sendReport fatalError getDirectoryList cleanDirectory $logFileName $displayLogsOnConsole);
50
use Getopt::Long qw(GetOptions);
51
use Getopt::Long qw(GetOptions);
51
Getopt::Long::Configure ("bundling");
52
Getopt::Long::Configure ("bundling");
52
 
53
 
53
my $scriptDirectory = $FindBin::RealBin;
54
my $scriptDirectory = $FindBin::RealBin;
54
my $scriptFullPath = "$scriptDirectory/" . $FindBin::Script;
55
my $scriptFullPath = "$scriptDirectory/" . $FindBin::Script;
Line 183... Line 184...
183
   }
184
   }
184
}
185
}
185
 
186
 
186
# simple sub to take root/dataset/datset/dataset and turn it into
187
# simple sub to take root/dataset/datset/dataset and turn it into
187
# dataset.dataset.dataset
188
# dataset.dataset.dataset
188
sub replaceSlashWithDot {
189
sub dirnameToFileName {
189
   my $string = shift;
190
   my ( $string, $delimiter, $substitution ) = @_;
190
   my @parts = split( "/", $string );
191
   $delimiter //= '/';
191
   shift @parts;
192
   $substitution //= '.';
-
 
193
   my @parts = split( /\Q$delimiter\E/, $string );
192
   return join( '.', @parts );
194
   return join( $substitution, @parts );
193
}
195
}
194
 
196
 
195
# perform replication on source server
197
# perform replication on source server
196
# $config - configuration hashref
198
# $config - configuration hashref
197
# $statusList - list of last snapshots replicated for each dataset in previous replications
199
# $statusList - list of last snapshots replicated for each dataset in previous replications
Line 202... Line 204...
202
   my $newStatus = [];
204
   my $newStatus = [];
203
   foreach my $dataset ( sort keys %{$config->{datasets}} ) {
205
   foreach my $dataset ( sort keys %{$config->{datasets}} ) {
204
      logMsg("Processing dataset '$dataset'");
206
      logMsg("Processing dataset '$dataset'");
205
      # get list of all snapshots on dataset
207
      # get list of all snapshots on dataset
206
      my $sourceList;
208
      my $sourceList;
-
 
209
#      print Dumper( $config ) . "\n";
-
 
210
#      print "$dataset\n";
-
 
211
#      print Dumper( $config->{datasets}->{$dataset} ) . "\n";
-
 
212
#      die;
207
      if ( -e "$scriptDirectory/test.status") {
213
      if ( -e "$scriptDirectory/test.status") {
208
         $sourceList = getStatusFile( "$scriptDirectory/test.status" );
214
         $sourceList = getStatusFile( "$scriptDirectory/test.status" );
209
      } else {
215
      } else {
210
         $sourceList = [ runCmd( "zfs list -rt snap -H -o name $config->{datasets}-{$dataset}->{source}" ) ];
216
         $sourceList = [ runCmd( "zfs list -rt snap -H -o name $config->{datasets}->{$dataset}->{source}" ) ];
211
      }
217
      }
212
      
218
      
213
      # remove the parent part, leave the dataset itself
-
 
214
      $sourceList =~ s|/||;
-
 
215
      # process dataset here
219
      # process dataset here
216
      my $commands = makeReplicateCommands( 
220
      my $commands = makeReplicateCommands( 
217
                        $sourceList,
221
                        $sourceList,
218
                        $statusList,
222
                        $statusList,
219
                        $dataset,
223
                        $dataset,
Line 225... Line 229...
225
         foreach my $cmd ( keys %$commands ) {
229
         foreach my $cmd ( keys %$commands ) {
226
            my $command = $commands->{$cmd};
230
            my $command = $commands->{$cmd};
227
            my $outputFile = $cmd;
231
            my $outputFile = $cmd;
228
            $outputFile = replaceSlashWithDot($outputFile);
232
            $outputFile = replaceSlashWithDot($outputFile);
229
            $command .= " | openssl enc -aes-256-cbc -K $config->{transport}->{encryption}->{key} -iv $config->{transport}->{encryption}->{IV} " if $config->{transport}->{encryption}->{key};
233
            $command .= " | openssl enc -aes-256-cbc -K $config->{transport}->{encryption}->{key} -iv $config->{transport}->{encryption}->{IV} " if $config->{transport}->{encryption}->{key};
230
            $command .= " > $config->{transport}->{mount_point}/" . $cmd;
234
            $command .= " > $config->{transport}->{mount_point}/" . dirnameToFileName( $cmd );
231
            logMsg("Running command: $command");
235
            logMsg("Running command: $command");
232
            runCmd(  $command  ) unless $config->{dryrun};
236
            runCmd(  $command  ) unless $config->{dryrun};
233
         }
237
         }
234
      } else {
238
      } else {
235
         logMsg( "Nothing to do for $dataset" ); 
239
         logMsg( "Nothing to do for $dataset" ); 
Line 265... Line 269...
265
# update the target datasets from the files on the transport drive
269
# update the target datasets from the files on the transport drive
266
sub updateTarget {
270
sub updateTarget {
267
   my $config = shift;
271
   my $config = shift;
268
   my $files = getDirectoryList( $config->{transport}->{mount_point});
272
   my $files = getDirectoryList( $config->{transport}->{mount_point});
269
   foreach my $filename ( @$files ) {
273
   foreach my $filename ( @$files ) {
-
 
274
      my $targetDataset = basename( $filename );
-
 
275
      my ($dataset) = split( /\Q\.\E/, $targetDataset ); # grab only the first element of a string which has internal delimiters
270
     my $command = "cat $config->{output} | openssl enc -aes-256-cbc -d -K $config->{key} -iv $config->{IV}";
276
      $targetDataset = $config->{datasets}->{$dataset}->{target} . '/' . dirnameToFileName( $targetDataset, '.', '/' );
-
 
277
      my $command = "cat $filename";
-
 
278
      $command .= " | openssl enc -aes-256-cbc -d -K $config->{transport}->{encryption}->{key} -iv $config->{transport}->{encryption}->{IV} " if $config->{transport}->{encryption}->{key};
-
 
279
      $command .= " | zfs receive -F $targetDataset";
-
 
280
      logMsg( $command );
-
 
281
      runCmd( $command );
271
   }
282
   }
272
}
283
}
273
 
284
 
274
##################### main program starts here #####################
285
##################### main program starts here #####################
275
# Example to create a random key for encryption/decryption:
286
# Example to create a random key for encryption/decryption:
Line 315... Line 326...
315
                $servername eq $config->{target}->{hostname} ? 'target' : 'unknown';
326
                $servername eq $config->{target}->{hostname} ? 'target' : 'unknown';
316
 
327
 
317
#cleanup( $config, "Testing" );
328
#cleanup( $config, "Testing" );
318
 
329
 
319
# mount the transport drive, fatal error if we can not find it
330
# mount the transport drive, fatal error if we can not find it
320
fatalError( "Unable to mount tranport drive with label $config->{transport}->{disk_label}", $config, \&cleanup )
331
fatalError( "Unable to mount tranport drive with label $config->{transport}->{label}", $config, \&cleanup )
321
   unless $config->{dryrun} or $config->{transport}->{mount_point} =  mountDriveByLabel( $config->{transport} );
332
   unless $config->{transport}->{mount_point} =  mountDriveByLabel( $config->{transport} );
322
 
333
 
323
# main program logic
334
# main program logic
324
if ( $config->{runningAs} eq 'source' ) {
335
if ( $config->{runningAs} eq 'source' ) {
325
    logMsg "Running as source server";
336
    logMsg "Running as source server";
326
    # remove all files from transport disk, but leave all subdirectories alone
337
    # remove all files from transport disk, but leave all subdirectories alone
Line 330... Line 341...
330
    $statusList = doSourceReplication($config, $statusList); 
341
    $statusList = doSourceReplication($config, $statusList); 
331
    writeStatusFile($config->{status_file}, $statusList) unless $config->{dryrun};
342
    writeStatusFile($config->{status_file}, $statusList) unless $config->{dryrun};
332
} elsif ( $config->{runningAs} eq 'target' ) {
343
} elsif ( $config->{runningAs} eq 'target' ) {
333
    logMsg "Running as target server";
344
    logMsg "Running as target server";
334
    mountGeli( $config->{target}->{geli} ) if ( defined $config->{target}->{geli} );
345
    mountGeli( $config->{target}->{geli} ) if ( defined $config->{target}->{geli} );
-
 
346
    umountDiskByLabel( $config->{target}->{geli}->{secureKey} )
-
 
347
       unless $config->{target}->{geli}->{secureKey}->{label} eq $config->{transport}->{label};
-
 
348
    print "Please insert device labeled REPORT\n" if $config->{target}->{report}->{targetDrive}->{label};
335
    updateTarget( $config );
349
    updateTarget( $config );
336
} else {
350
} else {
337
    fatalError( "This server ($servername) is neither source nor target server as per config\n" );
351
    fatalError( "This server ($servername) is neither source nor target server as per config\n" );
338
}
352
}
339
 
353