]> git.proxmox.com Git - pve-manager.git/blobdiff - PVE/VZDump.pm
vzdump: remove deprecated size parameter
[pve-manager.git] / PVE / VZDump.pm
index 8574fc94d1b81a2c7ea7084df591d4c8ec966ba4..8213ed665155eeb0f3313bcaa564ab7141b81092 100644 (file)
@@ -75,10 +75,11 @@ my $parse_prune_backups_maxfiles = sub {
     my $maxfiles = delete $param->{maxfiles};
     my $prune_backups = $param->{'prune-backups'};
 
-    warn "both 'maxfiles' and 'prune-backups' defined as ${kind} - ignoring 'maxfiles'\n"
+    debugmsg('warn', "both 'maxfiles' and 'prune-backups' defined as ${kind} - ignoring 'maxfiles'")
         if defined($maxfiles) && defined($prune_backups);
 
     if (defined($prune_backups)) {
+       return if ref($prune_backups) eq 'HASH'; # already parsed
        $param->{'prune-backups'} = PVE::JSONSchema::parse_property_string(
            'prune-backups',
            $prune_backups
@@ -105,8 +106,6 @@ sub storage_info {
     die "can't use storage '$storage' for backups - wrong content type\n"
        if (!$scfg->{content}->{backup});
 
-    PVE::Storage::activate_storage($cfg, $storage);
-
     my $info = {
        scfg => $scfg,
     };
@@ -211,6 +210,7 @@ sub read_vzdump_defaults {
             defined($default) ? ($_ => $default) : ()
        } keys %$confdesc
     };
+    $parse_prune_backups_maxfiles->($defaults, "defaults in VZDump schema");
 
     my $raw;
     eval { $raw = PVE::Tools::file_get_contents($fn); };
@@ -225,11 +225,17 @@ sub read_vzdump_defaults {
        my @mailto = split_list($res->{mailto});
        $res->{mailto} = [ @mailto ];
     }
+    $parse_prune_backups_maxfiles->($res, "options in '$fn'");
 
     foreach my $key (keys %$defaults) {
        $res->{$key} = $defaults->{$key} if !defined($res->{$key});
     }
 
+    if (defined($res->{storage}) && defined($res->{dumpdir})) {
+       debugmsg('warn', "both 'storage' and 'dumpdir' defined in '$fn' - ignoring 'dumpdir'");
+       delete $res->{dumpdir};
+    }
+
     return $res;
 }
 
@@ -311,15 +317,15 @@ sub sendmail {
            $text_log_part .= "$vmid: no log available\n\n";
            next;
        }
-       if (open (TMP, "$log")) {
-           while (my $line = <TMP>) {
+       if (open (my $TMP, '<', "$log")) {
+           while (my $line = <$TMP>) {
                next if $line =~ /^status: \d+/; # not useful in mails
                $text_log_part .= encode8bit ("$vmid: $line");
            }
+           close ($TMP);
        } else {
            $text_log_part .= "$vmid: Could not open log file\n\n";
        }
-       close (TMP);
        $text_log_part .= "\n";
     }
     $text_log_part .= $detail_post if defined($detail_post);
@@ -331,24 +337,29 @@ sub sendmail {
     $html .= "<tr><td>VMID<td>NAME<td>STATUS<td>TIME<td>SIZE<td>FILENAME</tr>\n";
 
     my $ssize = 0;
-
     foreach my $task (@$tasklist) {
        my $vmid = $task->{vmid};
        my $name = $task->{hostname};
 
        if  ($task->{state} eq 'ok') {
-
            $ssize += $task->{size};
 
-           $html .= sprintf ("<tr><td>%s<td>%s<td>OK<td>%s<td align=right>%s<td>%s</tr>\n",
-                               $vmid, $name,
-                               format_time($task->{backuptime}),
-                               format_size ($task->{size}),
-                               escape_html ($task->{target}));
+           $html .= sprintf (
+               "<tr><td>%s<td>%s<td>OK<td>%s<td align=right>%s<td>%s</tr>\n",
+               $vmid,
+               $name,
+               format_time($task->{backuptime}),
+               format_size ($task->{size}),
+               escape_html ($task->{target}),
+           );
        } else {
-           $html .= sprintf ("<tr><td>%s<td>%s<td><font color=red>FAILED<td>%s<td colspan=2>%s</tr>\n",
-                               $vmid, $name, format_time($task->{backuptime}),
-                               escape_html ($task->{msg}));
+           $html .= sprintf (
+               "<tr><td>%s<td>%s<td><font color=red>FAILED<td>%s<td colspan=2>%s</tr>\n",
+               $vmid,
+               $name,
+               format_time($task->{backuptime}),
+               escape_html ($task->{msg}),
+           );
        }
     }
 
@@ -369,8 +380,8 @@ sub sendmail {
            $html_log_part .= "$vmid: no log available\n\n";
            next;
        }
-       if (open (TMP, "$log")) {
-           while (my $line = <TMP>) {
+       if (open (my $TMP, '<', "$log")) {
+           while (my $line = <$TMP>) {
                next if $line =~ /^status: \d+/; # not useful in mails
                if ($line =~ m/^\S+\s\d+\s+\d+:\d+:\d+\s+(ERROR|WARN):/) {
                    $html_log_part .= encode8bit ("$vmid: <font color=red>".
@@ -379,21 +390,23 @@ sub sendmail {
                    $html_log_part .= encode8bit ("$vmid: " . escape_html ($line));
                }
            }
+           close ($TMP);
        } else {
            $html_log_part .= "$vmid: Could not open log file\n\n";
        }
-       close (TMP);
        $html_log_part .= "\n";
     }
     $html_log_part .= escape_html($detail_post) if defined($detail_post);
     $html_log_part .= "</pre>";
-    my $html_end .= "\n</body></html>\n";
+    my $html_end = "\n</body></html>\n";
     # end html part
 
     if (length($text) + length($text_log_part) +
-       length($html) + length($html_log_part) < MAX_MAIL_SIZE)
+       length($html) + length($html_log_part) +
+       length($html_end) < MAX_MAIL_SIZE)
     {
        $html .= $html_log_part;
+       $html .= $html_end;
        $text .= $text_log_part;
     } else {
        my $msg = "Log output was too long to be sent by mail. ".
@@ -434,10 +447,8 @@ sub new {
 
     my $defaults = read_vzdump_defaults();
 
-    $opts->{remove} = 1 if !defined($opts->{remove});
-
     foreach my $k (keys %$defaults) {
-       next if $k eq 'exclude-path' || $k eq 'maxfiles'; # dealt with separately
+       next if $k eq 'exclude-path' || $k eq 'prune-backups'; # dealt with separately
        if ($k eq 'dumpdir' || $k eq 'storage') {
            $opts->{$k} = $defaults->{$k} if !defined ($opts->{dumpdir}) &&
                !defined ($opts->{storage});
@@ -450,7 +461,11 @@ sub new {
     $opts->{tmpdir} =~ s|/+$|| if ($opts->{tmpdir});
 
     $skiplist = [] if !$skiplist;
-    my $self = bless { cmdline => $cmdline, opts => $opts, skiplist => $skiplist };
+    my $self = bless {
+       cmdline => $cmdline,
+       opts => $opts,
+       skiplist => $skiplist,
+    }, $class;
 
     my $findexcl = $self->{findexcl} = [];
     if ($defaults->{'exclude-path'}) {
@@ -462,14 +477,15 @@ sub new {
     }
 
     if ($opts->{stdexcludes}) {
-       push @$findexcl, '/tmp/?*',
-                        '/var/tmp/?*',
-                        '/var/run/?*.pid';
+       push @$findexcl,
+           '/tmp/?*',
+           '/var/tmp/?*',
+           '/var/run/?*.pid',
+           ;
     }
 
     foreach my $p (@plugins) {
-
-       my $pd = $p->new ($self);
+       my $pd = $p->new($self);
 
        push @{$self->{plugins}}, $pd;
     }
@@ -487,18 +503,22 @@ sub new {
     my $errors = '';
 
     if ($opts->{storage}) {
+       my $storage_cfg = PVE::Storage::config();
+       eval { PVE::Storage::activate_storage($storage_cfg, $opts->{storage}) };
+       if (my $err = $@) {
+           chomp($err);
+           $errors .= "could not activate storage '$opts->{storage}': $err";
+       }
+
        my $info = eval { storage_info ($opts->{storage}) };
        if (my $err = $@) {
+           chomp($err);
            $errors .= "could not get storage information for '$opts->{storage}': $err";
        } else {
            $opts->{dumpdir} = $info->{dumpdir};
            $opts->{scfg} = $info->{scfg};
            $opts->{pbs} = $info->{pbs};
-
-           if (!defined($opts->{'prune-backups'}) && !defined($opts->{maxfiles})) {
-               $opts->{'prune-backups'} = $info->{'prune-backups'};
-               $opts->{maxfiles} = $info->{maxfiles};
-           }
+           $opts->{'prune-backups'} //= $info->{'prune-backups'};
        }
     } elsif ($opts->{dumpdir}) {
        $errors .= "dumpdir '$opts->{dumpdir}' does not exist"
@@ -507,15 +527,7 @@ sub new {
        die "internal error";
     }
 
-    if (!defined($opts->{'prune-backups'})) {
-       my $maxfiles = delete $opts->{maxfiles} // $defaults->{maxfiles};
-       $maxfiles = int($maxfiles); # shouldn't be necessary, but be safe
-       if ($maxfiles) {
-           $opts->{'prune-backups'} = { 'keep-last' => $maxfiles };
-       } else {
-           $opts->{'prune-backups'} = { 'keep-all' => 1 };
-       }
-    }
+    $opts->{'prune-backups'} //= $defaults->{'prune-backups'};
 
     # avoid triggering any remove code path if keep-all is set
     $opts->{remove} = 0 if $opts->{'prune-backups'}->{'keep-all'};
@@ -570,28 +582,27 @@ sub getlock {
 
     die "missing UPID" if !$upid; # should not happen
 
-    if (!open (SERVER_FLCK, ">>$lockfile")) {
+    my $SERVER_FLCK;
+    if (!open ($SERVER_FLCK, '>>', "$lockfile")) {
        debugmsg ('err', "can't open lock on file '$lockfile' - $!", undef, 1);
        die "can't open lock on file '$lockfile' - $!";
     }
 
-    if (!flock (SERVER_FLCK, LOCK_EX|LOCK_NB)) {
-
+    if (!flock ($SERVER_FLCK, LOCK_EX|LOCK_NB)) {
        if (!$maxwait) {
            debugmsg ('err', "can't acquire lock '$lockfile' (wait = 0)", undef, 1);
            die "can't acquire lock '$lockfile' (wait = 0)";
        }
 
        debugmsg('info', "trying to get global lock - waiting...", undef, 1);
-
        eval {
            alarm ($maxwait * 60);
 
            local $SIG{ALRM} = sub { alarm (0); die "got timeout\n"; };
 
-           if (!flock (SERVER_FLCK, LOCK_EX)) {
+           if (!flock ($SERVER_FLCK, LOCK_EX)) {
                my $err = $!;
-               close (SERVER_FLCK);
+               close ($SERVER_FLCK);
                alarm (0);
                die "$err\n";
            }
@@ -610,6 +621,8 @@ sub getlock {
     }
 
     PVE::Tools::file_set_contents($pidfile, $upid);
+
+    return $SERVER_FLCK;
 }
 
 sub run_hook_script {
@@ -624,9 +637,12 @@ sub run_hook_script {
        die "The hook script '$script' is not executable.\n";
     }
 
-    my $cmd = "$script $phase";
+    my $cmd = [$script, $phase];
 
-    $cmd .= " $task->{mode} $task->{vmid}" if ($task);
+    if ($task) {
+       push @$cmd, $task->{mode};
+       push @$cmd, $task->{vmid};
+    }
 
     local %ENV;
     # set immutable opts directly (so they are available in all phases)
@@ -1073,9 +1089,16 @@ sub exec_backup_task {
     if ($task->{tmplog}) {
        if ($self->{opts}->{pbs}) {
            if ($task->{state} eq 'ok') {
-               my $param = [$pbs_snapshot_name, $task->{tmplog}];
-               PVE::Storage::PBSPlugin::run_raw_client_cmd(
-                   $opts->{scfg}, $opts->{storage}, 'upload-log', $param, errmsg => "upload log failed");
+               eval {
+                   PVE::Storage::PBSPlugin::run_raw_client_cmd(
+                       $opts->{scfg},
+                       $opts->{storage},
+                       'upload-log',
+                       [ $pbs_snapshot_name, $task->{tmplog} ],
+                       errmsg => "uploading backup task log failed",
+                   );
+               };
+               debugmsg('warn', "$@") if $@; # $@ contains already error prefix
            }
        } elsif ($task->{logfile}) {
            system {'cp'} 'cp', $task->{tmplog}, $task->{logfile};
@@ -1178,6 +1201,27 @@ sub option_exists {
     return defined($confdesc->{$key});
 }
 
+# NOTE it might make sense to merge this and verify_vzdump_parameters(), but one
+# needs to adapt command_line() in guest-common's PVE/VZDump/Common.pm and detect
+# a second parsing attempt, because verify_vzdump_parameters() is called twice
+# during the update_job API call.
+sub parse_mailto_exclude_path {
+    my ($param) = @_;
+
+    # exclude-path list need to be 0 separated
+    if (defined($param->{'exclude-path'})) {
+       my @expaths = split(/\0/, $param->{'exclude-path'} || '');
+       $param->{'exclude-path'} = [ @expaths ];
+    }
+
+    if (defined($param->{mailto})) {
+       my @mailto = PVE::Tools::split_list(extract_param($param, 'mailto'));
+       $param->{mailto} = [ @mailto ];
+    }
+
+    return;
+}
+
 sub verify_vzdump_parameters {
     my ($param, $check_missing) = @_;
 
@@ -1197,10 +1241,6 @@ sub verify_vzdump_parameters {
 
     $param->{all} = 1 if (defined($param->{exclude}) && !$param->{pool});
 
-    warn "option 'size' is deprecated and will be removed in a future " .
-        "release, please update your script/configuration!\n"
-       if defined($param->{size});
-
     return if !$check_missing;
 
     raise_param_exc({ vmid => "property is missing"})