[pve-devel] [RFC pve-storage master v1 02/12] api: Add 'plugins/storage' and 'plugins/storage/{plugin}' paths
Max R. Carrara
m.carrara at proxmox.com
Mon Sep 8 20:00:46 CEST 2025
Add these paths in order to expose plugin metadata via the API.
Both paths use a common JSON schema for plugin metadata;
'plugins/storage' lists the metadata for all plugins, whereas
'plugins/storage/{plugin}' returns the metadata for a single plugin.
The queried metadata is validated against the JSON schema for each API
call. This is rather suboptimal and should be done via tests instead,
but is kept in regardless to keep this RFC short.
What permissions the two paths should use has not yet been decided.
Signed-off-by: Max R. Carrara <m.carrara at proxmox.com>
---
src/PVE/API2/Makefile | 1 +
src/PVE/API2/Plugins/Makefile | 18 +++
src/PVE/API2/Plugins/Storage/Config.pm | 168 +++++++++++++++++++++++++
src/PVE/API2/Plugins/Storage/Makefile | 17 +++
4 files changed, 204 insertions(+)
create mode 100644 src/PVE/API2/Plugins/Makefile
create mode 100644 src/PVE/API2/Plugins/Storage/Config.pm
create mode 100644 src/PVE/API2/Plugins/Storage/Makefile
diff --git a/src/PVE/API2/Makefile b/src/PVE/API2/Makefile
index fe316c5..01b7b28 100644
--- a/src/PVE/API2/Makefile
+++ b/src/PVE/API2/Makefile
@@ -5,3 +5,4 @@ install:
install -D -m 0644 Disks.pm ${DESTDIR}${PERLDIR}/PVE/API2/Disks.pm
make -C Storage install
make -C Disks install
+ make -C Plugins install
diff --git a/src/PVE/API2/Plugins/Makefile b/src/PVE/API2/Plugins/Makefile
new file mode 100644
index 0000000..b235d67
--- /dev/null
+++ b/src/PVE/API2/Plugins/Makefile
@@ -0,0 +1,18 @@
+SOURCES =
+
+
+SUBDIRS = Storage \
+
+
+INSTALL_PATH = ${DESTDIR}${PERLDIR}/PVE/API2/Plugins
+
+
+.PHONY: install
+install:
+ set -e && for SOURCE in ${SOURCES}; \
+ do install -D -m 0644 $$SOURCE ${INSTALL_PATH}/$$SOURCE; \
+ done
+ set -e && for SUBDIR in ${SUBDIRS}; \
+ do make -C $$SUBDIR install; \
+ done
+
diff --git a/src/PVE/API2/Plugins/Storage/Config.pm b/src/PVE/API2/Plugins/Storage/Config.pm
new file mode 100644
index 0000000..064aec9
--- /dev/null
+++ b/src/PVE/API2/Plugins/Storage/Config.pm
@@ -0,0 +1,168 @@
+package PVE::API2::Plugins::Storage::Config;
+
+use v5.36;
+
+use HTTP::Status qw(:constants);
+
+use PVE::Exception qw(raise);
+use PVE::JSONSchema;
+use PVE::Storage;
+use PVE::Storage::Plugin;
+use PVE::Storage::Plugin::Meta qw(
+ plugin_kinds
+ plugin_content_types
+ plugin_formats
+ get_plugin_metadata
+ get_plugin_metadata_all
+);
+use PVE::Tools qw(extract_param);
+
+use PVE::RESTHandler;
+use base qw(PVE::RESTHandler);
+
+my $PLUGIN_METADATA_SCHEMA = {
+ type => 'object',
+ properties => {
+ type => {
+ type => 'string',
+ enum => PVE::Storage::Plugin->lookup_types(),
+ optional => 0,
+ },
+ kind => {
+ type => 'string',
+ enum => plugin_kinds(),
+ optional => 0,
+ },
+ content => {
+ type => 'object',
+ optional => 0,
+ properties => {
+ supported => {
+ type => 'array',
+ items => {
+ type => 'string',
+ enum => plugin_content_types(),
+ },
+ },
+ default => {
+ type => 'array',
+ items => {
+ type => 'string',
+ enum => plugin_content_types(),
+ },
+ },
+ },
+ },
+ format => {
+ type => 'object',
+ optional => 0,
+ properties => {
+ supported => {
+ type => 'array',
+ items => {
+ type => 'string',
+ enum => plugin_formats(),
+ },
+ },
+ default => {
+ type => 'string',
+ enum => plugin_formats(),
+ },
+ },
+ },
+ 'sensitive-properties' => {
+ type => 'array',
+ optional => 0,
+ items => {
+ type => 'string',
+ },
+ },
+ },
+};
+
+# plugins/storage
+
+__PACKAGE__->register_method({
+ name => 'index',
+ path => '',
+ method => 'GET',
+ description => 'List all available storage plugins and their metadata.',
+ permissions => {
+ # TODO: perms
+ description => "",
+ user => 'all',
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ kind => {
+ description => "Only list built-in or custom storage plugins.",
+ type => 'string',
+ enum => plugin_kinds(),
+ optional => 1,
+ },
+ },
+ },
+ returns => {
+ type => 'array',
+ items => $PLUGIN_METADATA_SCHEMA,
+ },
+ code => sub($param) {
+ my $param_kind = extract_param($param, 'kind');
+
+ my $result = [];
+
+ my $plugin_metadata = get_plugin_metadata_all();
+
+ for my $type (sort keys $plugin_metadata->%*) {
+ my $type_info = $plugin_metadata->{$type};
+
+ # TODO: run in tests instead?
+ PVE::JSONSchema::validate($type_info, $PLUGIN_METADATA_SCHEMA);
+
+ my $kind = $type_info->{kind};
+
+ next if defined($param_kind) && $kind ne $param_kind;
+
+ push($result->@*, $type_info);
+ }
+
+ return $result;
+ },
+});
+
+# plugins/storage/{plugin}
+
+__PACKAGE__->register_method({
+ name => 'info',
+ path => '{plugin}',
+ method => 'GET',
+ description => "Show general information and metadata of a storage plugin.",
+ permissions => {
+ # TODO: perms
+ description => "",
+ user => 'all',
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ plugin => {
+ type => 'string',
+ },
+ },
+ },
+ returns => $PLUGIN_METADATA_SCHEMA,
+ code => sub($param) {
+ my $param_type = extract_param($param, 'plugin');
+
+ my $plugin_metadata = get_plugin_metadata($param_type)
+ or raise("Plugin '$param_type' not found", code => HTTP_NOT_FOUND);
+
+ # TODO: run in tests for each plugin instead?
+ PVE::JSONSchema::validate($plugin_metadata, $PLUGIN_METADATA_SCHEMA);
+
+ return $plugin_metadata;
+ },
+});
+
+1;
diff --git a/src/PVE/API2/Plugins/Storage/Makefile b/src/PVE/API2/Plugins/Storage/Makefile
new file mode 100644
index 0000000..73875cf
--- /dev/null
+++ b/src/PVE/API2/Plugins/Storage/Makefile
@@ -0,0 +1,17 @@
+SOURCES = Config.pm \
+
+
+SUBDIRS =
+
+
+INSTALL_PATH = ${DESTDIR}${PERLDIR}/PVE/API2/Plugins/Storage
+
+.PHONY: install
+install:
+ set -e && for SOURCE in ${SOURCES}; \
+ do install -D -m 0644 $$SOURCE ${INSTALL_PATH}/$$SOURCE; \
+ done
+ set -e && for SUBDIR in ${SUBDIRS}; \
+ do make -C $$SUBDIR install; \
+ done
+
--
2.47.2
More information about the pve-devel
mailing list