X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=pve-zsync;h=425ffa2a5220ec001956e9567b59e9fbfb9a9b01;hb=9749f08ffc9afec35d560768be2e23ba1e48eea7;hp=44ed910addbcfff96e6d7ea4342565ac32b22cd2;hpb=ce6bc53ea7582aaacc52f1a369d0410a84acbc50;p=pve-zsync.git diff --git a/pve-zsync b/pve-zsync old mode 100644 new mode 100755 index 44ed910..425ffa2 --- a/pve-zsync +++ b/pve-zsync @@ -2,10 +2,9 @@ use strict; use warnings; -use Data::Dumper qw(Dumper); + use Fcntl qw(:flock SEEK_END); use Getopt::Long qw(GetOptionsFromArray); -use File::Copy qw(move); use File::Path qw(make_path); use JSON; use IO::File; @@ -22,7 +21,16 @@ my $LXC_CONF = "${PVE_DIR}/lxc"; my $LOCKFILE = "$CONFIG_PATH/${PROGNAME}.lock"; my $PROG_PATH = "$PATH/${PROGNAME}"; my $INTERVAL = 15; -my $DEBUG = 0; +my $DEBUG; + +BEGIN { + $DEBUG = 0; # change default here. not above on declaration! + $DEBUG ||= $ENV{ZSYNC_DEBUG}; + if ($DEBUG) { + require Data::Dumper; + Data::Dumper->import(); + } +} my $IPV4OCTET = "(?:25[0-5]|(?:[1-9]|1[0-9]|2[0-4])?[0-9])"; my $IPV4RE = "(?:(?:$IPV4OCTET\\.){3}$IPV4OCTET)"; @@ -46,15 +54,18 @@ my $HOSTRE = "(?:$HOSTv4RE1|\\[$IPV6RE\\])"; # ipv6 must always be in brac # targets are either a VMID, or a 'host:zpool/path' with 'host:' being optional my $TARGETRE = qr!^(?:($HOSTRE):)?(\d+|(?:[\w\-_]+)(/.+)?)$!; -check_bin ('cstream'); -check_bin ('zfs'); -check_bin ('ssh'); -check_bin ('scp'); +my $command = $ARGV[0]; + +if (defined($command) && $command ne 'help' && $command ne 'printpod') { + check_bin ('cstream'); + check_bin ('zfs'); + check_bin ('ssh'); + check_bin ('scp'); +} -$SIG{TERM} = $SIG{QUIT} = $SIG{PIPE} = $SIG{HUP} = $SIG{KILL} = $SIG{INT} = - sub { - die "Signal aborting sync\n"; - }; +$SIG{TERM} = $SIG{QUIT} = $SIG{PIPE} = $SIG{HUP} = $SIG{KILL} = $SIG{INT} = sub { + die "Signaled, aborting sync: $!\n"; +}; sub check_bin { my ($bin) = @_; @@ -120,12 +131,12 @@ sub get_status { } sub check_pool_exists { - my ($target) = @_; + my ($target, $user) = @_; my $cmd = []; if ($target->{ip}) { - push @$cmd, 'ssh', "root\@$target->{ip}", '--'; + push @$cmd, 'ssh', "$user\@$target->{ip}", '--'; } push @$cmd, 'zfs', 'list', '-H', '--', $target->{all}; eval { @@ -197,33 +208,44 @@ sub read_cron { sub parse_argv { my (@arg) = @_; - my $param = {}; - $param->{dest} = undef; - $param->{source} = undef; - $param->{verbose} = undef; - $param->{limit} = undef; - $param->{maxsnap} = undef; - $param->{name} = undef; - $param->{skip} = undef; - $param->{method} = undef; - - my ($ret, $ar) = GetOptionsFromArray(\@arg, - 'dest=s' => \$param->{dest}, - 'source=s' => \$param->{source}, - 'verbose' => \$param->{verbose}, - 'limit=i' => \$param->{limit}, - 'maxsnap=i' => \$param->{maxsnap}, - 'name=s' => \$param->{name}, - 'skip' => \$param->{skip}, - 'method=s' => \$param->{method}); - - if ($ret == 0) { - die "can't parse options\n"; - } + my $param = { + dest => undef, + source => undef, + verbose => undef, + limit => undef, + maxsnap => undef, + name => undef, + skip => undef, + method => undef, + source_user => undef, + dest_user => undef, + properties => undef, + dest_config_path => undef, + }; - $param->{name} = "default" if !$param->{name}; - $param->{maxsnap} = 1 if !$param->{maxsnap}; - $param->{method} = "ssh" if !$param->{method}; + my ($ret) = GetOptionsFromArray( + \@arg, + 'dest=s' => \$param->{dest}, + 'source=s' => \$param->{source}, + 'verbose' => \$param->{verbose}, + 'limit=i' => \$param->{limit}, + 'maxsnap=i' => \$param->{maxsnap}, + 'name=s' => \$param->{name}, + 'skip' => \$param->{skip}, + 'method=s' => \$param->{method}, + 'source-user=s' => \$param->{source_user}, + 'dest-user=s' => \$param->{dest_user}, + 'properties' => \$param->{properties}, + 'dest-config-path=s' => \$param->{dest_config_path}, + ); + + die "can't parse options\n" if $ret == 0; + + $param->{name} //= "default"; + $param->{maxsnap} //= 1; + $param->{method} //= "ssh"; + $param->{source_user} //= "root"; + $param->{dest_user} //= "root"; return $param; } @@ -256,12 +278,10 @@ sub encode_cron { my $param = parse_argv(@arg); if ($param->{source} && $param->{dest}) { - $cfg->{$param->{source}}->{$param->{name}}->{dest} = $param->{dest}; - $cfg->{$param->{source}}->{$param->{name}}->{verbose} = $param->{verbose}; - $cfg->{$param->{source}}->{$param->{name}}->{limit} = $param->{limit}; - $cfg->{$param->{source}}->{$param->{name}}->{maxsnap} = $param->{maxsnap}; - $cfg->{$param->{source}}->{$param->{name}}->{skip} = $param->{skip}; - $cfg->{$param->{source}}->{$param->{name}}->{method} = $param->{method}; + my $source = delete $param->{source}; + my $name = delete $param->{name}; + + $cfg->{$source}->{$name} = $param; } } @@ -283,6 +303,10 @@ sub param_to_job { $job->{limit} = $param->{limit}; $job->{maxsnap} = $param->{maxsnap} if $param->{maxsnap}; $job->{source} = $param->{source}; + $job->{source_user} = $param->{source_user}; + $job->{dest_user} = $param->{dest_user}; + $job->{properties} = !!$param->{properties}; + $job->{dest_config_path} = $param->{dest_config_path} if $param->{dest_config_path}; return $job; } @@ -351,7 +375,7 @@ sub update_state { print $out_fh $text; close($out_fh); - move("$STATE.new", $STATE); + rename "$STATE.new", $STATE; eval { close($in_fh); }; @@ -403,7 +427,7 @@ sub update_cron { die "can't write to $CRONJOBS.new\n" if !print($new_fh $text); close ($new_fh); - die "can't move $CRONJOBS.new: $!\n" if !move("${CRONJOBS}.new", "$CRONJOBS"); + die "can't move $CRONJOBS.new: $!\n" if !rename "${CRONJOBS}.new", $CRONJOBS; close ($fh); } @@ -415,7 +439,7 @@ sub format_job { $text = "#"; } if ($line) { - $line =~ /^#*(.+) root/; + $line =~ /^#*\s*((?:\S+\s+){4}\S+)\s+root/; $text .= $1; } else { $text .= "*/$INTERVAL * * * *"; @@ -426,6 +450,10 @@ sub format_job { $text .= " --limit $job->{limit}" if $job->{limit}; $text .= " --method $job->{method}"; $text .= " --verbose" if $job->{verbose}; + $text .= " --source-user $job->{source_user}"; + $text .= " --dest-user $job->{dest_user}"; + $text .= " --properties" if $job->{properties}; + $text .= " --dest-config-path $job->{dest_config_path}" if $job->{dest_config_path}; $text .= "\n"; return $text; @@ -453,21 +481,20 @@ sub list { } sub vm_exists { - my ($target) = @_; - - my @cmd = ('ssh', "root\@$target->{ip}", '--') if $target->{ip}; - - my $res = undef; + my ($target, $user) = @_; return undef if !defined($target->{vmid}); - eval { $res = run_cmd([@cmd, 'ls', "$QEMU_CONF/$target->{vmid}.conf"]) }; - - return "qemu" if $res; + my $conf_fn = "$target->{vmid}.conf"; - eval { $res = run_cmd([@cmd, 'ls', "$LXC_CONF/$target->{vmid}.conf"]) }; - - return "lxc" if $res; + if ($target->{ip}) { + my @cmd = ('ssh', "$user\@$target->{ip}", '--', '/bin/ls'); + return "qemu" if eval { run_cmd([@cmd, "$QEMU_CONF/$conf_fn"]) }; + return "lxc" if eval { run_cmd([@cmd, "$LXC_CONF/$conf_fn"]) }; + } else { + return "qemu" if -f "$QEMU_CONF/$conf_fn"; + return "lxc" if -f "$LXC_CONF/$conf_fn"; + } return undef; } @@ -486,20 +513,20 @@ sub init { my $dest = parse_target($param->{dest}); if (my $ip = $dest->{ip}) { - run_cmd(['ssh-copy-id', '-i', '/root/.ssh/id_rsa.pub', "root\@$ip"]); + run_cmd(['ssh-copy-id', '-i', '/root/.ssh/id_rsa.pub', "$param->{dest_user}\@$ip"]); } if (my $ip = $source->{ip}) { - run_cmd(['ssh-copy-id', '-i', '/root/.ssh/id_rsa.pub', "root\@$ip"]); + run_cmd(['ssh-copy-id', '-i', '/root/.ssh/id_rsa.pub', "$param->{source_user}\@$ip"]); } - die "Pool $dest->{all} does not exists\n" if !check_pool_exists($dest); + die "Pool $dest->{all} does not exists\n" if !check_pool_exists($dest, $param->{dest_user}); if (!defined($source->{vmid})) { - die "Pool $source->{all} does not exists\n" if !check_pool_exists($source); + die "Pool $source->{all} does not exists\n" if !check_pool_exists($source, $param->{source_user}); } - my $vm_type = vm_exists($source); + my $vm_type = vm_exists($source, $param->{source_user}); $job->{vm_type} = $vm_type; $source->{vm_type} = $vm_type; @@ -508,7 +535,7 @@ sub init { die "Config already exists\n" if $cfg->{$job->{source}}->{$job->{name}}; #check if vm has zfs disks if not die; - get_disks($source) if $source->{vmid}; + get_disks($source, $param->{source_user}) if $source->{vmid}; update_cron($job); update_state($job); @@ -561,7 +588,7 @@ sub sync { $job = get_job($param); }; - if ($job && $job->{state} eq "syncing") { + if ($job && defined($job->{state}) && $job->{state} eq "syncing") { die "Job --source $param->{source} --name $param->{name} is syncing at the moment"; } @@ -571,17 +598,17 @@ sub sync { my $sync_path = sub { my ($source, $dest, $job, $param, $date) = @_; - ($source->{old_snap}, $source->{last_snap}) = snapshot_get($source, $dest, $param->{maxsnap}, $param->{name}); + ($source->{old_snap}, $source->{last_snap}) = snapshot_get($source, $dest, $param->{maxsnap}, $param->{name}, $param->{source_user}); - snapshot_add($source, $dest, $param->{name}, $date); + snapshot_add($source, $dest, $param->{name}, $date, $param->{source_user}, $param->{dest_user}); send_image($source, $dest, $param); - snapshot_destroy($source, $dest, $param->{method}, $source->{old_snap}) if ($source->{destroy} && $source->{old_snap}); + snapshot_destroy($source, $dest, $param->{method}, $source->{old_snap}, $param->{source_user}, $param->{dest_user}) if ($source->{destroy} && $source->{old_snap}); }; - my $vm_type = vm_exists($source); + my $vm_type = vm_exists($source, $param->{source_user}); $source->{vm_type} = $vm_type; if ($job) { @@ -593,7 +620,8 @@ sub sync { eval{ if ($source->{vmid}) { die "VM $source->{vmid} doesn't exist\n" if !$vm_type; - my $disks = get_disks($source); + die "source-user has to be root for syncing VMs\n" if ($param->{source_user} ne "root"); + my $disks = get_disks($source, $param->{source_user}); foreach my $disk (sort keys %{$disks}) { $source->{all} = $disks->{$disk}->{all}; @@ -603,9 +631,9 @@ sub sync { &$sync_path($source, $dest, $job, $param, $date); } if ($param->{method} eq "ssh" && ($source->{ip} || $dest->{ip})) { - send_config($source, $dest,'ssh'); + send_config($source, $dest,'ssh', $param->{source_user}, $param->{dest_user}, $param->{dest_config_path}); } else { - send_config($source, $dest,'local'); + send_config($source, $dest,'local', $param->{source_user}, $param->{dest_user}, $param->{dest_config_path}); } } else { &$sync_path($source, $dest, $job, $param, $date); @@ -633,10 +661,10 @@ sub sync { } sub snapshot_get{ - my ($source, $dest, $max_snap, $name) = @_; + my ($source, $dest, $max_snap, $name, $source_user) = @_; my $cmd = []; - push @$cmd, 'ssh', "root\@$source->{ip}", '--', if $source->{ip}; + push @$cmd, 'ssh', "$source_user\@$source->{ip}", '--', if $source->{ip}; push @$cmd, 'zfs', 'list', '-r', '-t', 'snapshot', '-Ho', 'name', '-S', 'creation'; push @$cmd, $source->{all}; @@ -666,7 +694,7 @@ sub snapshot_get{ } sub snapshot_add { - my ($source, $dest, $name, $date) = @_; + my ($source, $dest, $name, $date, $source_user, $dest_user) = @_; my $snap_name = "rep_$name\_".$date; @@ -675,14 +703,14 @@ sub snapshot_add { my $path = "$source->{all}\@$snap_name"; my $cmd = []; - push @$cmd, 'ssh', "root\@$source->{ip}", '--', if $source->{ip}; + push @$cmd, 'ssh', "$source_user\@$source->{ip}", '--', if $source->{ip}; push @$cmd, 'zfs', 'snapshot', $path; eval{ run_cmd($cmd); }; if (my $err = $@) { - snapshot_destroy($source, $dest, 'ssh', $snap_name); + snapshot_destroy($source, $dest, 'ssh', $snap_name, $source_user, $dest_user); die "$err\n"; } } @@ -724,10 +752,10 @@ sub write_cron { } sub get_disks { - my ($target) = @_; + my ($target, $user) = @_; my $cmd = []; - push @$cmd, 'ssh', "root\@$target->{ip}", '--', if $target->{ip}; + push @$cmd, 'ssh', "$user\@$target->{ip}", '--', if $target->{ip}; if ($target->{vm_type} eq 'qemu') { push @$cmd, 'qm', 'config', $target->{vmid}; @@ -739,7 +767,7 @@ sub get_disks { my $res = run_cmd($cmd); - my $disks = parse_disks($res, $target->{ip}, $target->{vm_type}); + my $disks = parse_disks($res, $target->{ip}, $target->{vm_type}, $user); return $disks; } @@ -762,7 +790,7 @@ sub run_cmd { } sub parse_disks { - my ($text, $ip, $vm_type) = @_; + my ($text, $ip, $vm_type, $user) = @_; my $disks; @@ -798,7 +826,7 @@ sub parse_disks { } my $cmd = []; - push @$cmd, 'ssh', "root\@$ip", '--' if $ip; + push @$cmd, 'ssh', "$user\@$ip", '--' if $ip; push @$cmd, 'pvesm', 'path', "$stor$disk"; my $path = run_cmd($cmd); @@ -842,14 +870,14 @@ sub parse_disks { } sub snapshot_destroy { - my ($source, $dest, $method, $snap) = @_; + my ($source, $dest, $method, $snap, $source_user, $dest_user) = @_; my @zfscmd = ('zfs', 'destroy'); my $snapshot = "$source->{all}\@$snap"; eval { if($source->{ip} && $method eq 'ssh'){ - run_cmd(['ssh', "root\@$source->{ip}", '--', @zfscmd, $snapshot]); + run_cmd(['ssh', "$source_user\@$source->{ip}", '--', @zfscmd, $snapshot]); } else { run_cmd([@zfscmd, $snapshot]); } @@ -858,9 +886,10 @@ sub snapshot_destroy { warn "WARN: $erro"; } if ($dest) { - my @ssh = $dest->{ip} ? ('ssh', "root\@$dest->{ip}", '--') : (); + my @ssh = $dest->{ip} ? ('ssh', "$dest_user\@$dest->{ip}", '--') : (); - my $path = "$dest->{all}\/$source->{last_part}"; + my $path = "$dest->{all}"; + $path .= "/$source->{last_part}" if $source->{last_part}; eval { run_cmd([@ssh, @zfscmd, "$path\@$snap"]); @@ -872,12 +901,18 @@ sub snapshot_destroy { } sub snapshot_exist { - my ($source , $dest, $method) = @_; + my ($source , $dest, $method, $dest_user) = @_; my $cmd = []; - push @$cmd, 'ssh', "root\@$dest->{ip}", '--' if $dest->{ip}; + push @$cmd, 'ssh', "$dest_user\@$dest->{ip}", '--' if $dest->{ip}; push @$cmd, 'zfs', 'list', '-rt', 'snapshot', '-Ho', 'name'; - push @$cmd, "$dest->{all}/$source->{last_part}\@$source->{old_snap}"; + + my $path = $dest->{all}; + $path .= "/$source->{last_part}" if $source->{last_part}; + $path .= "\@$source->{old_snap}"; + + push @$cmd, $path; + my $text = ""; eval {$text =run_cmd($cmd);}; @@ -897,11 +932,12 @@ sub send_image { my $cmd = []; - push @$cmd, 'ssh', '-o', 'BatchMode=yes', "root\@$source->{ip}", '--' if $source->{ip}; + push @$cmd, 'ssh', '-o', 'BatchMode=yes', "$param->{source_user}\@$source->{ip}", '--' if $source->{ip}; push @$cmd, 'zfs', 'send'; + push @$cmd, '-p', if $param->{properties}; push @$cmd, '-v' if $param->{verbose}; - if($source->{last_snap} && snapshot_exist($source , $dest, $param->{method})) { + if($source->{last_snap} && snapshot_exist($source , $dest, $param->{method}, $param->{dest_user})) { push @$cmd, '-i', "$source->{all}\@$source->{last_snap}"; } push @$cmd, '--', "$source->{all}\@$source->{new_snap}"; @@ -910,11 +946,12 @@ sub send_image { my $bwl = $param->{limit}*1024; push @$cmd, \'|', 'cstream', '-t', $bwl; } - my $target = "$dest->{all}/$source->{last_part}"; + my $target = "$dest->{all}"; + $target .= "/$source->{last_part}" if $source->{last_part}; $target =~ s!/+!/!g; push @$cmd, \'|'; - push @$cmd, 'ssh', '-o', 'BatchMode=yes', "root\@$dest->{ip}", '--' if $dest->{ip}; + push @$cmd, 'ssh', '-o', 'BatchMode=yes', "$param->{dest_user}\@$dest->{ip}", '--' if $dest->{ip}; push @$cmd, 'zfs', 'recv', '-F', '--'; push @$cmd, "$target"; @@ -923,38 +960,39 @@ sub send_image { }; if (my $erro = $@) { - snapshot_destroy($source, undef, $param->{method}, $source->{new_snap}); + snapshot_destroy($source, undef, $param->{method}, $source->{new_snap}, $param->{source_user}, $param->{dest_user}); die $erro; }; } sub send_config{ - my ($source, $dest, $method) = @_; + my ($source, $dest, $method, $source_user, $dest_user, $dest_config_path) = @_; 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_config_path // $CONFIG_PATH; + $config_dir .= "/$dest->{last_part}" if $dest->{last_part}; $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"]); + run_cmd(['ssh', "$dest_user\@$dest->{ip}", '--', 'mkdir', '-p', '--', $config_dir]); + run_cmd(['scp', '--', "$source_user\@[$source->{ip}]:$source_target", "$dest_user\@[$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"]); + run_cmd(['ssh', "$dest_user\@$dest->{ip}", '--', 'mkdir', '-p', '--', $config_dir]); + run_cmd(['scp', '--', $source_target, "$dest_user\@[$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]); + run_cmd(['scp', '--', "$source_user\@[$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]); + run_cmd(['ssh', "$dest_user\@$dest->{ip}", '--', 'rm', '-f', '--', $dest_target_old]); } else { run_cmd(['rm', '-f', '--', $dest_target_old]); } @@ -1008,98 +1046,122 @@ sub disable_job { update_cron($job); } -my $command = $ARGV[0]; +my $cmd_help = { + destroy => qq{ +$PROGNAME destroy -source [OPTIONS] -my $commands = {'destroy' => 1, - 'create' => 1, - 'sync' => 1, - 'list' => 1, - 'status' => 1, - 'help' => 1, - 'enable' => 1, - 'disable' => 1}; - -if (!$command || !$commands->{$command}) { - usage(); - die "\n"; -} + remove a sync Job from the scheduler -my $help_sync = < -source [OPTIONS]\n + -name string - will sync one time + name of the sync job, if not set it is default + + -source string + + the source can be an or [IP:][/Path] + }, + create => qq{ +$PROGNAME create -dest -source [OPTIONS] + + Create a sync Job -dest string - the destination target is like [IP:][/Path] + the destination target is like [IP]:[/Path] - -limit integer + -dest-user string + + name of the user on the destination target, root by default + + -limit integer max sync speed in kBytes/s, default unlimited - -maxsnap integer + -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. - It is only necessary if scheduler allready contains this source. + 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 or [IP:][/Path] - -verbose boolean + -source-user string - print out the sync progress. -EOF + name of the user on the source target, root by default -my $help_create = < -source [OPTIONS] + -properties boolean - Create a sync Job + Include the dataset's properties in the stream. + + -dest-config-path string + + specify a custom config path on the destination target. default is /var/lib/pve-zsync + }, + sync => qq{ +$PROGNAME sync -dest -source [OPTIONS]\n + + will sync one time -dest string - the destination target is like [IP]:[/Path] + the destination target is like [IP:][/Path] - -limit integer + -dest-user string + + name of the user on the destination target, root by default + + -limit integer max sync speed in kBytes/s, default unlimited - -maxsnap string + -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 - - -skip boolean - - if this flag is set it will skip the first sync + 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 or [IP:][/Path] -EOF -my $help_destroy = < [OPTIONS] + -source-user string - remove a sync Job from the scheduler + name of the user on the source target, root by default - -name string + -verbose boolean - name of the sync job, if not set it is default + print out the sync progress. - -source string + -properties boolean - the source can be an or [IP:][/Path] -EOF + Include the dataset's properties in the stream. + + -dest-config-path string + + specify a custom config path on the destination target. default is /var/lib/pve-zsync + }, + list => qq{ +$PROGNAME list + + Get a List of all scheduled Sync Jobs + }, + status => qq{ +$PROGNAME status -my $help_help = < qq{ $PROGNAME help [OPTIONS] Get help about specified command. @@ -1111,21 +1173,8 @@ $PROGNAME help [OPTIONS] -verbose boolean Verbose output format. -EOF - -my $help_list = < qq{ $PROGNAME enable -source [OPTIONS] enable a syncjob and reset error @@ -1137,9 +1186,8 @@ $PROGNAME enable -source [OPTIONS] -source string the source can be an or [IP:][/Path] -EOF - -my $help_disable = < qq{ $PROGNAME disable -source [OPTIONS] pause a sync job @@ -1151,57 +1199,42 @@ $PROGNAME disable -source [OPTIONS] -source string the source can be an or [IP:][/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"; + }, + printpod => 'internal command', - } 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"; - - } +}; +if (!$command) { + usage(); die "\n"; +} elsif (!$cmd_help->{$command}) { + print "ERROR: unknown command '$command'"; + usage(1); die "\n"; } my @arg = @ARGV; my $param = parse_argv(@arg); +sub check_params { + for (@_) { + die "$cmd_help->{$command}\n" if !$param->{$_}; + } +} + if ($command eq 'destroy') { - die "$help_destroy\n" if !$param->{source}; + check_params(qw(source)); check_target($param->{source}); destroy_job($param); } elsif ($command eq 'sync') { - die "$help_sync\n" if !$param->{source} || !$param->{dest}; + check_params(qw(source 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_params(qw(source dest)); check_target($param->{source}); check_target($param->{dest}); @@ -1216,11 +1249,11 @@ if ($command eq 'destroy') { } elsif ($command eq 'help') { my $help_command = $ARGV[1]; - if ($help_command && $commands->{$help_command}) { - print help($help_command); + if ($help_command && $cmd_help->{$help_command}) { + die "$cmd_help->{$help_command}\n"; } - if ($param->{verbose} == 1){ + if ($param->{verbose}) { exec("man $PROGNAME"); } else { @@ -1229,17 +1262,19 @@ if ($command eq 'destroy') { } } elsif ($command eq 'enable') { - die "$help_enable\n" if !$param->{source}; + check_params(qw(source)); check_target($param->{source}); enable_job($param); } elsif ($command eq 'disable') { - die "$help_disable\n" if !$param->{source}; + check_params(qw(source)); check_target($param->{source}); disable_job($param); +} elsif ($command eq 'printpod') { + print_pod(); } sub usage { @@ -1262,8 +1297,11 @@ sub check_target { parse_target($target); } -__END__ +sub print_pod { + my $synopsis = join("\n", sort values %$cmd_help); + + print < [ARGS] [OPTIONS] -pve-zsync help [OPTIONS] - - Get help about specified command. - - string - - Command name - - -verbose boolean - - Verbose output format. - -pve-zsync create -dest -source [OPTIONS] - - Create a sync Job - - -dest string - - the destination target is like [IP]:[/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 or [IP:][/Path] - -pve-zsync destroy -source [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 or [IP:][/Path] - -pve-zsync disable -source [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 or [IP:][/Path] - -pve-zsync enable -source [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 or [IP:][/Path] -pve-zsync list - - Get a List of all scheduled Sync Jobs - -pve-zsync status - - Get the status of all scheduled Sync Jobs - -pve-zsync sync -dest -source [OPTIONS] - - will sync one time - - -dest string - - the destination target is like [IP:][/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 or [IP:][/Path] - - -verbose boolean - - print out the sync progress. +$synopsis =head1 DESCRIPTION @@ -1423,3 +1351,6 @@ Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . + +EOF +}