From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 751BE1FF0ED for ; Fri, 31 Jul 2026 17:37:22 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 5E2D821676; Fri, 31 Jul 2026 17:36:40 +0200 (CEST) From: Jakob Klocker To: pve-devel@lists.proxmox.com Subject: [PATCH pve-storage 5/9] storage: expose plugin metadata in storage status Date: Fri, 31 Jul 2026 17:36:13 +0200 Message-ID: <20260731153617.358265-6-j.klocker@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260731153617.358265-1-j.klocker@proxmox.com> References: <20260731153617.358265-1-j.klocker@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 1 AWL -0.582 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 1.274 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Message-ID-Hash: 5VPNR6HHZ4PLDAYSQADJUEXJGMPTRO4D X-Message-ID-Hash: 5VPNR6HHZ4PLDAYSQADJUEXJGMPTRO4D X-MailFrom: jklocker@dev.proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Jakob Klocker X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The plugin state determined when scanning custom plugins was so far only available internally. Add it to the per-storage information, together with the API version the plugin implements, the API version range this PVE supports, whether the plugin is provided by a third party, and the optional plugin URL. This allows the GUI to tell users that a storage uses an outdated or broken plugin and to point them at the plugin's homepage. Signed-off-by: Jakob Klocker --- src/PVE/API2/Storage/Status.pm | 39 ++++++++++++++++++++++++++++++++++ src/PVE/Storage.pm | 16 ++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/PVE/API2/Storage/Status.pm b/src/PVE/API2/Storage/Status.pm index 741d514..f044e7a 100644 --- a/src/PVE/API2/Storage/Status.pm +++ b/src/PVE/API2/Storage/Status.pm @@ -390,6 +390,45 @@ __PACKAGE__->register_method({ renderer => 'bytes', optional => 1, }, + plugin => { + description => "Metadata about the storage plugin backing this storage.", + type => 'object', + optional => 1, + properties => { + external => { + description => + "Set when the storage is provided by a third-party plugin.", + type => 'boolean', + optional => 1, + }, + state => { + description => "Plugin state: up-to-date, outdated, or load-error.", + type => 'string', + enum => ['up-to-date', 'outdated', 'load-error'], + optional => 1, + }, + 'api-version' => { + description => "API version implemented by the storage plugin.", + type => 'integer', + optional => 1, + }, + 'api-min' => { + description => "Minimum plugin API version supported by this PVE.", + type => 'integer', + optional => 1, + }, + 'api-max' => { + description => "Current plugin API version of this PVE.", + type => 'integer', + optional => 1, + }, + url => { + description => "URL to the plugin's homepage or documentation.", + type => 'string', + optional => 1, + }, + }, + }, }, }, code => sub { diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm index b433efc..06be29d 100755 --- a/src/PVE/Storage.pm +++ b/src/PVE/Storage.pm @@ -1620,6 +1620,14 @@ sub storage_info { } my $type = $ids->{$storeid}->{type}; + my $entry = custom_plugin_entry($type); + my $external = $entry ? 1 : 0; + my $state = get_plugin_state($type); + my $api_version = $entry ? $entry->{'api-version'} : APIVER; + my $plugin_url = + $entry + ? $entry->{'plugin-url'} + : eval { PVE::Storage::Plugin->lookup($type)->plugindata()->{'plugin-url'} }; $info->{$storeid} = { type => $type, @@ -1631,6 +1639,14 @@ sub storage_info { PVE::Storage::Plugin::content_hash_to_string($ids->{$storeid}->{content}), active => 0, enabled => $storage_enabled ? 1 : 0, + plugin => { + external => $external, + state => $state, + 'api-version' => $api_version, + 'api-min' => (APIVER - APIAGE), + 'api-max' => APIVER, + url => $plugin_url, + }, }; } -- 2.47.3