public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: "Max R. Carrara" <m.carrara@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [RFC pve-storage master v2 2/10] api: plugins/storage/plugin: include schema in plugin metadata
Date: Fri, 21 Nov 2025 17:58:31 +0100	[thread overview]
Message-ID: <20251121165858.818307-3-m.carrara@proxmox.com> (raw)
In-Reply-To: <20251121165858.818307-1-m.carrara@proxmox.com>

Return a simple schema describing the plugin as part of its metadata.

This schema is simply a hash consisting of a given plugin's
properties' schemas. Each property schema is obtained by calling the
`get_property_schema()` method of `PVE::SectionConfig` (which
`PVE::Storage::Plugin` inherits) for each property that a given plugin
uses in its `options()`. Additionally, each plugin's `options()` are
also taken into account, and the schemas are memoized.

This means that each returned schema is completely derived from the
given plugin's section config—the (globally) available properties and
the plugin's `options()`. At the same time, this should be adaptable
enough to include extra hints, such as whether a property is sensitive
or not, for example.

Deriving a schema for each plugin like this is more preferable over
exposing `createSchema()` and `updateSchema()` of
`PVE::Storage::Plugin` directly. In particular, these two schemas come
with some drawbacks when it comes to describing an *individual*
plugin's data:

- Neither schema contains any information on which properties are used
  by which plugins.

- It is not possible to determine whether a property is actually
  optional (or not) for a given plugin. If one plugin declares a
  property as optional somewhere, the property will be optional in the
  schema in most cases, despite being non-optional for other plugins.
  (This is generally true; skipping over a bunch of SectionConfig
  implementation details here for the sake of brevity).

- The same is true even more so for fixed properties. While the
  `updateSchema()` will oftentimes *not* contain fixed properties,
  meaning that you can compare it with `createSchema()` and figure out
  which properties *may* be fixed, this only holds if the property is
  fixed in *every* plugin's `options()`. As soon as a plugin declares
  a usually fixed property as non-fixed, the property is included in
  the `updateSchema()`.

- Even when switching to property isolation for
  `PVE::Storage::Plugin`, which properties are fixed / optional for
  individual plugins is still not consistently determinable for the
  previous two reasons.

This means that in addition to exposing `createSchema()` and
`updateSchema()`, we would also have to expose the `options()` of each
plugin, and then stitch all of that information together again just to
obtain the hash that the `get_schema_for_plugin()` helper being added
here returns.

Additionally, `get_property_schema()` takes property isolation into
account. More precisely, if one were to enable property isolation and
copy-paste the formerly global property definitions into the
`properties()` of each plugin where needed, the returned schema would
stay the same.

Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
---
 src/PVE/API2/Plugins/Storage/Plugin.pm | 34 ++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/src/PVE/API2/Plugins/Storage/Plugin.pm b/src/PVE/API2/Plugins/Storage/Plugin.pm
index fd0f734..573d3e4 100644
--- a/src/PVE/API2/Plugins/Storage/Plugin.pm
+++ b/src/PVE/API2/Plugins/Storage/Plugin.pm
@@ -22,6 +22,10 @@ my $PLUGIN_METADATA_SCHEMA = {
             type => 'string',
             optional => 0,
         },
+        schema => {
+            type => 'object',
+            optional => 0,
+        },
         type => {
             type => 'string',
             optional => 0,
@@ -30,6 +34,34 @@ my $PLUGIN_METADATA_SCHEMA = {
     },
 };
 
+my $PLUGIN_SCHEMAS = {};
+
+my sub get_schema_for_plugin : prototype($) ($plugin) {
+    my $type = $plugin->type();
+
+    return $PLUGIN_SCHEMAS->{$type} if defined($PLUGIN_SCHEMAS->{$type});
+
+    my $options = $plugin->options();
+
+    my $schema = {};
+    $PLUGIN_SCHEMAS->{$type} = $schema;
+
+    for my $option (keys $options->%*) {
+        my $prop_schema = PVE::RESTHandler::api_dump_remove_refs(
+            PVE::Storage::Plugin->get_property_schema($type, $option));
+
+        # shallow copy
+        my $property = { $prop_schema->%* };
+        $schema->{$option} = $property;
+
+        for my $opt_key (keys $options->{$option}->%*) {
+            $property->{$opt_key} = $options->{$option}->{$opt_key};
+        }
+    }
+
+    return $schema;
+}
+
 # plugins/storage/plugin
 
 __PACKAGE__->register_method({
@@ -56,6 +88,7 @@ __PACKAGE__->register_method({
 
             my $item = {
                 module => $plugin,
+                schema => get_schema_for_plugin($plugin),
                 type => $type,
             };
 
@@ -95,6 +128,7 @@ __PACKAGE__->register_method({
 
         my $result = {
             module => $plugin,
+            schema => get_schema_for_plugin($plugin),
             type => $param_type,
         };
 
-- 
2.47.3



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

  parent reply	other threads:[~2025-11-21 16:59 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-21 16:58 [pve-devel] [RFC pve-storage/proxmox-widget-toolkit/pve-manager master v2 00/10] GUI Support for Custom Storage Plugins Max R. Carrara
2025-11-21 16:58 ` [pve-devel] [RFC pve-storage master v2 1/10] api: plugins/storage: add initial routes and endpoints Max R. Carrara
2025-11-21 16:58 ` Max R. Carrara [this message]
2025-11-21 16:58 ` [pve-devel] [RFC pve-storage master v2 3/10] api: plugins/storage/plugin: mark sensitive properties in schema Max R. Carrara
2025-11-21 16:58 ` [pve-devel] [RFC pve-storage master v2 4/10] api: plugins/storage/plugin: factor plugin metadata code into helper Max R. Carrara
2025-11-21 16:58 ` [pve-devel] [RFC pve-storage master v2 5/10] api: plugins/storage/plugin: add plugins' 'content' to their metadata Max R. Carrara
2025-11-21 16:58 ` [pve-devel] [RFC proxmox-widget-toolkit master v2 6/10] utils: introduce helper function getFieldDefFromPropertySchema Max R. Carrara
2025-11-21 16:58 ` [pve-devel] [RFC proxmox-widget-toolkit master v2 7/10] acme: use helper to construct ExtJS fields from property schemas Max R. Carrara
2025-11-21 16:58 ` [pve-devel] [RFC pve-manager master v2 08/10] api: add API routes 'plugins' and 'plugins/storage' Max R. Carrara
2025-11-21 16:58 ` [pve-devel] [RFC pve-manager master v2 09/10] ui: storage view: display error when no editor for storage type exists Max R. Carrara
2025-11-21 16:58 ` [pve-devel] [RFC pve-manager master v2 10/10] ui: storage: add basic UI integration for custom storage plugins Max R. Carrara

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=20251121165858.818307-3-m.carrara@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 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