[pve-devel] [PATCH v1 pve-storage 3/8] pluginbase: document SectionConfig methods

Max Carrara m.carrara at proxmox.com
Wed Mar 26 15:20:54 CET 2025


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 at 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.
+
+This should return a string with which the plugin can be uniquely identified.
+
+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.
+
+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,
+the names of properties must not collide with one another.
+
+When implementing a third-party plugin, it is recommended to prefix properties
+with some kind of identifier, like so:
+
+    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.
+
+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.
+
+The properties a plugin uses are then declared as follows:
+
+    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
+most properties optional by default, unless it I<really> is required to always
+exist.
+
+C<fixed> properties can only be set when creating a new storage via the plugin
+and cannot be changed afterwards.
+
+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
+the storage supports. Additionally, defaults may also be set. This is done
+through the C<content> and C<format> keys.
+
+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:
+
+    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:
+
+    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.
+
+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.
+
+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.
+
+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.
+
+=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.
+
+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





More information about the pve-devel mailing list