use Getopt::Long qw(GetOptionsFromArray);
use File::Copy qw(move);
use File::Path qw(make_path);
-use Switch;
use JSON;
use IO::File;
use String::ShellQuote 'shell_quote';
check_bin ('ssh');
check_bin ('scp');
+$SIG{TERM} = $SIG{QUIT} = $SIG{PIPE} = $SIG{HUP} = $SIG{KILL} = $SIG{INT} =
+ sub {
+ die "Signal aborting sync\n";
+ };
+
sub check_bin {
my ($bin) = @_;
}
sub cut_target_width {
- my ($target, $max) = @_;
+ my ($path, $maxlen) = @_;
+ $path =~ s@/+@/@g;
- return $target if (length($target) <= $max);
- my @spl = split('/', $target);
+ return $path if length($path) <= $maxlen;
- my $count = length($spl[@spl-1]);
- return "..\/".substr($spl[@spl-1],($count-$max)+3 , $count) if $count > $max;
+ return '..'.substr($path, -$maxlen+2) if $path !~ m@/@;
- $count += length($spl[0]) if @spl > 1;
- return substr($spl[0], 0, $max-4-length($spl[@spl-1]))."\/..\/".$spl[@spl-1] if $count > $max;
+ $path =~ s@/([^/]+/?)$@@;
+ my $tail = $1;
+
+ if (length($tail)+3 == $maxlen) {
+ return "../$tail";
+ } elsif (length($tail)+2 >= $maxlen) {
+ return '..'.substr($tail, -$maxlen+2)
+ }
- my $rest = 1;
- $rest = $max-$count if ($max-$count > 0);
+ $path =~ s@(/[^/]+)(?:/|$)@@;
+ my $head = $1;
+ my $both = length($head) + length($tail);
+ my $remaining = $maxlen-$both-4; # -4 for "/../"
- return "$spl[0]".substr($target, length($spl[0]), $rest)."..\/".$spl[@spl-1];
+ if ($remaining < 0) {
+ return substr($head, 0, $maxlen - length($tail) - 3) . "../$tail"; # -3 for "../"
+ }
+
+ substr($path, ($remaining/2), (length($path)-$remaining), '..');
+ return "$head/" . $path . "/$tail";
}
sub lock {
my ($target) = @_;
my $cmd = [];
- push @$cmd, 'ssh', "root\@$target->{ip}", '--', if $target->{ip};
+
+ if ($target->{ip}) {
+ push @$cmd, 'ssh', "root\@$target->{ip}", '--';
+ }
push @$cmd, 'zfs', 'list', '-H', '--', $target->{all};
eval {
run_cmd($cmd);
};
if ($@) {
- return 1;
+ return 0;
}
- return undef;
+ return 1;
}
sub parse_target {
$list .= sprintf("%-25s", cut_target_width($name, 25));
$list .= sprintf("%-10s", $states->{$source}->{$name}->{state});
$list .= sprintf("%-20s", $states->{$source}->{$name}->{lsync});
- $list .= sprintf("%-6s", $states->{$source}->{$name}->{vm_type});
+ $list .= sprintf("%-6s", defined($states->{$source}->{$name}->{vm_type}) ? $states->{$source}->{$name}->{vm_type} : "undef");
$list .= sprintf("%-5s\n", $cfg->{$source}->{$name}->{method});
}
}
my $res = undef;
+ return undef if !defined($target->{vmid});
+
eval { $res = run_cmd([@cmd, 'ls', "$QEMU_CONF/$target->{vmid}.conf"]) };
return "qemu" if $res;
run_cmd(['ssh-copy-id', '-i', '/root/.ssh/id_rsa.pub', "root\@$ip"]);
}
- die "Pool $dest->{all} does not exists\n" if check_pool_exists($dest);
-
- my $check = check_pool_exists($source->{path}, $source->{ip}) if !$source->{vmid} && $source->{path};
+ die "Pool $dest->{all} does not exists\n" if !check_pool_exists($dest);
- die "Pool $source->{path} does not exists\n" if undef($check);
+ if (!defined($source->{vmid})) {
+ die "Pool $source->{all} does not exists\n" if !check_pool_exists($source);
+ }
my $vm_type = vm_exists($source);
$job->{vm_type} = $vm_type;
$source->{vm_type} = $vm_type;
- die "VM $source->{vmid} doesn't exist\n" if $param->{vmid} && !$vm_type;
+ die "VM $source->{vmid} doesn't exist\n" if $source->{vmid} && !$vm_type;
die "Config already exists\n" if $cfg->{$job->{source}}->{$job->{name}};
#check if vm has zfs disks if not die;
- get_disks($source, 1) if $source->{vmid};
+ get_disks($source) if $source->{vmid};
update_cron($job);
update_state($job);
while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
$line = $1;
- if ($line =~ m/(rep_$name.*)$/) {
+ if ($line =~ m/(rep_\Q${name}\E_\d{4}-\d{2}-\d{2}_\d{2}:\d{2}:\d{2})$/) {
$last_snap = $1 if (!$last_snap);
$old_snap = $1;
}
sub get_disks {
- my ($target, $get_err) = @_;
+ my ($target) = @_;
my $cmd = [];
push @$cmd, 'ssh', "root\@$target->{ip}", '--', if $target->{ip};
my $res = run_cmd($cmd);
- my $disks = parse_disks($res, $target->{ip}, $target->{vm_type}, $get_err);
+ my $disks = parse_disks($res, $target->{ip}, $target->{vm_type});
return $disks;
}
}
sub parse_disks {
- my ($text, $ip, $vm_type, $get_err) = @_;
+ my ($text, $ip, $vm_type) = @_;
my $disks;
my $num = 0;
while ($text && $text =~ s/^(.*?)(\n|$)//) {
my $line = $1;
- my $error = $vm_type eq 'qemu' ? 1 : 0 ;
- next if $line =~ /cdrom|none/;
+ next if $line =~ /media=cdrom/;
next if $line !~ m/^(?:((?:virtio|ide|scsi|sata|mp)\d+)|rootfs): /;
#QEMU if backup is not set include in sync
- next if $vm_type eq 'qemu && ($line =~ m/backup=(?i:0|no|off|false)/)';
+ next if $vm_type eq 'qemu' && ($line =~ m/backup=(?i:0|no|off|false)/);
#LXC if backup is not set do no in sync
- $error = ($line =~ m/backup=(?i:1|yes|on|true)/) if $vm_type eq 'lxc';
+ next if $vm_type eq 'lxc' && ($line =~ m/^mp\d:/) && ($line !~ m/backup=(?i:1|yes|on|true)/);
my $disk = undef;
my $stor = undef;
- if($line =~ m/^(?:((?:virtio|ide|scsi|sata|mp)\d+)|rootfs): ([^:]+:)([A-Za-z0-9\-]+),(.*)$/) {
- $disk = $3;
- $stor = $2;
- } else {
- print "Disk: \"$line\" will not include in pve-sync\n" if $get_err || $error;
+ if($line =~ m/^(?:(?:(?:virtio|ide|scsi|sata|mp)\d+)|rootfs): (.*)$/) {
+ my @parameter = split(/,/,$1);
+
+ foreach my $opt (@parameter) {
+ if ($opt =~ m/^(?:file=|volume=)?([^:]+:)([A-Za-z0-9\-]+)$/){
+ $disk = $2;
+ $stor = $1;
+ last;
+ }
+ }
+ }
+ if (!defined($disk) || !defined($stor)) {
+ print "Disk: \"$line\" has no valid zfs dataset format and will be skipped\n";
next;
}
my $cmd = [];
- push @$cmd, 'ssh', "root\@$source->{ip}", '--' if $source->{ip};
+ push @$cmd, 'ssh', '-o', 'BatchMode=yes', "root\@$source->{ip}", '--' if $source->{ip};
push @$cmd, 'zfs', 'send';
push @$cmd, '-v' if $param->{verbose};
$target =~ s!/+!/!g;
push @$cmd, \'|';
- push @$cmd, 'ssh', "root\@$dest->{ip}", '--' if $dest->{ip};
- push @$cmd, 'zfs', 'recv', '-F', '--';
- push @$cmd, "$target";
+ push @$cmd, 'ssh', '-o', 'BatchMode=yes', "root\@$dest->{ip}", '--' if $dest->{ip};
+ push @$cmd, 'zfs', 'recv', '-F', '--';
+ push @$cmd, "$target";
- eval {
- run_cmd($cmd)
- };
+ eval {
+ run_cmd($cmd)
+ };
- if (my $erro = $@) {
- snapshot_destroy($source, undef, $param->{method}, $source->{new_snap});
- die $erro;
- };
- }
+ if (my $erro = $@) {
+ snapshot_destroy($source, undef, $param->{method}, $source->{new_snap});
+ die $erro;
+ };
+}
- sub send_config{
- my ($source, $dest, $method) = @_;
+sub send_config{
+ my ($source, $dest, $method) = @_;
- my $source_target = $source->{vm_type} eq 'qemu' ? "$QEMU_CONF/$source->{vmid}.conf": "$LXC_CONF/$source->{vmid}.conf";
- my $dest_target_new ="$source->{vmid}.conf.$source->{vm_type}.$source->{new_snap}";
+ my $source_target = $source->{vm_type} eq 'qemu' ? "$QEMU_CONF/$source->{vmid}.conf": "$LXC_CONF/$source->{vmid}.conf";
+ my $dest_target_new ="$source->{vmid}.conf.$source->{vm_type}.$source->{new_snap}";
- my $config_dir = $dest->{last_part} ? "${CONFIG_PATH}/$dest->{last_part}" : $CONFIG_PATH;
+ my $config_dir = $dest->{last_part} ? "${CONFIG_PATH}/$dest->{last_part}" : $CONFIG_PATH;
- $dest_target_new = $config_dir.'/'.$dest_target_new;
+ $dest_target_new = $config_dir.'/'.$dest_target_new;
- if ($method eq 'ssh'){
- if ($dest->{ip} && $source->{ip}) {
- run_cmd(['ssh', "root\@$dest->{ip}", '--', 'mkdir', '-p', '--', $config_dir]);
- run_cmd(['scp', '--', "root\@[$source->{ip}]:$source_target", "root\@[$dest->{ip}]:$dest_target_new"]);
- } elsif ($dest->{ip}) {
- run_cmd(['ssh', "root\@$dest->{ip}", '--', 'mkdir', '-p', '--', $config_dir]);
- run_cmd(['scp', '--', $source_target, "root\@[$dest->{ip}]:$dest_target_new"]);
- } elsif ($source->{ip}) {
- run_cmd(['mkdir', '-p', '--', $config_dir]);
- run_cmd(['scp', '--', "root\@$source->{ip}:$source_target", $dest_target_new]);
- }
+ if ($method eq 'ssh'){
+ if ($dest->{ip} && $source->{ip}) {
+ run_cmd(['ssh', "root\@$dest->{ip}", '--', 'mkdir', '-p', '--', $config_dir]);
+ run_cmd(['scp', '--', "root\@[$source->{ip}]:$source_target", "root\@[$dest->{ip}]:$dest_target_new"]);
+ } elsif ($dest->{ip}) {
+ run_cmd(['ssh', "root\@$dest->{ip}", '--', 'mkdir', '-p', '--', $config_dir]);
+ run_cmd(['scp', '--', $source_target, "root\@[$dest->{ip}]:$dest_target_new"]);
+ } elsif ($source->{ip}) {
+ run_cmd(['mkdir', '-p', '--', $config_dir]);
+ run_cmd(['scp', '--', "root\@[$source->{ip}]:$source_target", $dest_target_new]);
+ }
- if ($source->{destroy}){
- my $dest_target_old ="${config_dir}/$source->{vmid}.conf.$source->{vm_type}.$source->{old_snap}";
- if($dest->{ip}){
- run_cmd(['ssh', "root\@$dest->{ip}", '--', 'rm', '-f', '--', $dest_target_old]);
- } else {
- run_cmd(['rm', '-f', '--', $dest_target_old]);
- }
+ if ($source->{destroy}){
+ my $dest_target_old ="${config_dir}/$source->{vmid}.conf.$source->{vm_type}.$source->{old_snap}";
+ if($dest->{ip}){
+ run_cmd(['ssh', "root\@$dest->{ip}", '--', 'rm', '-f', '--', $dest_target_old]);
+ } else {
+ run_cmd(['rm', '-f', '--', $dest_target_old]);
}
- } elsif ($method eq 'local') {
- run_cmd(['mkdir', '-p', '--', $config_dir]);
- run_cmd(['cp', $source_target, $dest_target_new]);
}
+ } elsif ($method eq 'local') {
+ run_cmd(['mkdir', '-p', '--', $config_dir]);
+ run_cmd(['cp', $source_target, $dest_target_new]);
}
+}
- sub get_date {
- my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
- my $datestamp = sprintf ("%04d-%02d-%02d_%02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
+sub get_date {
+ my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
+ my $datestamp = sprintf ("%04d-%02d-%02d_%02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
- return $datestamp;
- }
+ return $datestamp;
+}
- sub status {
- my $cfg = read_cron();
+sub status {
+ my $cfg = read_cron();
- my $status_list = sprintf("%-25s%-25s%-10s\n", "SOURCE", "NAME", "STATUS");
+ my $status_list = sprintf("%-25s%-25s%-10s\n", "SOURCE", "NAME", "STATUS");
- my $states = read_state();
+ my $states = read_state();
- foreach my $source (sort keys%{$cfg}) {
- foreach my $sync_name (sort keys%{$cfg->{$source}}) {
- $status_list .= sprintf("%-25s", cut_target_width($source, 25));
- $status_list .= sprintf("%-25s", cut_target_width($sync_name, 25));
- $status_list .= "$states->{$source}->{$sync_name}->{state}\n";
- }
+ foreach my $source (sort keys%{$cfg}) {
+ foreach my $sync_name (sort keys%{$cfg->{$source}}) {
+ $status_list .= sprintf("%-25s", cut_target_width($source, 25));
+ $status_list .= sprintf("%-25s", cut_target_width($sync_name, 25));
+ $status_list .= "$states->{$source}->{$sync_name}->{state}\n";
}
-
- return $status_list;
}
- sub enable_job {
- my ($param) = @_;
+ return $status_list;
+}
- my $job = get_job($param);
- $job->{state} = "ok";
- update_state($job);
- update_cron($job);
- }
+sub enable_job {
+ my ($param) = @_;
- sub disable_job {
- my ($param) = @_;
+ my $job = get_job($param);
+ $job->{state} = "ok";
+ update_state($job);
+ update_cron($job);
+}
- my $job = get_job($param);
- $job->{state} = "stopped";
- update_state($job);
- update_cron($job);
- }
+sub disable_job {
+ my ($param) = @_;
- my $command = $ARGV[0];
+ my $job = get_job($param);
+ $job->{state} = "stopped";
+ update_state($job);
+ update_cron($job);
+}
- my $commands = {'destroy' => 1,
- 'create' => 1,
- 'sync' => 1,
- 'list' => 1,
- 'status' => 1,
- 'help' => 1,
- 'enable' => 1,
- 'disable' => 1};
+my $command = $ARGV[0];
- if (!$command || !$commands->{$command}) {
- usage();
- die "\n";
- }
+my $commands = {'destroy' => 1,
+ 'create' => 1,
+ 'sync' => 1,
+ 'list' => 1,
+ 'status' => 1,
+ 'help' => 1,
+ 'enable' => 1,
+ 'disable' => 1};
- my $help_sync = "$PROGNAME sync -dest <string> -source <string> [OPTIONS]\n
-\twill sync one time\n
-\t-dest\tstring\n
-\t\tthe destination target is like [IP:]<Pool>[/Path]\n
-\t-limit\tinteger\n
-\t\tmax sync speed in kBytes/s, default unlimited\n
-\t-maxsnap\tinteger\n
-\t\thow much snapshots will be kept before get erased, default 1/n
-\t-name\tstring\n
-\t\tname of the sync job, if not set it is default.
-\tIt is only necessary if scheduler allready contains this source.\n
-\t-source\tstring\n
-\t\tthe source can be an <VMID> or [IP:]<ZFSPool>[/Path]\n";
-
- my $help_create = "$PROGNAME create -dest <string> -source <string> [OPTIONS]/n
-\tCreate a sync Job\n
-\t-dest\tstring\n
-\t\tthe destination target is like [IP]:<Pool>[/Path]\n
-\t-limit\tinteger\n
-\t\tmax sync speed in kBytes/s, default unlimited\n
-\t-maxsnap\tstring\n
-\t\thow much snapshots will be kept before get erased, default 1\n
-\t-name\tstring\n
-\t\tname of the sync job, if not set it is default\n
-\t-skip\tboolean\n
-\t\tif this flag is set it will skip the first sync\n
-\t-source\tstring\n
-\t\tthe source can be an <VMID> or [IP:]<ZFSPool>[/Path]\n";
-
- my $help_destroy = "$PROGNAME destroy -source <string> [OPTIONS]\n
-\tremove a sync Job from the scheduler\n
-\t-name\tstring\n
-\t\tname of the sync job, if not set it is default\n
-\t-source\tstring\n
-\t\tthe source can be an <VMID> or [IP:]<ZFSPool>[/Path]\n";
-
- my $help_help = "$PROGNAME help <cmd> [OPTIONS]\n
-\tGet help about specified command.\n
-\t<cmd>\tstring\n
-\t\tCommand name\n
-\t-verbose\tboolean\n
-\t\tVerbose output format.\n";
-
- my $help_list = "$PROGNAME list\n
-\tGet a List of all scheduled Sync Jobs\n";
-
- my $help_status = "$PROGNAME status\n
-\tGet the status of all scheduled Sync Jobs\n";
-
- my $help_enable = "$PROGNAME enable -source <string> [OPTIONS]\n
-\tenable a syncjob and reset error\n
-\t-name\tstring\n
-\t\tname of the sync job, if not set it is default\n
-\t-source\tstring\n
-\t\tthe source can be an <VMID> or [IP:]<ZFSPool>[/Path]\n";
-
- my $help_disable = "$PROGNAME disable -source <string> [OPTIONS]\n
-\tpause a syncjob\n
-\t-name\tstring\n
-\t\tname of the sync job, if not set it is default\n
-\t-source\tstring\n
-\t\tthe source can be an <VMID> or [IP:]<ZFSPool>[/Path]\n";
-
- sub help {
- my ($command) = @_;
-
- switch($command){
- case 'help'
- {
- die "$help_help\n";
- }
- case 'sync'
- {
- die "$help_sync\n";
- }
- case 'destroy'
- {
- die "$help_destroy\n";
- }
- case 'create'
- {
- die "$help_create\n";
- }
- case 'list'
- {
- die "$help_list\n";
- }
- case 'status'
- {
- die "$help_status\n";
- }
- case 'enable'
- {
- die "$help_enable\n";
- }
- case 'disable'
- {
- die "$help_enable\n";
- }
- }
+if (!$command || !$commands->{$command}) {
+ usage();
+ die "\n";
+}
- }
+my $help_sync = <<EOF;
+$PROGNAME sync -dest <string> -source <string> [OPTIONS]\n
- my @arg = @ARGV;
- my $param = parse_argv(@arg);
+ will sync one time
+ -dest string
+
+ the destination target is like [IP:]<Pool>[/Path]
+
+ -limit integer
+
+ max sync speed in kBytes/s, default unlimited
+
+ -maxsnap integer
+
+ how much snapshots will be kept before get erased, default 1
+
+ -name string
+
+ name of the sync job, if not set it is default.
+ It is only necessary if scheduler allready contains this source.
+
+ -source string
+
+ the source can be an <VMID> or [IP:]<ZFSPool>[/Path]
+
+ -verbose boolean
+
+ print out the sync progress.
+EOF
+
+my $help_create = <<EOF;
+$PROGNAME create -dest <string> -source <string> [OPTIONS]
+
+ Create a sync Job
+
+ -dest string
+
+ the destination target is like [IP]:<Pool>[/Path]
+
+ -limit integer
+
+ max sync speed in kBytes/s, default unlimited
+
+ -maxsnap string
+
+ how much snapshots will be kept before get erased, default 1
+
+ -name string
+
+ name of the sync job, if not set it is default
+
+ -skip boolean
+
+ if this flag is set it will skip the first sync
+
+ -source string
+
+ the source can be an <VMID> or [IP:]<ZFSPool>[/Path]
+EOF
+
+my $help_destroy = <<EOF;
+$PROGNAME destroy -source <string> [OPTIONS]
+
+ remove a sync Job from the scheduler
+
+ -name string
+
+ name of the sync job, if not set it is default
+
+ -source string
+
+ the source can be an <VMID> or [IP:]<ZFSPool>[/Path]
+EOF
+
+my $help_help = <<EOF;
+$PROGNAME help <cmd> [OPTIONS]
+
+ Get help about specified command.
+
+ <cmd> string
+
+ Command name
+
+ -verbose boolean
+
+ Verbose output format.
+EOF
+
+my $help_list = <<EOF;
+$PROGNAME list
+
+ Get a List of all scheduled Sync Jobs
+EOF
+
+my $help_status = <<EOF;
+$PROGNAME status
+
+ Get the status of all scheduled Sync Jobs
+EOF
+
+my $help_enable = <<EOF;
+$PROGNAME enable -source <string> [OPTIONS]
+
+ enable a syncjob and reset error
+
+ -name string
+
+ name of the sync job, if not set it is default
+
+ -source string
+
+ the source can be an <VMID> or [IP:]<ZFSPool>[/Path]
+EOF
+
+my $help_disable = <<EOF;
+$PROGNAME disable -source <string> [OPTIONS]
+
+ pause a sync job
+
+ -name string
+
+ name of the sync job, if not set it is default
+
+ -source string
+
+ the source can be an <VMID> or [IP:]<ZFSPool>[/Path]
+EOF
+
+sub help {
+ my ($command) = @_;
+
+ if ($command eq 'help') {
+ die "$help_help\n";
+
+ } elsif ($command eq 'sync') {
+ die "$help_sync\n";
+
+ } elsif ($command eq 'destroy') {
+ die "$help_destroy\n";
+
+ } elsif ($command eq 'create') {
+ die "$help_create\n";
+
+ } elsif ($command eq 'list') {
+ die "$help_list\n";
+
+ } elsif ($command eq 'status') {
+ die "$help_status\n";
+
+ } elsif ($command eq 'enable') {
+ die "$help_enable\n";
+
+ } elsif ($command eq 'disable') {
+ die "$help_disable\n";
- switch($command) {
- case "destroy"
- {
- die "$help_destroy\n" if !$param->{source};
- check_target($param->{source});
- destroy_job($param);
- }
- case "sync"
- {
- die "$help_sync\n" if !$param->{source} || !$param->{dest};
- check_target($param->{source});
- check_target($param->{dest});
- sync($param);
- }
- case "create"
- {
- die "$help_create\n" if !$param->{source} || !$param->{dest};
- check_target($param->{source});
- check_target($param->{dest});
- init($param);
- }
- case "status"
- {
- print status();
- }
- case "list"
- {
- print list();
- }
- case "help"
- {
- my $help_command = $ARGV[1];
- if ($help_command && $commands->{$help_command}) {
- print help($help_command);
- }
- if ($param->{verbose} == 1){
- exec("man $PROGNAME");
- } else {
- usage(1);
- }
- }
- case "enable"
- {
- die "$help_enable\n" if !$param->{source};
- check_target($param->{source});
- enable_job($param);
- }
- case "disable"
- {
- die "$help_disable\n" if !$param->{source};
- check_target($param->{source});
- disable_job($param);
- }
}
- sub usage {
- my ($help) = @_;
-
- print("ERROR:\tno command specified\n") if !$help;
- print("USAGE:\t$PROGNAME <COMMAND> [ARGS] [OPTIONS]\n");
- print("\t$PROGNAME help [<cmd>] [OPTIONS]\n\n");
- print("\t$PROGNAME create -dest <string> -source <string> [OPTIONS]\n");
- print("\t$PROGNAME destroy -source <string> [OPTIONS]\n");
- print("\t$PROGNAME disable -source <string> [OPTIONS]\n");
- print("\t$PROGNAME enable -source <string> [OPTIONS]\n");
- print("\t$PROGNAME list\n");
- print("\t$PROGNAME status\n");
- print("\t$PROGNAME sync -dest <string> -source <string> [OPTIONS]\n");
+}
+
+my @arg = @ARGV;
+my $param = parse_argv(@arg);
+
+if ($command eq 'destroy') {
+ die "$help_destroy\n" if !$param->{source};
+
+ check_target($param->{source});
+ destroy_job($param);
+
+} elsif ($command eq 'sync') {
+ die "$help_sync\n" if !$param->{source} || !$param->{dest};
+
+ check_target($param->{source});
+ check_target($param->{dest});
+ sync($param);
+
+} elsif ($command eq 'create') {
+ die "$help_create\n" if !$param->{source} || !$param->{dest};
+
+ check_target($param->{source});
+ check_target($param->{dest});
+ init($param);
+
+} elsif ($command eq 'status') {
+ print status();
+
+} elsif ($command eq 'list') {
+ print list();
+
+} elsif ($command eq 'help') {
+ my $help_command = $ARGV[1];
+
+ if ($help_command && $commands->{$help_command}) {
+ print help($help_command);
+
}
+ if ($param->{verbose}) {
+ exec("man $PROGNAME");
+
+ } else {
+ usage(1);
- sub check_target {
- my ($target) = @_;
- parse_target($target);
}
+} elsif ($command eq 'enable') {
+ die "$help_enable\n" if !$param->{source};
+
+ check_target($param->{source});
+ enable_job($param);
+
+} elsif ($command eq 'disable') {
+ die "$help_disable\n" if !$param->{source};
+
+ check_target($param->{source});
+ disable_job($param);
+
+}
+
+sub usage {
+ my ($help) = @_;
+
+ print("ERROR:\tno command specified\n") if !$help;
+ print("USAGE:\t$PROGNAME <COMMAND> [ARGS] [OPTIONS]\n");
+ print("\t$PROGNAME help [<cmd>] [OPTIONS]\n\n");
+ print("\t$PROGNAME create -dest <string> -source <string> [OPTIONS]\n");
+ print("\t$PROGNAME destroy -source <string> [OPTIONS]\n");
+ print("\t$PROGNAME disable -source <string> [OPTIONS]\n");
+ print("\t$PROGNAME enable -source <string> [OPTIONS]\n");
+ print("\t$PROGNAME list\n");
+ print("\t$PROGNAME status\n");
+ print("\t$PROGNAME sync -dest <string> -source <string> [OPTIONS]\n");
+}
+
+sub check_target {
+ my ($target) = @_;
+ parse_target($target);
+}
+
__END__
=head1 NAME
the source can be an <VMID> or [IP:]<ZFSPool>[/Path]
+ -verbose boolean
+
+ print out the sync progress.
+
=head1 DESCRIPTION
This Tool helps you to sync your VM or directory which stored on ZFS between 2 servers.