]> git.proxmox.com Git - pve-zsync.git/blobdiff - pve-zsync
bump version to 2.3.1
[pve-zsync.git] / pve-zsync
index 1213361ab1e2997fa80d63971ebbefc36c02ffef..de5d46f529f6a6f897d56349961fda11d60c74d3 100755 (executable)
--- a/pve-zsync
+++ b/pve-zsync
@@ -9,6 +9,7 @@ use File::Path qw(make_path);
 use JSON;
 use IO::File;
 use String::ShellQuote 'shell_quote';
+use Text::ParseWords;
 
 my $PROGNAME = "pve-zsync";
 my $CONFIG_PATH = "/var/lib/${PROGNAME}";
@@ -53,7 +54,7 @@ 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\-_]+)(/.+)?)$!;
 
-my $DISK_KEY_RE = qr/^(?:(?:(?:virtio|ide|scsi|sata|efidisk|mp)\d+)|rootfs): /;
+my $DISK_KEY_RE = qr/^(?:(?:(?:virtio|ide|scsi|sata|efidisk|tpmstate|mp)\d+)|rootfs): /;
 
 my $INSTANCE_ID = get_instance_id($$);
 
@@ -232,7 +233,7 @@ sub read_cron {
 
     my $text = read_file($CRONJOBS, 0);
 
-    return encode_cron(@{$text});
+    return parse_cron(@{$text});
 }
 
 sub parse_argv {
@@ -244,12 +245,14 @@ sub parse_argv {
        verbose => undef,
        limit => undef,
        maxsnap => undef,
+       dest_maxsnap => undef,
        name => undef,
        skip => undef,
        method => undef,
        source_user => undef,
        dest_user => undef,
        prepend_storage_id => undef,
+       compressed => undef,
        properties => undef,
        dest_config_path => undef,
     };
@@ -261,12 +264,14 @@ sub parse_argv {
        'verbose' => \$param->{verbose},
        'limit=i' => \$param->{limit},
        'maxsnap=i' => \$param->{maxsnap},
+       'dest-maxsnap=i' => \$param->{dest_maxsnap},
        'name=s' => \$param->{name},
        'skip' => \$param->{skip},
        'method=s' => \$param->{method},
        'source-user=s' => \$param->{source_user},
        'dest-user=s' => \$param->{dest_user},
        'prepend-storage-id' => \$param->{prepend_storage_id},
+       'compressed' => \$param->{compressed},
        'properties' => \$param->{properties},
        'dest-config-path=s' => \$param->{dest_config_path},
     );
@@ -300,14 +305,13 @@ sub add_state_to_job {
     return $job;
 }
 
-sub encode_cron {
+sub parse_cron {
     my (@text) = @_;
 
     my $cfg = {};
 
     while (my $line = shift(@text)) {
-
-       my @arg = split('\s', $line);
+       my @arg = Text::ParseWords::shellwords($line);
        my $param = parse_argv(@arg);
 
        if ($param->{source} && $param->{dest}) {
@@ -336,10 +340,12 @@ sub param_to_job {
     $job->{method} = "ssh" if !$job->{method};
     $job->{limit} = $param->{limit};
     $job->{maxsnap} = $param->{maxsnap};
+    $job->{dest_maxsnap} = $param->{dest_maxsnap};
     $job->{source} = $param->{source};
     $job->{source_user} = $param->{source_user};
     $job->{dest_user} = $param->{dest_user};
     $job->{prepend_storage_id} = !!$param->{prepend_storage_id};
+    $job->{compressed} = !!$param->{compressed};
     $job->{properties} = !!$param->{properties};
     $job->{dest_config_path} = $param->{dest_config_path} if $param->{dest_config_path};
 
@@ -460,12 +466,14 @@ sub format_job {
     $text .= " root";
     $text .= " $PROGNAME sync --source $job->{source} --dest $job->{dest}";
     $text .= " --name $job->{name} --maxsnap $job->{maxsnap}";
+    $text .= " --dest-maxsnap $job->{dest_maxsnap}" if defined($job->{dest_maxsnap});
     $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 .= " --prepend-storage-id" if $job->{prepend_storage_id};
+    $text .= " --compressed" if $job->{compressed};
     $text .= " --properties" if $job->{properties};
     $text .= " --dest-config-path $job->{dest_config_path}" if $job->{dest_config_path};
     $text .= "\n";
@@ -681,20 +689,31 @@ sub sync {
 
            ($dest->{old_snap}, $dest->{last_snap}) = snapshot_get(
                $dest_dataset,
-               $param->{maxsnap},
+               $param->{dest_maxsnap} // $param->{maxsnap},
                $param->{name},
                $dest->{ip},
                $param->{dest_user},
            );
 
+           ($source->{old_snap}) = snapshot_get(
+               $source->{all},
+               $param->{maxsnap},
+               $param->{name},
+               $source->{ip},
+               $param->{source_user},
+           );
+
            prepare_prepended_target($source, $dest, $param->{dest_user}) if defined($dest->{prepend});
 
            snapshot_add($source, $dest, $param->{name}, $date, $param->{source_user}, $param->{dest_user});
 
            send_image($source, $dest, $param);
 
-           for my $old_snap (@{$dest->{old_snap}}) {
+           for my $old_snap (@{$source->{old_snap}}) {
                snapshot_destroy($source->{all}, $old_snap, $source->{ip}, $param->{source_user});
+           }
+
+           for my $old_snap (@{$dest->{old_snap}}) {
                snapshot_destroy($dest_dataset, $old_snap, $dest->{ip}, $param->{dest_user});
            }
        };
@@ -930,11 +949,12 @@ sub parse_disks {
            $num++;
 
        } else {
-           die "ERROR: in path\n";
+           die "unexpected path '$path'\n";
        }
     }
 
-    die "Vm include no disk on zfs.\n" if !$disks->{0};
+    die "Guest does not include any ZFS volumes (or all are excluded by the backup flag).\n"
+       if !$disks->{0};
     return $disks;
 }
 
@@ -1013,6 +1033,8 @@ sub send_image {
 
     push @$cmd, 'ssh', '-o', 'BatchMode=yes', "$param->{source_user}\@$source->{ip}", '--' if $source->{ip};
     push @$cmd, 'zfs', 'send';
+    push @$cmd, '-L', if $param->{compressed}; # no effect if dataset never had large recordsize
+    push @$cmd, '-c', if $param->{compressed};
     push @$cmd, '-p', if $param->{properties};
     push @$cmd, '-v' if $param->{verbose};
 
@@ -1157,6 +1179,9 @@ $PROGNAME create --dest <string> --source <string> [OPTIONS]
                The number of snapshots to keep until older ones are erased.
                The default is 1, use 0 for unlimited.
 
+       --dest-maxsnap   integer
+               Override maxsnap for the destination dataset.
+
        --name      string
                The name of the sync job, if not set it is default
 
@@ -1172,6 +1197,11 @@ $PROGNAME create --dest <string> --source <string> [OPTIONS]
        --source-user    string
                The (ssh) user-name on the source target, root by default
 
+       --compressed
+               If specified, send data without decompressing first. If features lz4_compress,
+               zstd_compress or large_blocks are in use by the source, they need to be enabled on
+               the target as well.
+
        --properties
                If specified, include the dataset's properties in the stream.
 
@@ -1197,6 +1227,9 @@ $PROGNAME sync --dest <string> --source <string> [OPTIONS]\n
                The number of snapshots to keep until older ones are erased.
                The default is 1, use 0 for unlimited.
 
+       --dest-maxsnap   integer
+               Override maxsnap for the destination dataset.
+
        --name      string
                The name of the sync job, if not set it is 'default'.
                It is only necessary if scheduler allready contains this source.
@@ -1213,6 +1246,11 @@ $PROGNAME sync --dest <string> --source <string> [OPTIONS]\n
        --verbose
                If specified, print out the sync progress.
 
+       --compressed
+               If specified, send data without decompressing first. If features lz4_compress,
+               zstd_compress or large_blocks are in use by the source, they need to be enabled on
+               the target as well.
+
        --properties
                If specified, include the dataset's properties in the stream.