public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: "Fabian Grünbichler" <f.gruenbichler@proxmox.com>
To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>,
	Stefan Reiter <s.reiter@proxmox.com>
Subject: Re: [pve-devel] [PATCH storage 09/10] add FileRestore API for PBS
Date: Thu, 22 Apr 2021 08:19:51 +0200	[thread overview]
Message-ID: <1619071785.ey2usqrbcy.astroid@nora.none> (raw)
In-Reply-To: <fd73a3a0-4d16-7ab9-ed7c-551d7bd6e295@proxmox.com>

On April 21, 2021 3:38 pm, Stefan Reiter wrote:
> On 21/04/2021 15:26, Fabian Grünbichler wrote:
>> On April 21, 2021 1:15 pm, Stefan Reiter wrote:
>>> Includes list and restore calls.
>>>
>>> Requires VM.Backup and Datastore.Audit permissions, for the accessed
>>> VM/CT and containing datastore respectively.
>> 
>> we require Datastore.AllocateSpace + VM.Backup for the owning guest,
>> or Datastore.Allocate for the storage altogether for accessing backup
>> archives otherwise, maybe this should have the same logic?
>> 
> 
> sounds reasonable
> 
>>>
>>> Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
>>> ---
>>>
>>> Requires updated pve-common, pve-http-server.
>>>
>>>   PVE/API2/Storage/FileRestore.pm | 163 ++++++++++++++++++++++++++++++++
>>>   PVE/API2/Storage/Makefile       |   2 +-
>>>   PVE/API2/Storage/Status.pm      |   6 ++
>>>   3 files changed, 170 insertions(+), 1 deletion(-)
>>>   create mode 100644 PVE/API2/Storage/FileRestore.pm
>>>
>>> diff --git a/PVE/API2/Storage/FileRestore.pm b/PVE/API2/Storage/FileRestore.pm
>>> new file mode 100644
>>> index 0000000..a0b5e88
>>> --- /dev/null
>>> +++ b/PVE/API2/Storage/FileRestore.pm
>>> @@ -0,0 +1,163 @@
>>> +package PVE::API2::Storage::FileRestore;
>>> +
>>> +use strict;
>>> +use warnings;
>>> +
>>> +use PVE::JSONSchema qw(get_standard_option);
>>> +use PVE::PBSClient;
>>> +use PVE::Storage;
>>> +use PVE::Tools qw(extract_param);
>>> +
>>> +use PVE::RESTHandler;
>>> +use base qw(PVE::RESTHandler);
>>> +
>>> +__PACKAGE__->register_method ({
>>> +    name => 'list',
>>> +    path => 'list',
>>> +    method => 'GET',
>>> +    proxyto => 'node',
>>> +    permissions => {
>>> +	description => "Requires 'VM.Backup' permission on the VM being accessed, and " .
>>> +	    "'Datastore.Audit' on the datastore being restored from.",
>>> +	user => 'all', # checked explicitly
>>> +    },
>>> +    description => "List files and directories for single file restore under the given path.",
>>> +    protected => 1,
>>> +    parameters => {
>>> +	additionalProperties => 0,
>>> +	properties => {
>>> +	    node => get_standard_option('pve-node'),
>>> +	    storage => get_standard_option('pve-storage-id'),
>>> +	    snapshot => {
>>> +		description => "Backup snapshot identifier.",
>>> +		type => 'string',
>>> +	    },
>> 
>> why not use a volume id here (instead of storage + snapshot ID), and
>> then check inside whether it's a pbs backup? would allow easily
>> extending this to VMA backups as well later on, completion by our usual
>> volume ID helpers/selectors, ..
>> 
> 
> I did it this way mostly because we get the 'storage' parameter here 
> anyway - it's in the URL path, since this lives under 
> '/nodes/{node}/storage/{storage}'. Thus the only thing missing was the 
> snapshot.

hmm, yeah. there is precedent for using a volname/volid accepting 
parameter in PVE::API2::Storage::Content though (complete with helper to 
resolve the storage path parameter and the 'potentially contained in 
volid' storage parameter), so maybe that might be an option as well? 
might make the CLI easier, and potentially also API usage (no need to 
have the "split volume id into parts" logic client-side as well then).

> Is there a format for the "latter part of a volume-id"? If there is, 
> this would also just be a simple change later on, as it'd just replace 
> the 'snapshot' param.

no, although it might be nice to make one ;) the volume id format is 
specified at least as far as 'STORAGE_ID:VOLUME_NAME', but the volname 
itself is rather "freeform" (as in, '(.+)' with the details left up to 
the plugin :-/ - see PVE::Storage::Plugin::parse_volume_id).

> 
>>> +	    filepath => {
>>> +		description => 'base64-path to the directory or file being listed, or "/".',
>>> +		type => 'string',
>>> +	    },
>>> +	},
>>> +    },
>>> +    returns => {
>>> +	type => 'array',
>>> +	items => {
>>> +	    type => "object",
>>> +	    properties => {
>>> +		filepath => {
>>> +		    description => "base64 path of the current entry",
>>> +		    type => 'string',
>>> +		},
>>> +		type => {
>>> +		    description => "Entry type.",
>>> +		    type => 'string',
>>> +		},
>>> +		text => {
>>> +		    description => "Entry display text.",
>>> +		    type => 'string',
>>> +		},
>>> +		leaf => {
>>> +		    description => "If this entry is a leaf in the directory graph.",
>>> +		    type => 'any', # JSON::PP::Boolean gets passed through
>>> +		},
>>> +		size => {
>>> +		    description => "Entry file size.",
>>> +		    type => 'integer',
>>> +		    optional => 1,
>>> +		},
>>> +		mtime => {
>>> +		    description => "Entry last-modified time (unix timestamp).",
>>> +		    type => 'integer',
>>> +		    optional => 1,
>>> +		},
>>> +	    },
>>> +	},
>>> +    },
>>> +    code => sub {
>>> +	my ($param) = @_;
>>> +
>>> +	my $rpcenv = PVE::RPCEnvironment::get();
>>> +	my $user = $rpcenv->get_user();
>>> +
>>> +	my $path = extract_param($param, 'filepath') || "/";
>>> +	my $base64 = $path ne "/";
>>> +	my $snap = extract_param($param, 'snapshot');
>>> +	my $storeid = extract_param($param, 'storage');
>>> +	my $cfg = PVE::Storage::config();
>>> +	my $scfg = PVE::Storage::storage_config($cfg, $storeid);
>>> +
>>> +	my $volid = "$storeid:backup/$snap";
>>> +	my (undef, undef, $ownervm) = PVE::Storage::parse_volname($cfg, $volid);
>>> +	$rpcenv->check($user, "/storage/$storeid", ['Datastore.Audit']);
>>> +	$rpcenv->check($user, "/vms/$ownervm", ['VM.Backup']);
>> 
>> see comment above, this could then become
>> 'PVE::Storage::check_volume_access(..)
>>> +
>>> +	my $client = PVE::PBSClient->new($scfg, $storeid);
>>> +	my $ret = $client->file_restore_list($snap, $path, $base64);
>>> +
>>> +	return $ret;
>>> +    }});
>>> +
>>> +__PACKAGE__->register_method ({
>>> +    name => 'download',
>>> +    path => 'download',
>>> +    method => 'GET',
>>> +    proxyto => 'node',
>>> +    permissions => {
>>> +	description => "Requires 'VM.Backup' permission on the VM being accessed, and " .
>>> +	    "'Datastore.Audit' on the datastore being restored from.",
>>> +	user => 'all', # checked explicitly
>>> +    },
>>> +    description => "Extract a file or directory (as zip archive) from a PBS backup.",
>>> +    parameters => {
>>> +	additionalProperties => 0,
>>> +	properties => {
>>> +	    node => get_standard_option('pve-node'),
>>> +	    storage => get_standard_option('pve-storage-id'),
>>> +	    snapshot => {
>>> +		description => "Backup snapshot identifier.",
>>> +		type => 'string',
>>> +	    },
>> 
>> same here as above
>> 
>>> +	    filepath => {
>>> +		description => 'base64-path to the directory or file being listed.',
>>> +		type => 'string',
>>> +	    },
>>> +	},
>>> +    },
>>> +    returns => {
>>> +	type => 'any', # download
>>> +    },
>>> +    protected => 1,
>>> +    code => sub {
>>> +	my ($param) = @_;
>>> +
>>> +	my $rpcenv = PVE::RPCEnvironment::get();
>>> +	my $user = $rpcenv->get_user();
>>> +
>>> +	my $path = extract_param($param, 'filepath');
>>> +	my $snap = extract_param($param, 'snapshot');
>>> +	my $storeid = extract_param($param, 'storage');
>>> +	my $cfg = PVE::Storage::config();
>>> +	my $scfg = PVE::Storage::storage_config($cfg, $storeid);
>>> +
>>> +	my $volid = "$storeid:backup/$snap";
>>> +	my (undef, undef, $ownervm) = PVE::Storage::parse_volname($cfg, $volid);
>>> +	$rpcenv->check($user, "/storage/$storeid", ['Datastore.Audit']);
>>> +	$rpcenv->check($user, "/vms/$ownervm", ['VM.Backup']);
>> 
>> and here as well
>> 
>>> +
>>> +	my $client = PVE::PBSClient->new($scfg, $storeid);
>>> +	my $fifo = $client->file_restore_extract_prepare();
>>> +
>>> +	$rpcenv->fork_worker('pbs-download', undef, $user, sub {
>>> +	    $client->file_restore_extract($fifo, $snap, $path, 1);
>>> +	});
>>> +
>>> +	my $ret = {
>>> +	    download => {
>>> +		path => $fifo,
>>> +		stream => 1,
>>> +		'content-type' => 'application/octet-stream',
>>> +	    },
>>> +	};
>>> +	return $ret;
>>> +    }});
>>> +
>>> +1;
>>> diff --git a/PVE/API2/Storage/Makefile b/PVE/API2/Storage/Makefile
>>> index 690b437..1705080 100644
>>> --- a/PVE/API2/Storage/Makefile
>>> +++ b/PVE/API2/Storage/Makefile
>>> @@ -1,5 +1,5 @@
>>>   
>>> -SOURCES= Content.pm Status.pm Config.pm PruneBackups.pm Scan.pm
>>> +SOURCES= Content.pm Status.pm Config.pm PruneBackups.pm Scan.pm FileRestore.pm
>>>   
>>>   .PHONY: install
>>>   install:
>>> diff --git a/PVE/API2/Storage/Status.pm b/PVE/API2/Storage/Status.pm
>>> index d12643f..897b4a7 100644
>>> --- a/PVE/API2/Storage/Status.pm
>>> +++ b/PVE/API2/Storage/Status.pm
>>> @@ -12,6 +12,7 @@ use PVE::RRD;
>>>   use PVE::Storage;
>>>   use PVE::API2::Storage::Content;
>>>   use PVE::API2::Storage::PruneBackups;
>>> +use PVE::API2::Storage::FileRestore;
>>>   use PVE::RESTHandler;
>>>   use PVE::RPCEnvironment;
>>>   use PVE::JSONSchema qw(get_standard_option);
>>> @@ -32,6 +33,11 @@ __PACKAGE__->register_method ({
>>>       path => '{storage}/content',
>>>   });
>>>   
>>> +__PACKAGE__->register_method ({
>>> +   subclass => "PVE::API2::Storage::FileRestore",
>>> +   path => '{storage}/file-restore',
>>> +});
>>> +
>>>   __PACKAGE__->register_method ({
>>>       name => 'index',
>>>       path => '',
>>> -- 
>>> 2.20.1
>>>
>>>
>>>
>>> _______________________________________________
>>> pve-devel mailing list
>>> pve-devel@lists.proxmox.com
>>> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>>>
>>>
>>>
>> 
>> 
>> _______________________________________________
>> pve-devel mailing list
>> pve-devel@lists.proxmox.com
>> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>> 
>> 
> 




  reply	other threads:[~2021-04-22  6:20 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-21 11:15 [pve-devel] [PATCH 00/10] Single-file-restore GUI for PBS snapshots Stefan Reiter
2021-04-21 11:15 ` [pve-devel] [PATCH RESEND common 01/10] JSONSchema: don't cycle-check 'download' responses Stefan Reiter
2021-04-21 15:37   ` [pve-devel] applied: " Thomas Lamprecht
2021-04-21 11:15 ` [pve-devel] [PATCH common 02/10] PBSClient: allow running other binaries Stefan Reiter
2021-04-21 14:29   ` Thomas Lamprecht
2021-04-21 14:38     ` Stefan Reiter
2021-04-21 14:50       ` Thomas Lamprecht
2021-04-21 15:37   ` [pve-devel] applied: " Thomas Lamprecht
2021-04-21 11:15 ` [pve-devel] [PATCH common 03/10] PBSClient: add file_restore_list command Stefan Reiter
     [not found]   ` <<20210421111539.29261-4-s.reiter@proxmox.com>
2021-04-21 13:19     ` Fabian Grünbichler
2021-04-21 11:15 ` [pve-devel] [PATCH common 04/10] PBSClient: allow different command execution callback Stefan Reiter
     [not found]   ` <<20210421111539.29261-5-s.reiter@proxmox.com>
2021-04-21 13:19     ` Fabian Grünbichler
2021-04-21 13:39       ` Stefan Reiter
2021-04-21 11:15 ` [pve-devel] [PATCH common 05/10] PBSClient: add file_restore_extract function Stefan Reiter
2021-04-21 11:15 ` [pve-devel] [PATCH RESEND http-server 06/10] allow 'download' to be passed from API handler Stefan Reiter
2021-04-21 15:43   ` [pve-devel] applied: " Thomas Lamprecht
2021-04-21 11:15 ` [pve-devel] [PATCH http-server 07/10] support streaming data form fh to client Stefan Reiter
     [not found]   ` <<20210421111539.29261-8-s.reiter@proxmox.com>
2021-04-21 13:25     ` Fabian Grünbichler
2021-04-21 11:15 ` [pve-devel] [PATCH http-server 08/10] allow stream download from path and over pvedaemon-proxy Stefan Reiter
2021-04-21 11:15 ` [pve-devel] [PATCH storage 09/10] add FileRestore API for PBS Stefan Reiter
     [not found]   ` <<20210421111539.29261-10-s.reiter@proxmox.com>
2021-04-21 13:26     ` Fabian Grünbichler
2021-04-21 13:38       ` Stefan Reiter
2021-04-22  6:19         ` Fabian Grünbichler [this message]
2021-04-21 11:15 ` [pve-devel] [PATCH manager 10/10] backupview: add file restore button Stefan Reiter
2021-04-22 10:33 ` [pve-devel] [PATCH 00/10] Single-file-restore GUI for PBS snapshots Dominic Jäger
2021-04-22 12:12   ` Stefan Reiter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1619071785.ey2usqrbcy.astroid@nora.none \
    --to=f.gruenbichler@proxmox.com \
    --cc=pve-devel@lists.proxmox.com \
    --cc=s.reiter@proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal