From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 256651FF187 for ; Mon, 8 Sep 2025 20:01:10 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id BC6E518851; Mon, 8 Sep 2025 20:01:06 +0200 (CEST) From: "Max R. Carrara" To: pve-devel@lists.proxmox.com Date: Mon, 8 Sep 2025 20:00:46 +0200 Message-ID: <20250908180058.530119-3-m.carrara@proxmox.com> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250908180058.530119-1-m.carrara@proxmox.com> References: <20250908180058.530119-1-m.carrara@proxmox.com> MIME-Version: 1.0 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1757354440192 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.087 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [RFC pve-storage master v1 02/12] api: Add 'plugins/storage' and 'plugins/storage/{plugin}' paths X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox VE development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" 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 --- 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 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel