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 {
}
my $USE_CRYPT_PARAMS = {
- backup => 1,
- restore => 1,
- 'upload-log' => 1,
- list => 1,
- extract => 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);
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();
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" };
outfunc => $outfunc,
errmsg => "$binary failed",
binary => $binary,
+ namespace => $namespace,
);
return undef if $no_output;
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
$cmd_opts //= {};
+ $cmd_opts->{namespace} = $self->{scfg}->{namespace} if defined($self->{scfg}->{namespace});
+
return run_raw_client_cmd($self, 'backup', $param, %$cmd_opts);
};
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",
];
$cmd_opts //= {};
+ $cmd_opts->{namespace} = $namespace;
+
return run_raw_client_cmd($self, 'restore', $param, %$cmd_opts);
};
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 {
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;
}
push @$param, "$group";
- return run_client_cmd($self, 'prune', $param);
+ return run_client_cmd($self, 'prune', $param, undef, undef, $namespace);
};
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,
);
}
# 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" };
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",
);