]> git.proxmox.com Git - pve-common.git/blobdiff - src/PVE/PBSClient.pm
bump version to 8.2.1
[pve-common.git] / src / PVE / PBSClient.pm
index e96f20d9a493fbe29bcec0c9a658e9f2147cfba8..e63af03dfaa26f09a1f8735513eebd1f356665f8 100644 (file)
@@ -77,7 +77,7 @@ sub delete_password {
 
     my $pwfile = password_file_name($self);
 
-    unlink $pwfile or die "deleting password file failed - $!\n";
+    unlink $pwfile or $! == ENOENT or die "deleting password file failed - $!\n";
 };
 
 sub get_password {
@@ -130,20 +130,25 @@ my sub open_encryption_key {
 }
 
 my $USE_CRYPT_PARAMS = {
-    backup => 1,
-    restore => 1,
-    'upload-log' => 1,
+    'proxmox-backup-client' => {
+       backup => 1,
+       restore => 1,
+       'upload-log' => 1,
+    },
+    'proxmox-file-restore' => {
+       list => 1,
+       extract => 1,
+    },
 };
 
 my sub do_raw_client_cmd {
     my ($self, $client_cmd, $param, %opts) = @_;
 
-    my $use_crypto = $USE_CRYPT_PARAMS->{$client_cmd};
+    my $client_bin = (delete $opts{binary}) || 'proxmox-backup-client';
+    my $use_crypto = $USE_CRYPT_PARAMS->{$client_bin}->{$client_cmd} // 0;
 
-    my $client_exe = (delete $opts{binary}) || 'proxmox-backup-client';
-    $client_exe = "/usr/bin/$client_exe";
-    die "executable not found '$client_exe'! proxmox-backup-client or proxmox-backup-file-restore not installed?\n"
-       if ! -x $client_exe;
+    my $client_exe = "/usr/bin/$client_bin";
+    die "executable not found '$client_exe'! $client_bin not installed?\n" if ! -x $client_exe;
 
     my $scfg = $self->{scfg};
     my $repo = get_repository($scfg);
@@ -173,6 +178,9 @@ my sub do_raw_client_cmd {
     push @$cmd, @$param if defined($param);
 
     push @$cmd, "--repository", $repo;
+    if (defined(my $ns = delete($opts{namespace}))) {
+       push @$cmd, '--ns', $ns;
+    }
 
     local $ENV{PBS_PASSWORD} = $self->get_password();
 
@@ -189,13 +197,13 @@ my sub do_raw_client_cmd {
     run_command($cmd, %opts);
 }
 
-my sub run_raw_client_cmd {
+my sub run_raw_client_cmd : prototype($$$%) {
     my ($self, $client_cmd, $param, %opts) = @_;
     return do_raw_client_cmd($self, $client_cmd, $param, %opts);
 }
 
-my sub run_client_cmd {
-    my ($self, $client_cmd, $param, $no_output, $binary) = @_;
+my sub run_client_cmd : prototype($$;$$$$) {
+    my ($self, $client_cmd, $param, $no_output, $binary, $namespace) = @_;
 
     my $json_str = '';
     my $outfunc = sub { $json_str .= "$_[0]\n" };
@@ -214,6 +222,7 @@ my sub run_client_cmd {
        outfunc => $outfunc,
        errmsg => "$binary failed",
        binary => $binary,
+       namespace => $namespace,
     );
 
     return undef if $no_output;
@@ -233,14 +242,33 @@ sub autogen_encryption_key {
     return file_get_contents($encfile);
 };
 
+# TODO remove support for namespaced parameters. Needs Breaks for pmg-api and libpve-storage-perl.
+# Deprecated! The namespace should be passed in as part of the config in new().
+# Snapshot or group parameters can be either just a string and will then default to the namespace
+# that's part of the initial configuration in new(), or a tuple of `[namespace, snapshot]`.
+my sub split_namespaced_parameter : prototype($$) {
+    my ($self, $snapshot) = @_;
+    return ($self->{scfg}->{namespace}, $snapshot) if !ref($snapshot);
+
+    (my $namespace, $snapshot) = @$snapshot;
+    return ($namespace, $snapshot);
+}
+
 # lists all snapshots, optionally limited to a specific group
 sub get_snapshots {
     my ($self, $group) = @_;
 
+    my $namespace;
+    if (defined($group)) {
+       ($namespace, $group) = split_namespaced_parameter($self, $group);
+    } else {
+       $namespace = $self->{scfg}->{namespace};
+    }
+
     my $param = [];
     push @$param, $group if defined($group);
 
-    return run_client_cmd($self, "snapshots", $param);
+    return run_client_cmd($self, "snapshots", $param, undef, undef, $namespace);
 };
 
 # create a new PXAR backup of a FS directory tree - doesn't cross FS boundary
@@ -260,6 +288,8 @@ sub backup_fs_tree {
 
     $cmd_opts //= {};
 
+    $cmd_opts->{namespace} = $self->{scfg}->{namespace} if defined($self->{scfg}->{namespace});
+
     return run_raw_client_cmd($self, 'backup', $param, %$cmd_opts);
 };
 
@@ -270,6 +300,8 @@ sub restore_pxar {
     die "archive name not provided\n" if !defined($pxarname);
     die "restore-target not provided\n" if !defined($target);
 
+    (my $namespace, $snapshot) = split_namespaced_parameter($self, $snapshot);
+
     my $param = [
        "$snapshot",
        "$pxarname.pxar",
@@ -278,6 +310,8 @@ sub restore_pxar {
     ];
     $cmd_opts //= {};
 
+    $cmd_opts->{namespace} = $namespace;
+
     return run_raw_client_cmd($self, 'restore', $param, %$cmd_opts);
 };
 
@@ -286,7 +320,9 @@ sub forget_snapshot {
 
     die "snapshot not provided\n" if !defined($snapshot);
 
-    return run_raw_client_cmd($self, 'forget', ["$snapshot"]);
+    (my $namespace, $snapshot) = split_namespaced_parameter($self, $snapshot);
+
+    return run_client_cmd($self, 'forget', ["$snapshot"], 1, undef, $namespace)
 };
 
 sub prune_group {
@@ -294,6 +330,8 @@ sub prune_group {
 
     die "group not provided\n" if !defined($group);
 
+    (my $namespace, $group) = split_namespaced_parameter($self, $group);
+
     # do nothing if no keep options specified for remote
     return [] if scalar(keys %$prune_opts) == 0;
 
@@ -310,7 +348,7 @@ sub prune_group {
     }
     push @$param, "$group";
 
-    return run_client_cmd($self, 'prune', $param);
+    return run_client_cmd($self, 'prune', $param, undef, undef, $namespace);
 };
 
 sub status {
@@ -337,13 +375,22 @@ sub status {
 };
 
 sub file_restore_list {
-    my ($self, $snapshot, $filepath, $base64) = @_;
+    my ($self, $snapshot, $filepath, $base64, $extra_params) = @_;
+
+    (my $namespace, $snapshot) = split_namespaced_parameter($self, $snapshot);
+    my $cmd = [ $snapshot, $filepath, "--base64", $base64 ? 1 : 0];
+
+    if (my $timeout = $extra_params->{timeout}) {
+       push $cmd->@*, '--timeout', $timeout;
+    }
+
     return run_client_cmd(
        $self,
        "list",
-       [ $snapshot, $filepath, "--base64", $base64 ? 1 : 0 ],
+       $cmd,
        0,
        "proxmox-file-restore",
+       $namespace,
     );
 }
 
@@ -369,7 +416,9 @@ sub file_restore_extract_prepare {
 
 # this blocks while data is transfered, call this from a background worker
 sub file_restore_extract {
-    my ($self, $output_file, $snapshot, $filepath, $base64) = @_;
+    my ($self, $output_file, $snapshot, $filepath, $base64, $tar) = @_;
+
+    (my $namespace, $snapshot) = split_namespaced_parameter($self, $snapshot);
 
     my $ret = eval {
        local $SIG{ALRM} = sub { die "got timeout\n" };
@@ -381,11 +430,17 @@ sub file_restore_extract {
        my $fn = fileno($fh);
        my $errfunc = sub { print $_[0], "\n"; };
 
+       my $cmd = [ $snapshot, $filepath, "-", "--base64", $base64 ? 1 : 0];
+       if ($tar) {
+           push @$cmd, '--format', 'tar', '--zstd', 1;
+       }
+
        return run_raw_client_cmd(
            $self,
             "extract",
-           [ $snapshot, $filepath, "-", "--base64", $base64 ? 1 : 0 ],
+           $cmd,
            binary => "proxmox-file-restore",
+           namespace => $namespace,
            errfunc => $errfunc,
            output => ">&$fn",
        );