Subversion Repositories zfs_utils

Rev

Rev 26 | Rev 30 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
24 rodolico 1
#! /usr/bin/env perl
2
 
3
use strict;
4
use warnings;
5
 
6
use FindBin;
7
use lib "$FindBin::Bin/..";
27 rodolico 8
use Data::Dumper;
9
use ZFS_Utils qw(loadConfig shredFile logMsg makeReplicateCommands mountDriveByLabel mountGeli runCmd $logFileName $displayLogsOnConsole);
24 rodolico 10
 
11
# set the log file to be next to this script
12
$logFileName = "$FindBin::Bin/sneakernet.log";
13
# display all log messages on console in addition to the log file
14
$displayLogsOnConsole = 1;
15
 
16
my $configFileName = "$0.conf.yaml";
17
 
18
my $config = {
19
   # file created on source server to track last copyed dataset
20
   'status_file' => "$0.status",
21
   #information about source server
22
   'source_server' => {
23
      'hostname' => '', # used to see if we are on source
24
      'poolname' => '', # name of the ZFS pool to export
25
   },
26
   #information about target server
27
   'target_server' => {
28
      'hostname' => '', # used to see if we are on target
29
      'poolname' => '', # name of the ZFS pool to import
30
      # if this is set, the dataset uses GELI, so we must decrypt and
31
      # mount it first
32
      'geli' => {
33
         'keydiskname' => 'replica', # the GPT label of the key disk
34
         'keyfile' => 'geli.key', # the name of the key file on keydiskname
35
         'localKey' => 'e98c660cccdae1226550484d62caa2b72f60632ae0c607528aba1ac9e7bfbc9c', # hex representation of the local key part
36
         'target' => '/media/geli.key', # location to create the combined keyfile
37
         'poolname' => '', # name of the ZFS pool to import
38
         'diskList' => [ 
39
            '/dev/gpt/sneakernet_disk' 
40
            ], # list of disks to try to mount the dataset from
41
      }
42
   },
27 rodolico 43
 
24 rodolico 44
   'transport' => {
45
      # this is the GPT label of the sneakernet disk
46
      'disk_label' => 'sneakernet',
47
      # where we want to mount it
48
      'mount_point' => '/mnt/sneakernet',
49
      # amount of time to wait for the disk to appear
50
      'timeout' => 600,
51
      # if set, all files will be encrypted with this key/IV during transport
52
      'encryption' => {
53
         'key'    => '', # openssl rand 32 | xxd -p | tr -d '\n' > test.key
54
         'IV'     => '00000000000000000000000000000000',
55
      },
56
   },
57
   'datasets' => {
58
      'iscsi' => {
59
         'source' => 'storage/backup/iscsi',
60
         'target' => 'storage/backup/iscsi',
61
         'filename' => 'iscsi'
62
      },
63
      'files_share'  => {
64
         'source' => 'storage/backup/files_share',
65
         'target' => 'storage/backup/files_share',
66
         'filename' => 'files_share'
67
      },
68
   }
69
};
70
 
71
 
72
# generate a random key with
73
# openssl rand 32 | xxd -p | tr -d '\n' > test.key
74
 
75
# If a YAML config file exists next to the script, load and merge it
76
$config = loadConfig($configFileName, $config );
27 rodolico 77
 
25 rodolico 78
# set some defaults
79
$config->{'status_file'} = "$0.status" unless ( defined $config->{'status_file'} );
24 rodolico 80
 
25 rodolico 81
 
24 rodolico 82
die "Invalid config file: missing source and/or target server\n"
83
    unless (defined $config->{source_server} && defined $config->{target_server});
84
 
85
my $servername = `hostname -s`;
86
chomp $servername;
87
if ( $servername eq $config->{source_server}->{hostname} ) {
25 rodolico 88
    logMsg "Running as source server\n";
24 rodolico 89
    # source server logic here
90
} elsif ( $servername eq $config->{target_server}->{hostname} ) {
25 rodolico 91
    logMsg "Running as target server\n";
24 rodolico 92
    mountGeli( $config->{target_server}->{geli} ) if ( defined $config->{target_server}->{geli} );
93
} else {
25 rodolico 94
    logMsg "This server ($servername) is neither source nor target server as per config\n";
95
    die;
24 rodolico 96
}
97
 
25 rodolico 98
# read in history/status file
99
my $targetList = [];
100
if ( -e $config->{status_file} && open my $fh, '<', $config->{status_file} ) {
101
   chomp( my @lines = <$fh> );
102
   $targetList = \@lines;
103
   close $fh;
104
} else {
105
   logMsg("Error: could not read status file '$config->{status_file}': $!");
106
   die;
107
}
24 rodolico 108
 
25 rodolico 109
my $newStatus = [];
110
foreach my $dataset ( sort keys %{$config->{datasets}} ) {
27 rodolico 111
   logMsg("Processing dataset '$dataset'");
25 rodolico 112
   my $sourceList = [ runCmd( "zfs", "list", "-rt", "snap", "-H", "-o", "name", $config->{datasets}->{$dataset}->{source} ) ];
113
   # process dataset here
114
   my $commands = makeReplicateCommands($sourceList, $targetList, $newStatus );
115
   foreach my $cmd ( @$commands ) {
27 rodolico 116
      $cmd .= " > $config->{transport}->{mount_point}/" . $dataset;
117
      logMsg("Running command: $cmd");
25 rodolico 118
      #runCmd( split( /\s+/, $cmd ) );
119
   }
120
}
121
 
122
1;
123
 
124
 
24 rodolico 125
#`cat $config->{input} | openssl enc -aes-256-cbc -K $config->{key} -iv $config->{IV} > $config->{output}`;
126
 
127
# this will decrypt $config->{output} to stdout
128
#`cat $config->{output} | openssl enc -aes-256-cbc -d -K $config->{key} -iv $config->{IV} > test.out`;