public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: "Max Carrara" <m.carrara@proxmox.com>
To: "Fiona Ebner" <f.ebner@proxmox.com>,
	"Proxmox VE development discussion" <pve-devel@lists.proxmox.com>
Subject: Re: [pve-devel] [RFC storage 10/23] plugin: introduce new_backup_provider() method
Date: Fri, 26 Jul 2024 14:02:26 +0200	[thread overview]
Message-ID: <D2ZGEL5EHGPF.34PJ6J89RS0YT@proxmox.com> (raw)
In-Reply-To: <e509ff38-11cb-431c-8ead-ed10a4ef747b@proxmox.com>

On Fri Jul 26, 2024 at 11:52 AM CEST, Fiona Ebner wrote:
> Am 25.07.24 um 17:32 schrieb Max Carrara:
> > On Thu Jul 25, 2024 at 3:11 PM CEST, Fiona Ebner wrote:
> >> Am 25.07.24 um 11:48 schrieb Max Carrara:
> >>>     The same goes for backup provider plugins - IMO namespacing them
> >>>     like e.g. `PVE::Backup::Provider::Plugin::Foo` where `Foo` is a
> >>>     (concrete) plugin.
> >>>
> >>
> >> The BackupProvider namespace is already intended for the plugins, adding
> >> an extra level with "Plugin" would just bloat the module names,
> >> especially if we decide to go the same route as for storage plugins and
> >> have a "Custom" sub-namespace.
> > 
> > I understand what you mean, yeah. Would perhaps something like
> > `PVE::BackupProvider::Plugin::*` be better?
> > 
> > The reason why I'm suggesting this is because in `PVE::Storage::*`,
> > every plugin lives alongside `Plugin.pm`, even though the extra
> > directory wouldn't really hurt IMO. E.g. `PVE::Storage::DirPlugin` would
> > then be `PVE::Storage::Plugin::Dir`.
> > 
>
> I think it's fine to live alongside the base plugin (I'd prefer
> Plugin::Base if going for a dedicated directory). I agree, if we ever
> want to add something other than plugins to the top namespace, it is
> much nicer to have the dedicated directory. And it is made more explicit
> that things in there are plugins (and not having to name each one
> FooPlugin). However, I still feel like
> PVE::BackupProvider::Plugin::Custom::Bar is rather lengthy (should we go
> with the Custom directory again), but I'm not really opposed to doing it
> like this.
>
> >>
> >>> The above two methods - `backup_nbd` and `backup_directory` - is there
> >>> perhaps a way to merge them? I'm not sure if what I'm having in mind
> >>> here is actually feasible, but what I mean is "making the method
> >>> agnostic to the type of backup". As in, perhaps pass a hash that
> >>> contains a `type` key for the type of backup being made, and instead of
> >>> having long method signatures, include the remaining parameters as the
> >>> remaining keys. For example:
> >>>
> >>> {
> >>>     'type' => 'lxc-dir',  # type names are just examples here
> >>>     'directory' => '/foo/bar/baz',
> >>>     'bandwidth_limit' => 42,
> >>>     ...
> >>> }
> >>>
> >>> {
> >>>     'type' => 'vm-nbd',
> >>>     'device_name' => '...',
> >>>     'nbd_path' => '...',
> >>>     ...
> >>> }
> >>>
> >>> You get the point :P
> >>>
> >>> IMO it would make it easier to extend later, and also make it more
> >>> straightforward to introduce new parameters / deprecate old ones, while
> >>> the method signature stays stable otherwise.
> >>>
> >>> The same goes for the different cleanup methods further down below;
> >>> instead of having a separate method for each "type of cleanup being
> >>> performed", let the implementor handle it according to the data the
> >>> method receives.
> >>>
> >>> IMHO I think it's best to be completely agnostic over VM / LXC backups
> >>> (and their specific types) wherever possible and let the data describe
> >>> what's going on instead.
> >>>
> >>
> >> The point about extensibility is a good one. The API wouldn't need to
> >> change even if we implement new mechanisms. But thinking about it some
> >> more, is there anything really gained? Because we will not force plugins
> >> to implement the methods for new mechanisms of course, they can just
> >> continue supporting what they support. Each mechanism will have its own
> >> specific set of parameters, so throwing everything into a catch-all
> >> method and hash might make it too generic.
> > 
> > The main point is indeed extensibility, but it also makes maintaining
> > the API a bit easier. Should we (in the future) decide to add or remove
> > any parameters, we don't need to touch the signature - and in turn, we
> > don't need to tediously `grep` for every call site to ensure that
> > they're updated accordingly.
> > 
> > With hashes one could instead always just check if the required
> > arguments have been provided.
> > 
>
> I'm all for going with a similar API age + version mechanism like for
> the storage plugins, so removing parameters should not be done except
> for major releases and adding will be backwards-compatible.
>
> I don't quite get your point about not needing to update the call sites.
> If you change the structure of the passed-in hash you still need to do that.

Pardon me, I was a bit imprecise there. You're completely right that the
passed hash has to be changed as well, of course.

What I meant in particular was that because the signature (most likely)
won't change, we won't have to take special care to update the
individual arguments that are passed to a method when e.g. a parameter
is deprecated (or removed) or added.

For example, optional arguments are often just left out (because that's
possible in Perl), so if we introduced another parameter ...

* after the optional one, we'd have to pass something like `0` or
  `undef` for the optional one first before passing the new one:

    # before
    $plugin->foo($first, $second);

    # after
    $plugin->foo($first, $second, undef, $new); 

* before the optional one, we'd have to make sure the order of arguments
  is correct:

    # before
    $plugin->foo($first, $second, 1);

    # after
    $plugin->foo($first, $second, $new, 1);

If we were to use a hash representing the parameters instead, the cases
would look like this respectively:

    $plugin->foo({ first => $first, second => $second, new => $new });

    $plugin->foo({ first => $first, second => $second, optional => 1, new = $new });

More examples of that pattern would be `PVE::Tools::run_command` and
`PVE::RADOS::mon_command`.

These changes can (and IMO should) still be guarded by an API age +
version mechanism, it's just that the *surrounding maintenance work*
becomes easier IMO, even if the initial cost for us and for implementors
is a bit higher.

Of course, this is all a suggestion and I really don't want to seem like
I'm telling you what to do here! If you decide not to have a parameter
hash etc. then that's also completely fine by me, of course. :)

>
> I do see some benefit in not needing to add new methods for every
> mechanism, and there could also be a single backup_hook() method instead
> of a dedicated one for each phase while we're at it. But changes to the
> passed-in hashes will still fall under the same restrictions like
> changing a signature API-wise, so users will be informed via API age +
> version.

That's fair, yeah! I agree with you here as well - I think *not* having
an API age + version would be rather detrimental.

>
> >>
> >> Or think about the documentation for the single backup method: it would
> >> become super lengthy and describe all backup mechanisms, while a plugin
> >> most likely only cares about a single one and would have an easier time
> >> with a method that captures that mechanism's parameters explicitly.
> >> Won't the end result be making the implementors life slightly harder,
> >> because it first needs to extract the parameters for the specific mechanism?
> > 
> > Yes, I agree - this does create a bit of a double-edged sword -
> > implementors are responsible for handling the hash correctly; of course
> > they could lob it all into one generic method and call it a day, or they
> > could introduce a separate helper function for each `type`, for example.
> > 
>
> I would like to keep methods for containers and VMs separate in any
> case, because they require different things and I don't see any benefit
> in merging them. For containers, you backup the whole filesystem
> structure in one go, for VMs you get each disk separately. There are
> certain parameters that are better fixed, i.e. are passed for every
> mechanism, e.g. info about idmap for containers, drive ID for VMs. So
> having them in the signature rather then inside a hash is better and
> merging won't work if you have different fixed ones. But I'm fine with
> having a mechanism-agnostic signature, one for VMs and one for containers.

Okay, that also seems reasonable to me :)

>
> > The up- and downside of a generic method would be that it's up to the
> > implementor on how to deal with it.
> > 
> > At the same time, it would allow their plugin to handle different API
> > versions a bit easier as well, because the method signature wouldn't
> > change - only the data changes. If they wanted their plugin to support
> > multiple API versions all at once, they could certainly do it that way
> > and aren't restricted by a fixed set of parameters.
> > 
> > Now that I've given it some more thought, there are quite a bunch of ups
> > and downs, though I'm personally still in favour of the more generic
> > method, as it would reduce maintenance cost in the long run, IMO for
> > both us and implementors. The initial cost of adding the parameter
> > extraction / handling would be higher, I agree, but I feel like it's
> > more worth in the long run.
> > 
> > Also, IMO lengthy documentation is better than having a rigid API ;P
> > 
>
> I do prefer a rigid API. After all you don't want to make life for
> implementers hard by changing too much between versions. And it can
> still be a rigid API, even if there's a mechanism-agnostic signature,
> just keep the data backwards-compatible.

I also agree; I don't have anything to add, you hit the nail on the
head.

Also, thanks for going through this discussion here with me - even if
you choose to not incorporate my suggestions, I'm glad we have these
little exchanges, because they periodically update my perspective(s) on
Perl code as well :P



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel


  reply	other threads:[~2024-07-26 12:03 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-23  9:56 [pve-devel] [RFC qemu/storage/qemu-server/container/manager 00/23] backup provider API Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [PATCH qemu 01/23] block/reqlist: allow adding overlapping requests Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [PATCH qemu 02/23] PVE backup: fixup error handling for fleecing Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [PATCH qemu 03/23] PVE backup: factor out setting up snapshot access " Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [PATCH qemu 04/23] PVE backup: save device name in device info structure Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [PATCH qemu 05/23] PVE backup: include device name in error when setting up snapshot access fails Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC qemu 06/23] PVE backup: add target ID in backup state Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC qemu 07/23] PVE backup: get device info: allow caller to specify filter for which devices use fleecing Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC qemu 08/23] PVE backup: implement backup access setup and teardown API for external providers Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC qemu 09/23] PVE backup: implement bitmap support for external backup access Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC storage 10/23] plugin: introduce new_backup_provider() method Fiona Ebner
2024-07-25  9:48   ` Max Carrara
2024-07-25 13:11     ` Fiona Ebner
2024-07-25 13:25       ` Fiona Ebner
2024-07-25 15:32       ` Max Carrara
2024-07-26  9:52         ` Fiona Ebner
2024-07-26 12:02           ` Max Carrara [this message]
2024-07-26 12:45             ` Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC storage 11/23] extract backup config: delegate to backup provider if there is one Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [POC storage 12/23] add backup provider example Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [PATCH qemu-server 13/23] move nbd_stop helper to QMPHelpers module Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [PATCH qemu-server 14/23] backup: move cleanup of fleecing images to cleanup method Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [PATCH qemu-server 15/23] backup: cleanup: check if VM is running before issuing QMP commands Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC qemu-server 16/23] backup: allow adding fleecing images also for EFI and TPM Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC qemu-server 17/23] backup: implement backup for external providers Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [PATCH qemu-server 18/23] restore: die early when there is no size for a device Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC qemu-server 19/23] backup: implement restore for external providers Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC container 20/23] backup: implement backup " Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC container 21/23] backup: implement restore " Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [PATCH manager 22/23] ui: backup: also check for backup subtype to classify archive Fiona Ebner
2024-07-23  9:56 ` [pve-devel] [RFC manager 23/23] backup: implement backup for external providers Fiona Ebner

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=D2ZGEL5EHGPF.34PJ6J89RS0YT@proxmox.com \
    --to=m.carrara@proxmox.com \
    --cc=f.ebner@proxmox.com \
    --cc=pve-devel@lists.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