all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: "Max Carrara" <m.carrara@proxmox.com>
To: "Proxmox VE development discussion" <pve-devel@lists.proxmox.com>
Subject: Re: [pve-devel] [PATCH v1 pve-storage 3/8] pluginbase: document SectionConfig methods
Date: Wed, 02 Apr 2025 18:31:42 +0200	[thread overview]
Message-ID: <D8WAOY6HIZYT.15MN08DDZ05RL@proxmox.com> (raw)
In-Reply-To: <1743423551.a0519q1x3m.astroid@yuna.none>

On Mon Mar 31, 2025 at 5:13 PM CEST, Fabian Grünbichler wrote:
> On March 26, 2025 3:20 pm, Max Carrara wrote:
> > This commit adds docstrings for the relevant PVE::SectionConfig
> > methods in the context of the storage plugin API.
> > 
> > Signed-off-by: Max Carrara <m.carrara@proxmox.com>
> > ---
> >  src/PVE/Storage/PluginBase.pm | 194 +++++++++++++++++++++++++++++++++-
> >  1 file changed, 192 insertions(+), 2 deletions(-)
> > 
> > diff --git a/src/PVE/Storage/PluginBase.pm b/src/PVE/Storage/PluginBase.pm
> > index 16977f3..5f7e6fd 100644
> > --- a/src/PVE/Storage/PluginBase.pm
> > +++ b/src/PVE/Storage/PluginBase.pm
> > @@ -88,7 +88,7 @@ package PVE::Storage::PluginBase;
> >  use strict;
> >  use warnings;
> >  
> > -use Carp qw(croak);
> > +use Carp qw(croak confess);
> >  
> >  use parent qw(PVE::SectionConfig);
> >  
> > @@ -100,27 +100,217 @@ use parent qw(PVE::SectionConfig);
> >  
> >  =cut
> >  
> > +=head3 $plugin->type()
> > +
> > +B<REQUIRED:> Must be implemented in every storage plugin.

Upfront note: Unless I otherwise comment something, I agree with you.
Just sparing myself from writing and you from reading too many ACKs :P

>
> I am not sure whether we should do
>
> s/implemented in/implemented by
>
> for this whole thing and SectionConfig, but I won't note it for every
> instance ;)
>
> > +
> > +This should return a string with which the plugin can be uniquely identified.
>
> a string which uniquely identifies the plugin.
>
> > +Any string is acceptable, as long as it's descriptive and you're sure it won't
> > +conflict with another plugin. In the cases of built-in plugins, you will often
> > +find the filesystem name or something similar being used.
>
> I'd replace that with something like:
>
> Commonly, the name of the storage technology or filesystem supported by
> the plugin is used. If it is necessary to differentiate multiple
> plugins for the same storage technology/filesystem, add a suffix
> denoting the supported variant or feature set.
>
> > +
> > +See C<L<PVE::SectionConfig/type>> for more information.
> > +
> > +=cut
> > +
> >  sub type {
> >      croak "implement me in sub-class\n";
> >  }
> >  
> > +=head3 $plugin->properties()
> > +
> > +B<OPTIONAL:> May be implemented in a storage plugin.
> > +
> > +This method should be implemented if there are additional properties to be used
> > +by your plugin. Since properties are global and may be reused across plugins,
>
> s/used/registered
>
> IMHO that conveys better what the difference between properties and
> options are..
>
> "global and may be reused across plugins" is kinda superfluous, maybe
>
> "Since properties share a global namespace across all plugins"?
>
> > +the names of properties must not collide with one another.
>
> each property can only be registered once by a single plugin, but used
> as an option by many.
>
> > +
> > +When implementing a third-party plugin, it is recommended to prefix properties
> > +with some kind of identifier, like so:
>
> Third-party plugins should therefore prefix any properties they register
> with their plugin type, for example:
>
> > +
> > +    sub properties {
> > +	return {
> > +	    'example-storage-address' => {
> > +		description => 'Host address of the ExampleStorage to connect to.',
> > +		type => 'string',
> > +	    },
> > +	    'example-storage-pool' => {
> > +		description => 'Name of the ExampleStorage pool to use.',
> > +		type => 'string',
> > +	    },
> > +	    # [...]
> > +	};
> > +    }
> > +
> > +However, it is encouraged to reuse properties of inbuilt plugins whenever
> > +possible. There are a few provided properties that are regarded as I<sensitive>
> > +and will be treated differently in order to not expose them or write them as
> > +plain text into configuration files. One such property fit for external use is
> > +C<password>, which you can use to provide a password, API secret, or similar.
>
> If possible, generic properties registered by built-in plugins should be
> reused.
>
> (inbuilt is a very weird, very British word ;))
>
> the rest of that is kinda misplaced here and should be its own section
> somewhere (it affects options just as much as properties). we should
> probably allow registering sensitive properties for plugins?

Yes, we should! And Fiona's already on it 🎉 [0]

[0]: https://lore.proxmox.com/pve-devel/20250321134852.103871-11-f.ebner@proxmox.com/

>
> > +
> > +See C<L<PVE::SectionConfig/properties>> for more information.
> > +
> > +=cut
> > +
> >  sub properties {
> >      my ($class) = @_;
> >      return $class->SUPER::properties();
> >  }
> >  
> > +=head3 $plugin->options()
> > +
> > +B<REQUIRED:> Must be implemented in every storage plugin.
> > +
> > +This method returns a hash of the properties used by the plugin. Because
> > +properties are shared among plugins, it is recommended to reuse any existing
> > +ones of inbuilt plugins and only define custom properties via
> > +C<L<< properties()|/"$plugin->properties()" >>> if necessary.
>
> Everything but the first sentence can be a reference to the properties
> part above..
>
> > +
> > +The properties a plugin uses are then declared as follows:
>
> or just, "For example:" ? ;)
>
> > +
> > +    sub options {
> > +	return {
> > +	    nodes => { optional => 1 },
> > +	    content => { optional => 1 },
> > +	    disable => { optional => 1 },
> > +	    'example-storage-pool' => { fixed => 1 },
> > +	    'example-storage-address' => { fixed => 1 },
> > +	    password => { optional => 1 },
> > +	};
> > +    }
> > +
> > +C<optional> properties are not required to be set. It is recommended to set
>
> s/set/make or "declare"?
>
> > +most properties optional by default, unless it I<really> is required to always
> > +exist.
>
> s/it/they
> s/exist/be set
>
> > +
> > +C<fixed> properties can only be set when creating a new storage via the plugin
> > +and cannot be changed afterwards.
>
> s/creating a new storage/adding a new storage config entry/ ? a bit more
> precise to differentiate it from actually "creating a storage" as in
> formatting a disk/..
>
> I am not sure what "via the plugin" is supposed to mean there, I think
> it can just be dropped.
>
> > +
> > +See C<L<PVE::SectionConfig/options>> for more information.
> > +
> > +=cut
> > +
> >  sub options {
> >      my ($class) = @_;
> >      return $class->SUPER::options();
> >  }
> >  
> > +=head3 $plugin->plugindata()
> > +
> > +B<REQUIRED:> Must be implemented in every storage plugin.
> > +
> > +This method returns a hash that specifies additional capabilities of the storage
> > +plugin, such as what kinds of data may be stored on it or what VM disk formats
>
> s/data/content or s/data/volumes
>
> > +the storage supports. Additionally, defaults may also be set. This is done
> > +through the C<content> and C<format> keys.
>
> but how about re-organizing it a bit?
>
> This method returns a hash declaring which content types and image
> formats this plugin (or the underlying storage) supports.
>
> and then describe each key?
>
> > +
> > +The C<content> key is used to declare B<supported content types> and their
> > +defaults, while the C<format> key declares B<supported disk formats> and the
> > +default disk format of the storage:
>
> "and their defaults" sounds weird.
>
> The 'content' key stores a list containing two hashes. The first list
> element is a hash declaring which content types are supported by the
> plugin. The second list element is a hash declaring which content types
> are used by default if no explicit 'content' option is set on a plugin
> instance.
>
> and maybe link somewhere else for a description of the content type
> values, so that there is a single place that various parts that need it
> can link to?
>
> and then
>
> The 'format' key stores a list containing two hashes. The first list
> element is a hash declaring which image formats are supported by the
> storage plugin. The second list element is the default image format that
> should be used for images on the storage if non is explicitly provided.
>
> > +
> > +    sub plugindata {
> > +	return {
> > +	    content => [
> > +		# possible content types
> > +		{
> > +		    images => 1,   # disk images
> > +		    rootdir => 1,  # container root directories
> > +		    vztmpl => 1,   # container templates
> > +		    iso => 1,      # iso images
> > +		    backup => 1,   # vzdump backup files
> > +		    snippets => 1, # snippets
> > +		    import => 1,   # imports; see explanation below
> > +		    none => 1,     # no content; see explanation below
> > +		},
> > +		# defaults if 'content' isn't explicitly set
> > +		{
> > +		    images => 1,   # store disk images by default
> > +		    rootdir => 1   # store containers by default
> > +		    # possible to add more or have no defaults
> > +		}
> > +	    ],
> > +	    format => [
> > +		# possible disk formats
> > +		{
> > +		    raw => 1,   # raw disk image
> > +		    qcow2 => 1, # QEMU image format
> > +		    vmdk => 1,  # VMware image format
> > +		    subvol => 1 # subvolumes; see explanation below
> > +		},
> > +		"qcow2" # default if 'format' isn't explicitly set
> > +	    ]
> > +	    # [...]
> > +	};
> > +    }
> > +
> > +While the example above depicts a rather capable storage, the following
> > +shows a simpler storage that can only be used for VM disks:
>
> raw-formatted VM disks
>
> > +
> > +    sub plugindata {
> > +	return {
> > +	    content => [
> > +		{ images => 1 },
> > +	    ],
> > +	    format => [
> > +		{ raw => 1 },
> > +		"raw",
> > +	    ]
> > +	};
> > +    }
> > +
> > +Which content types and formats are supported depends on the underlying storage
> > +implementation.
> > +
> > +B<Regarding C<import>:> The C<import> content type is used internally to
> > +interface with virtual guests of foreign sources or formats. The corresponding
> > +functionality has not yet been published to the public parts of the storage
> > +API. Third-party plugins therefore should not declare this content type.
>
> this should live somewhere where content types are described
>
> > +
> > +B<Regarding C<none>:> The C<none> content type denotes the I<absence> of other
> > +types of content, i.e. this content type may only be set on a storage if no
> > +other content type is set. This is used internally for storages that support
> > +adding another storage "on top" of them; at the moment, this makes it possible
> > +to set up an LVM (thin) pool on top of an iSCSI LUN. The corresponding
> > +functionality has not yet been published to the public parts of the storage
> > +API. Third-party plugins therefore should not declare this content type.
>
> same
>
> > +
> > +B<Regarding C<subvol>:> The C<subvol> format is used internally to allow the
> > +root directories of containers to use ZFS subvolumes (also known as
> > +I<ZFS datasets>, not to be confused with I<ZVOLs>). Third-party plugins should
> > +not declare this format type.
>
> this is incomplete, but same.
>
> > +
> > +There is one more key, C<select_existing>, which is used internally for
> > +ISCSI-related GUI functionality. Third-party plugins should not declare this
> > +key.
>
> this is okay here :)
>
> > +
> > +=cut
> > +
> >  sub plugindata {
> >      my ($class) = @_;
> >      return $class->SUPER::plugindata();
> >  }
> >  
> > +=head3 $plugin->private()
> > +
> > +B<WARNING:> This method is provided by C<L<PVE::Storage::Plugin>> and
> > +must be used as-is. It is merely documented here for informal purposes
> > +and B<must not be overridden.>
> > +
> > +Returns a hash containing the tracked plugin metadata, most notably the
> > +C<propertyList>, which contains all known properties of all plugins.
> > +
> > +C<L<PVE::Storage::Plugin>> uses this to predefine a lot of useful properties
> > +that are relevant for all plugins. Core functionality such as defining
> > +whether a storage is shared, which nodes may use it, whether a storage
> > +is enabled or not, etc. are implemented via these properties.
>
> this is not true and sounds like it is very interesting to look at/mess
> with ;) in reality, it is part of SectionConfig machinery, so just say
> that and that it must not be overridden and be done with it?
>
> if PluginBase becomes the real base plugin then it and some other
> helpers would need to move here anyway..
>
> > +
> > +See C<L<PVE::SectionConfig/private>> for more information.
> > +
> > +=cut
> > +
> >  sub private {
> > -    croak "implement me in sub-class\n";
> > +    confess "private() is provided by PVE::Storage::Plugin and must not be overridden";
> >  }
> >  
> >  =head2 GENERAL
> > -- 
> > 2.39.5
> > 
> > 
> > 
> > _______________________________________________
> > 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



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

  reply	other threads:[~2025-04-02 16:32 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-26 14:20 [pve-devel] [PATCH v1 pve-storage 0/8] Base Module + Documentation for PVE::Storage::Plugin API Max Carrara
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 1/8] pluginbase: introduce PVE::Storage::PluginBase with doc scaffold Max Carrara
2025-03-31 15:13   ` Fabian Grünbichler
2025-04-02 16:31     ` Max Carrara
2025-04-03  7:12       ` Fabian Grünbichler
2025-04-03 14:05         ` Max Carrara
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 2/8] pluginbase: add high-level plugin API description Max Carrara
2025-03-31 15:13   ` Fabian Grünbichler
2025-04-02 16:31     ` Max Carrara
2025-04-03  7:12       ` Fabian Grünbichler
2025-04-03 14:05         ` Max Carrara
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 3/8] pluginbase: document SectionConfig methods Max Carrara
2025-03-31 15:13   ` Fabian Grünbichler
2025-04-02 16:31     ` Max Carrara [this message]
2025-04-11 13:49     ` Wolfgang Bumiller
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 4/8] pluginbase: document general plugin methods Max Carrara
2025-03-28 12:50   ` Maximiliano Sandoval
2025-03-31 15:12   ` Fabian Grünbichler
2025-04-02 16:31     ` Max Carrara
2025-04-11 14:04       ` Wolfgang Bumiller
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 5/8] pluginbase: document hooks Max Carrara
2025-03-28 13:07   ` Maximiliano Sandoval
2025-03-31 15:12   ` Fabian Grünbichler
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 6/8] pluginbase: document image operation methods Max Carrara
2025-03-31 15:12   ` Fabian Grünbichler
2025-04-02 16:32     ` Max Carrara
2025-04-03  7:23       ` Fabian Grünbichler
2025-04-03 14:05         ` Max Carrara
2025-04-11 14:08   ` Wolfgang Bumiller
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 7/8] pluginbase: document volume operations Max Carrara
2025-03-31 15:12   ` Fabian Grünbichler
2025-04-02 16:32     ` Max Carrara
2025-04-14  8:24       ` Wolfgang Bumiller
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 8/8] pluginbase: document import and export methods Max Carrara
2025-04-01  8:40   ` Fabian Grünbichler
2025-04-01  9:40     ` Fiona Ebner
2025-04-14 14:35       ` Wolfgang Bumiller
2025-04-02 16:32     ` Max Carrara
2025-04-11 13:27 ` [pve-devel] [PATCH v1 pve-storage 0/8] Base Module + Documentation for PVE::Storage::Plugin API Wolfgang Bumiller

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=D8WAOY6HIZYT.15MN08DDZ05RL@proxmox.com \
    --to=m.carrara@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal