]> git.proxmox.com Git - pve-zsync.git/blobdiff - pve-zsync
introduce and use read_file helper
[pve-zsync.git] / pve-zsync
index ea3178e8e68d41dceba4356bf295b5b241ef73af..76e12ced9e0e199b6fdea38e6e856e00e4ed5fb3 100755 (executable)
--- a/pve-zsync
+++ b/pve-zsync
@@ -53,6 +53,8 @@ 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 $command = $ARGV[0];
 
 if (defined($command) && $command ne 'help' && $command ne 'printpod') {
@@ -79,6 +81,19 @@ sub check_bin {
     die "unable to find command '$bin'\n";
 }
 
+sub read_file {
+    my ($filename, $one_line_only) = @_;
+
+    my $fh = IO::File->new($filename, "r")
+       or die "Could not open file ${filename}: $!\n";
+
+    my $text = $one_line_only ? <$fh> : [ <$fh> ];
+
+    close($fh);
+
+    return $text;
+}
+
 sub cut_target_width {
     my ($path, $maxlen) = @_;
     $path =~ s@/+@/@g;
@@ -200,14 +215,9 @@ sub read_cron {
        return undef;
     }
 
-    my $fh = IO::File->new("< $CRONJOBS");
-    die "Could not open file $CRONJOBS: $!\n" if !$fh;
+    my $text = read_file($CRONJOBS, 0);
 
-    my @text = <$fh>;
-
-    close($fh);
-
-    return encode_cron(@text);
+    return encode_cron(@{$text});
 }
 
 sub parse_argv {
@@ -327,28 +337,14 @@ sub read_state {
        return undef;
     }
 
-    my $fh = IO::File->new("< $STATE");
-    die "Could not open file $STATE: $!\n" if !$fh;
-
-    my $text = <$fh>;
-    my $states = decode_json($text);
-
-    close($fh);
-
-    return $states;
+    my $text = read_file($STATE, 1);
+    return decode_json($text);
 }
 
 sub update_state {
     my ($job) = @_;
-    my $text;
-    my $in_fh;
 
-    eval {
-
-       $in_fh = IO::File->new("< $STATE");
-       die "Could not open file $STATE: $!\n" if !$in_fh;
-       $text = <$in_fh>;
-    };
+    my $text = eval { read_file($STATE, 1); };
 
     my $out_fh = IO::File->new("> $STATE.new");
     die "Could not open file ${STATE}.new: $!\n" if !$out_fh;
@@ -380,9 +376,6 @@ sub update_state {
 
     close($out_fh);
     rename "$STATE.new", $STATE;
-    eval {
-       close($in_fh);
-    };
 
     return $states;
 }
@@ -397,12 +390,9 @@ sub update_cron {
     my $header = "SHELL=/bin/sh\n";
     $header .= "PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n\n";
 
-    my $fh = IO::File->new("< $CRONJOBS");
-    die "Could not open file $CRONJOBS: $!\n" if !$fh;
-
-    my @test = <$fh>;
+    my $current = read_file($CRONJOBS, 0);
 
-    while (my $line = shift(@test)) {
+    foreach my $line (@{$current}) {
        chomp($line);
        if ($line =~ m/source $job->{source} .*name $job->{name} /) {
            $updated = 1;
@@ -431,7 +421,6 @@ sub update_cron {
     close ($new_fh);
 
     die "can't move $CRONJOBS.new: $!\n" if !rename "${CRONJOBS}.new", $CRONJOBS;
-    close ($fh);
 }
 
 sub format_job {
@@ -632,13 +621,13 @@ 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}, $param->{source_user});
+           ($dest->{old_snap}, $dest->{last_snap}) = snapshot_get($source, $dest, $param->{maxsnap}, $param->{name}, $param->{dest_user});
 
            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}, $param->{source_user}, $param->{dest_user}) if ($source->{destroy} && $source->{old_snap});
+           snapshot_destroy($source, $dest, $param->{method}, $dest->{old_snap}, $param->{source_user}, $param->{dest_user}) if ($source->{destroy} && $dest->{old_snap});
 
        };
 
@@ -692,14 +681,22 @@ sub sync {
 }
 
 sub snapshot_get{
-    my ($source, $dest, $max_snap, $name, $source_user) = @_;
+    my ($source, $dest, $max_snap, $name, $dest_user) = @_;
 
     my $cmd = [];
-    push @$cmd, 'ssh', "$source_user\@$source->{ip}", '--', if $source->{ip};
+    push @$cmd, 'ssh', "$dest_user\@$dest->{ip}", '--', if $dest->{ip};
     push @$cmd, 'zfs', 'list', '-r', '-t', 'snapshot', '-Ho', 'name', '-S', 'creation';
-    push @$cmd, $source->{all};
 
-    my $raw = run_cmd($cmd);
+    my $path = $dest->{all};
+    $path .= "/$source->{last_part}" if $source->{last_part};
+    push @$cmd, $path;
+
+    my $raw;
+    eval {$raw = run_cmd($cmd)};
+    if (my $erro =$@) { #this means the volume doesn't exist on dest yet
+       return undef;
+    }
+
     my $index = 0;
     my $line = "";
     my $last_snap = undef;
@@ -707,9 +704,10 @@ sub snapshot_get{
 
     while ($raw && $raw =~ s/^(.*?)(\n|$)//) {
        $line = $1;
-       if ($line =~ m/(rep_\Q${name}\E_\d{4}-\d{2}-\d{2}_\d{2}:\d{2}:\d{2})$/) {
-
+       if ($line =~ m/@(.*)$/) {
            $last_snap = $1 if (!$last_snap);
+       }
+       if ($line =~ m/(rep_\Q${name}\E_\d{4}-\d{2}-\d{2}_\d{2}:\d{2}:\d{2})$/) {
            $old_snap = $1;
            $index++;
            if ($index == $max_snap) {
@@ -746,42 +744,6 @@ sub snapshot_add {
     }
 }
 
-sub write_cron {
-    my ($cfg) = @_;
-
-    my $text = "SHELL=/bin/sh\n";
-    $text .= "PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n";
-
-    my $fh = IO::File->new("> $CRONJOBS");
-    die "Could not open file: $!\n" if !$fh;
-
-    foreach my $source (sort keys%{$cfg}) {
-       foreach my $sync_name (sort keys%{$cfg->{$source}}) {
-           next if $cfg->{$source}->{$sync_name}->{status} ne 'ok';
-           $text .= "$PROG_PATH sync";
-           $text .= " -source  ";
-           if ($cfg->{$source}->{$sync_name}->{vmid}) {
-               $text .= "$cfg->{$source}->{$sync_name}->{source_ip}:" if $cfg->{$source}->{$sync_name}->{source_ip};
-               $text .= "$cfg->{$source}->{$sync_name}->{vmid} ";
-           } else {
-               $text .= "$cfg->{$source}->{$sync_name}->{source_ip}:" if $cfg->{$source}->{$sync_name}->{source_ip};
-               $text .= "$cfg->{$source}->{$sync_name}->{source_pool}";
-               $text .= "$cfg->{$source}->{$sync_name}->{source_path}" if $cfg->{$source}->{$sync_name}->{source_path};
-           }
-           $text .= " -dest  ";
-           $text .= "$cfg->{$source}->{$sync_name}->{dest_ip}:" if $cfg->{$source}->{$sync_name}->{dest_ip};
-           $text .= "$cfg->{$source}->{$sync_name}->{dest_pool}";
-           $text .= "$cfg->{$source}->{$sync_name}->{dest_path}" if $cfg->{$source}->{$sync_name}->{dest_path};
-           $text .= " -name $sync_name ";
-           $text .= " -limit $cfg->{$source}->{$sync_name}->{limit}" if $cfg->{$source}->{$sync_name}->{limit};
-           $text .= " -maxsnap $cfg->{$source}->{$sync_name}->{maxsnap}" if $cfg->{$source}->{$sync_name}->{maxsnap};
-           $text .= "\n";
-       }
-    }
-    die "Can't write to cron\n" if (!print($fh $text));
-    close($fh);
-}
-
 sub get_disks {
     my ($target, $user) = @_;
 
@@ -830,7 +792,7 @@ sub parse_disks {
        my $line = $1;
 
        next if $line =~ /media=cdrom/;
-       next if $line !~ m/^(?:((?:virtio|ide|scsi|sata|mp)\d+)|rootfs): /;
+       next if $line !~ m/$DISK_KEY_RE/;
 
        #QEMU if backup is not set include in  sync
        next if $vm_type eq 'qemu' && ($line =~ m/backup=(?i:0|no|off|false)/);
@@ -840,7 +802,7 @@ sub parse_disks {
 
        my $disk = undef;
        my $stor = undef;
-       if($line =~ m/^(?:(?:(?:virtio|ide|scsi|sata|mp)\d+)|rootfs): (.*)$/) {
+       if($line =~ m/$DISK_KEY_RE(.*)$/) {
            my @parameter = split(/,/,$1);
 
            foreach my $opt (@parameter) {
@@ -931,31 +893,25 @@ sub snapshot_destroy {
     }
 }
 
+# check if snapshot for incremental sync exist on source side
 sub snapshot_exist {
-    my ($source , $dest, $method, $dest_user) = @_;
+    my ($source , $dest, $method, $source_user) = @_;
 
     my $cmd = [];
-    push @$cmd, 'ssh', "$dest_user\@$dest->{ip}", '--' if $dest->{ip};
+    push @$cmd, 'ssh', "$source_user\@$source->{ip}", '--' if $source->{ip};
     push @$cmd, 'zfs', 'list', '-rt', 'snapshot', '-Ho', 'name';
 
-    my $path = $dest->{all};
-    $path .= "/$source->{last_part}" if $source->{last_part};
-    $path .= "\@$source->{old_snap}";
+    my $path = $source->{all};
+    $path .= "\@$dest->{last_snap}";
 
     push @$cmd, $path;
 
-
-    my $text = "";
-    eval {$text =run_cmd($cmd);};
+    eval {run_cmd($cmd)};
     if (my $erro =$@) {
        warn "WARN: $erro";
        return undef;
     }
-
-    while ($text && $text =~ s/^(.*?)(\n|$)//) {
-       my $line =$1;
-       return 1 if $line =~ m/^.*$source->{old_snap}$/;
-    }
+    return 1;
 }
 
 sub send_image {
@@ -968,8 +924,8 @@ sub send_image {
     push @$cmd, '-p', if $param->{properties};
     push @$cmd, '-v' if $param->{verbose};
 
-    if($source->{last_snap} && snapshot_exist($source , $dest, $param->{method}, $param->{dest_user})) {
-       push @$cmd, '-i', "$source->{all}\@$source->{last_snap}";
+    if($dest->{last_snap} && snapshot_exist($source , $dest, $param->{method}, $param->{source_user})) {
+       push @$cmd, '-i', "$source->{all}\@$dest->{last_snap}";
     }
     push @$cmd, '--', "$source->{all}\@$source->{new_snap}";
 
@@ -1021,7 +977,7 @@ sub send_config{
        }
 
        if ($source->{destroy}){
-           my $dest_target_old ="${config_dir}/$source->{vmid}.conf.$source->{vm_type}.$source->{old_snap}";
+           my $dest_target_old ="${config_dir}/$source->{vmid}.conf.$source->{vm_type}.$dest->{old_snap}";
            if($dest->{ip}){
                run_cmd(['ssh', "$dest_user\@$dest->{ip}", '--', 'rm', '-f', '--', $dest_target_old]);
            } else {