From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <pve-devel-bounces@lists.proxmox.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id EF5111FF15C for <inbox@lore.proxmox.com>; Wed, 26 Mar 2025 15:21:15 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 4108C391AC; Wed, 26 Mar 2025 15:21:07 +0100 (CET) From: Max Carrara <m.carrara@proxmox.com> To: pve-devel@lists.proxmox.com Date: Wed, 26 Mar 2025 15:20:52 +0100 Message-Id: <20250326142059.261938-2-m.carrara@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250326142059.261938-1-m.carrara@proxmox.com> References: <20250326142059.261938-1-m.carrara@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.074 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] [PATCH v1 pve-storage 1/8] pluginbase: introduce PVE::Storage::PluginBase with doc scaffold X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/> List-Post: <mailto:pve-devel@lists.proxmox.com> List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe> Reply-To: Proxmox VE development discussion <pve-devel@lists.proxmox.com> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" <pve-devel-bounces@lists.proxmox.com> Add PVE::Storage::PluginBase, which defines stubs for all methods that storage plugins should implement in order to conform to our plugin API. This makes it much easier for (third-party) developers to see which methods should be implemented. PluginBase is inserted into the inheritance chain between PVE::Storage::Plugin and PVE::SectionConfig instead of letting the Plugin module inherit from SectionConfig directly. This keeps the inheritance chain linear, avoiding multiple inheritance. Also provide a scaffold for documentation. Preserve pre-existing comments for context's sake. Signed-off-by: Max Carrara <m.carrara@proxmox.com> --- src/PVE/Storage/Makefile | 1 + src/PVE/Storage/Plugin.pm | 2 +- src/PVE/Storage/PluginBase.pm | 328 ++++++++++++++++++++++++++++++++++ 3 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 src/PVE/Storage/PluginBase.pm diff --git a/src/PVE/Storage/Makefile b/src/PVE/Storage/Makefile index ce3fd68..f2cdb66 100644 --- a/src/PVE/Storage/Makefile +++ b/src/PVE/Storage/Makefile @@ -1,6 +1,7 @@ SOURCES= \ Common.pm \ Plugin.pm \ + PluginBase.pm \ DirPlugin.pm \ LVMPlugin.pm \ NFSPlugin.pm \ diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm index 65cf43f..df6882a 100644 --- a/src/PVE/Storage/Plugin.pm +++ b/src/PVE/Storage/Plugin.pm @@ -19,7 +19,7 @@ use PVE::Storage::Common; use JSON; -use base qw(PVE::SectionConfig); +use parent qw(PVE::Storage::PluginBase); use constant KNOWN_COMPRESSION_FORMATS => ('gz', 'lzo', 'zst', 'bz2'); use constant COMPRESSOR_RE => join('|', KNOWN_COMPRESSION_FORMATS); diff --git a/src/PVE/Storage/PluginBase.pm b/src/PVE/Storage/PluginBase.pm new file mode 100644 index 0000000..e56aa72 --- /dev/null +++ b/src/PVE/Storage/PluginBase.pm @@ -0,0 +1,328 @@ +=head1 NAME + +C<PVE::Storage::PluginBase> - Storage Plugin API Interface + +=head1 DESCRIPTION + +=cut + +package PVE::Storage::PluginBase; + +use strict; +use warnings; + +use Carp qw(croak); + +use parent qw(PVE::SectionConfig); + +=head1 PLUGIN INTERFACE METHODS + +=cut + +=head2 PLUGIN DEFINITION + +=cut + +sub type { + croak "implement me in sub-class\n"; +} + +sub properties { + my ($class) = @_; + return $class->SUPER::properties(); +} + +sub options { + my ($class) = @_; + return $class->SUPER::options(); +} + +sub plugindata { + my ($class) = @_; + return $class->SUPER::plugindata(); +} + +sub private { + croak "implement me in sub-class\n"; +} + +=head2 GENERAL + +=cut + +sub check_connection { + my ($class, $storeid, $scfg) = @_; + + return 1; +} + +sub activate_storage { + my ($class, $storeid, $scfg, $cache) = @_; + croak "implement me in sub-class\n"; +} + +sub deactivate_storage { + my ($class, $storeid, $scfg, $cache) = @_; + + return; +} + +sub status { + my ($class, $storeid, $scfg, $cache) = @_; + croak "implement me in sub-class\n"; +} + +sub cluster_lock_storage { + my ($class, $storeid, $shared, $timeout, $func, @param) = @_; + croak "implement me in sub-class\n"; +} + +sub parse_volname { + my ($class, $volname) = @_; + croak "implement me in sub-class\n"; +} + +sub get_subdir { + my ($class, $scfg, $vtype) = @_; + croak "implement me in sub-class\n"; +} + +sub filesystem_path { + my ($class, $scfg, $volname, $snapname) = @_; + croak "implement me in sub-class\n"; +} + +sub path { + my ($class, $scfg, $volname, $storeid, $snapname) = @_; + croak "implement me in sub-class\n"; +} + +sub find_free_diskname { + my ($class, $storeid, $scfg, $vmid, $fmt, $add_fmt_suffix) = @_; + croak "implement me in sub-class\n"; +} + +=head2 HOOKS + +=cut + +# called during addition of storage (before the new storage config got written) +# die to abort addition if there are (grave) problems +# NOTE: runs in a storage config *locked* context +sub on_add_hook { + my ($class, $storeid, $scfg, %param) = @_; + return undef; +} + +# called during storage configuration update (before the updated storage config got written) +# die to abort the update if there are (grave) problems +# NOTE: runs in a storage config *locked* context +sub on_update_hook { + my ($class, $storeid, $scfg, %param) = @_; + return undef; +} + +# called during deletion of storage (before the new storage config got written) +# and if the activate check on addition fails, to cleanup all storage traces +# which on_add_hook may have created. +# die to abort deletion if there are (very grave) problems +# NOTE: runs in a storage config *locked* context +sub on_delete_hook { + my ($class, $storeid, $scfg) = @_; + return undef; +} + +=head2 IMAGE OPERATIONS + +=cut + +sub list_images { + my ($class, $storeid, $scfg, $vmid, $vollist, $cache) = @_; + croak "implement me in sub-class\n"; +} + +sub create_base { + my ($class, $storeid, $scfg, $volname) = @_; + croak "implement me in sub-class\n"; +} + +sub clone_image { + my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_; + croak "implement me in sub-class\n"; +} + +sub alloc_image { + my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_; + croak "implement me in sub-class\n"; +} + +sub free_image { + my ($class, $storeid, $scfg, $volname, $isBase, $format) = @_; + croak "implement me in sub-class\n"; +} + +=head2 VOLUME OPERATIONS + +=cut + +sub list_volumes { + my ($class, $storeid, $scfg, $vmid, $content_types) = @_; + croak "implement me in sub-class\n"; +} + +# Returns undef if the attribute is not supported for the volume. +# Should die if there is an error fetching the attribute. +# Possible attributes: +# notes - user-provided comments/notes. +# protected - not to be removed by free_image, and for backups, ignored when pruning. +sub get_volume_attribute { + my ($class, $scfg, $storeid, $volname, $attribute) = @_; + croak "implement me in sub-class\n"; +} + +# Dies if the attribute is not supported for the volume. +sub update_volume_attribute { + my ($class, $scfg, $storeid, $volname, $attribute, $value) = @_; + croak "implement me in sub-class\n"; +} + +sub volume_size_info { + my ($class, $scfg, $storeid, $volname, $timeout) = @_; + croak "implement me in sub-class\n"; +} + +sub volume_resize { + my ($class, $scfg, $storeid, $volname, $size, $running) = @_; + croak "implement me in sub-class\n"; +} + +sub volume_snapshot { + my ($class, $scfg, $storeid, $volname, $snap) = @_; + croak "implement me in sub-class\n"; +} + +# Returns a hash with the snapshot names as keys and the following data: +# id - Unique id to distinguish different snapshots even if the have the same name. +# timestamp - Creation time of the snapshot (seconds since epoch). +# Returns an empty hash if the volume does not exist. +sub volume_snapshot_info { + my ($class, $scfg, $storeid, $volname) = @_; + croak "implement me in sub-class\n"; +} + +# Asserts that a rollback to $snap on $volname is possible. +# If certain snapshots are preventing the rollback and $blockers is an array +# reference, the snapshot names can be pushed onto $blockers prior to dying. +sub volume_rollback_is_possible { + my ($class, $scfg, $storeid, $volname, $snap, $blockers) = @_; + croak "implement me in sub-class\n"; +} + +sub volume_snapshot_rollback { + my ($class, $scfg, $storeid, $volname, $snap) = @_; + croak "implement me in sub-class\n"; +} + +sub volume_snapshot_delete { + my ($class, $scfg, $storeid, $volname, $snap, $running) = @_; + croak "implement me in sub-class\n"; +} + +sub volume_snapshot_needs_fsfreeze { + croak "implement me in sub-class\n"; +} + +sub storage_can_replicate { + my ($class, $scfg, $storeid, $format) = @_; + croak "implement me in sub-class\n"; +} + +sub volume_has_feature { + my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running, $opts) = @_; + croak "implement me in sub-class\n"; +} + +sub map_volume { + my ($class, $storeid, $scfg, $volname, $snapname) = @_; + croak "implement me in sub-class\n"; +} + +sub unmap_volume { + my ($class, $storeid, $scfg, $volname, $snapname) = @_; + croak "implement me in sub-class\n"; +} + +sub activate_volume { + my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_; + croak "implement me in sub-class\n"; +} + +sub deactivate_volume { + my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_; + croak "implement me in sub-class\n"; +} + +sub rename_volume { + my ($class, $scfg, $storeid, $source_volname, $target_vmid, $target_volname) = @_; + croak "implement me in sub-class\n"; +} + +sub prune_backups { + my ($class, $scfg, $storeid, $keep, $vmid, $type, $dryrun, $logfunc) = @_; + croak "implement me in sub-class\n"; +} + +=head2 IMPORTS AND EXPORTS + +=cut + +# Import/Export interface: +# Any path based storage is assumed to support 'raw' and 'tar' streams, so +# the default implementations will return this if $scfg->{path} is set, +# mimicking the old PVE::Storage::storage_migrate() function. +# +# Plugins may fall back to PVE::Storage::Plugin::volume_{export,import}... +# functions in case the format doesn't match their specialized +# implementations to reuse the raw/tar code. +# +# Format specification: +# The following formats are all prefixed with image information in the form +# of a 64 bit little endian unsigned integer (pack('Q<')) in order to be able +# to preallocate the image on storages which require it. +# +# raw+size: (image files only) +# A raw binary data stream such as produced via `dd if=TheImageFile`. +# qcow2+size, vmdk: (image files only) +# A raw qcow2/vmdk/... file such as produced via `dd if=some.qcow2` for +# files which are already in qcow2 format, or via `qemu-img convert`. +# Note that these formats are only valid with $with_snapshots being true. +# tar+size: (subvolumes only) +# A GNU tar stream containing just the inner contents of the subvolume. +# This does not distinguish between the contents of a privileged or +# unprivileged container. In other words, this is from the root user +# namespace's point of view with no uid-mapping in effect. +# As produced via `tar -C vm-100-disk-1.subvol -cpf TheOutputFile.dat .` + +# Export a volume into a file handle as a stream of desired format. +sub volume_export { + my ($class, $scfg, $storeid, $fh, $volname, $format, $snapshot, $base_snapshot, $with_snapshots) = @_; + croak "implement me in sub-class\n"; +} + +sub volume_export_formats { + my ($class, $scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots) = @_; + croak "implement me in sub-class\n"; +} + +# Import data from a stream, creating a new or replacing or adding to an existing volume. +sub volume_import { + my ($class, $scfg, $storeid, $fh, $volname, $format, $snapshot, $base_snapshot, $with_snapshots, $allow_rename) = @_; + croak "implement me in sub-class\n"; +} + +sub volume_import_formats { + my ($class, $scfg, $storeid, $volname, $snapshot, $base_snapshot, $with_snapshots) = @_; + croak "implement me in sub-class\n"; +} + +1; -- 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel