From: Max Carrara <m.carrara@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v1 pve-storage 7/8] pluginbase: document volume operations
Date: Wed, 26 Mar 2025 15:20:58 +0100 [thread overview]
Message-ID: <20250326142059.261938-8-m.carrara@proxmox.com> (raw)
In-Reply-To: <20250326142059.261938-1-m.carrara@proxmox.com>
Add docstrings for the following methods:
- list_volumes
- get_volume_attribute
- update_volume_attribute
- volume_size_info
- volume_resize
- volume_snapshot
- volume_snapshot_info
- volume_rollback_is_possible
- volume_snapshot_rollback
- volume_snapshot_delete
- volume_snapshot_needs_fsfreeze
- storage_can_replicate
- volume_has_feature
- map_volume
- unmap_volume
- activate_volume
- deactivate_volume
- rename_volume
- prune_backups
Signed-off-by: Max Carrara <m.carrara@proxmox.com>
Co-authored-by: Maximiliano Sandoval <m.sandoval@proxmox.com>
---
src/PVE/Storage/PluginBase.pm | 401 ++++++++++++++++++++++++++++++++--
1 file changed, 388 insertions(+), 13 deletions(-)
diff --git a/src/PVE/Storage/PluginBase.pm b/src/PVE/Storage/PluginBase.pm
index 37b1471..a1bfc8d 100644
--- a/src/PVE/Storage/PluginBase.pm
+++ b/src/PVE/Storage/PluginBase.pm
@@ -861,108 +861,483 @@ sub free_image {
=cut
+=head3 $plugin->list_volumes($storeid, \%scfg, $vmid, \@content_types)
+
+B<REQUIRED:> Must be implemented in every storage plugin.
+
+Returns a list of volumes for the given guest whose content type is within the
+given C<\@content_types>. If C<\@content_types> is empty, no volumes will be
+returned. See C<L<< plugindata()|/"$plugin->plugindata()" >>> for all content types.
+
+ # List all backups for a guest
+ my $backups = $plugin->list_volumes($storeid, $scfg, $vmid, ['backup']);
+
+ # List all containers and virtual machines on the storage
+ my $guests = $plugin->list_volumes($storeid, $scfg, undef, ['rootdir', 'images'])
+
+The returned listref of hashrefs has the following structure:
+
+ [
+ {
+ content => "images",
+ ctime => "1702298038", # creation time as unix timestamp
+ format => "raw",
+ size => 9663676416, # in bytes!
+ vmid => 102,
+ volid => "local-lvm:vm-102-disk-0",
+ },
+ # [...]
+ ]
+
+Backups will also contain additional keys:
+
+ [
+ {
+ content => "backup",
+ ctime => 1742405070, # creation time as unix timestamp
+ format => "tar.zst",
+ notes => "...", # comment that was entered when backup was created
+ size => 328906840, # in bytes!
+ subtype => "lxc", # "lxc" for containers, "qemu" for VMs
+ vmid => 106,
+ volid => "local:backup/vzdump-lxc-106-2025_03_19-18_24_30.tar.zst",
+ },
+ # [...]
+ ]
+
+=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.
+=head3 $plugin->get_volume_attribute(\%scfg, $storeid, $volname, $attribute)
+
+=head3 $plugin->get_volume_attribute(...)
+
+B<REQUIRED:> Must be implemented in every storage plugin.
+
+Returns the value of the given C<$attribute> for a volume. If the attribute isn't
+supported for the volume, returns C<undef>.
+
+C<die>s if there is an error fetching the attribute.
+
+B<Possible attributes:>
+
+=over
+
+=item * C<notes> (returns scalar)
+
+User-provided comments / notes.
+
+=item * C<protected> (returns scalar)
+
+When set to C<1>, the volume must not be removed by C<L<< free_image()|/"$plugin->free_image(...)" >>>.
+Backups with C<protected> set to C<1> are ignored when pruning.
+
+=back
+
+=cut
+
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.
+=head3 $plugin->update_volume_attribute(\%scfg, $storeid, $volname, $attribute, $value)
+
+=head3 $plugin->update_volume_attribute(...)
+
+B<REQUIRED:> Must be implemented in every storage plugin.
+
+Sets the value of the given C<$attribute> for a volume to C<$value>.
+
+C<die>s if the attribute isn't supported for the volume (or storage).
+
+For a list of supported attributes, see C<L<< get_volume_attribute()|/"$plugin->get_volume_attribute(...)" >>>.
+
+=cut
+
sub update_volume_attribute {
my ($class, $scfg, $storeid, $volname, $attribute, $value) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->volume_size_info(\%scfg, $storeid, $volname [, $timeout])
+
+B<REQUIRED:> Must be implemented in every storage plugin.
+
+Returns information about the given volume's size. In scalar context, this returns
+just the volume's size in bytes:
+
+ my $size = $plugin->volume_size_info($scfg, $storeid, $volname, $timeout)
+
+In list context, returns an array with the following structure:
+
+ my ($size, $format, $used, $parent, $ctime) = $plugin->volume_size_info(
+ $scfg, $storeid, $volname, $timeout
+ )
+
+where C<$size> is the size of the volume in bytes, C<$format> one of the possible
+L<< formats listed in C<plugindata()>|/"$plugin->plugindata()" >>, C<$used> the
+amount of space used in bytes, C<$parent> the (optional) name of the base volume
+and C<$ctime> the creation time as unix timestamp.
+
+Optionally, a C<$timeout> may be provided after which the method should C<die>.
+This timeout is best passed to other helpers which already support timeouts,
+such as C<L<< PVE::Tools::run_command|PVE::Tools/run_command >>>.
+
+See also the C<L<< PVE::Storage::Plugin::file_size_info|PVE::Storage::Plugin/file_size_info >>> helper.
+
+=cut
+
sub volume_size_info {
my ($class, $scfg, $storeid, $volname, $timeout) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->volume_resize(\%scfg, $storeid, $volname, $size [, $running])
+
+B<REQUIRED:> Must be implemented in every storage plugin.
+
+Resizes a volume to the new C<$size> in bytes. Optionally, the guest that owns
+the volume may be C<$running> (= C<1>).
+
+C<die>s in case of errors, or if the underlying storage implementation or the
+volume's format doesn't support resizing.
+
+This function should not return any value. In previous versions the returned
+value would be used to determine the new size of the volume or whether the
+operation succeeded.
+
+=cut
+
sub volume_resize {
my ($class, $scfg, $storeid, $volname, $size, $running) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->volume_snapshot(\%scfg, $storeid, $volname, $snap)
+
+B<OPTIONAL:> May be implemented if the underlying storage supports snapshots.
+
+Takes a snapshot of a volume and gives it the name provided by C<$snap>.
+
+C<die>s if the underlying storrage doesn't support snapshots or an error
+occurs while taking a snapshot.
+
+=cut
+
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.
+=head3 $plugin->volume_snapshot_info(\%scfg, $storeid, $volname)
+
+Returns a hashref with the snapshot names as keys and the following structure:
+
+ {
+ my_snapshot => {
+ id => "01b7e668-58b4-6f42-9a5e-1944c2855c84", # Unique id to distinguish different snapshots with the same name.
+ timestamp => "1729841807", # Creation time of the snapshot (seconds since epoch).
+ },
+ # [...]
+ }
+
+Returns an empty hashref if the volume does not exist.
+
+=cut
+
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.
+=head3 $plugin->volume_rollback_is_possible(\%scfg, $storeid, $volname, $snap [, \@blockers])
+
+=head3 $plugin->volume_rollback_is_possible(...)
+
+B<OPTIONAL:> May be implemented if the underlying storage supports snapshots.
+
+Asserts whether a rollback to C<$snap> on C<$volname> is possible, C<die>s if
+it isn't.
+
+Optionally, C<\@blockers> may be provided, which may contain the names of
+snapshots that are preventing the rollback. Should any such snapshots exist,
+they should be pushed to this listref pior to C<die>-ing. The caller may then
+use this listref when handling errors.
+
+=cut
+
sub volume_rollback_is_possible {
my ($class, $scfg, $storeid, $volname, $snap, $blockers) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->volume_snapshot_rollback(\%scfg, $storeid, $volname, $snap)
+
+Performs a rollback to the given C<$snap>shot on C<$volname>.
+
+C<die>s in case of errors.
+
+=cut
+
sub volume_snapshot_rollback {
my ($class, $scfg, $storeid, $volname, $snap) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->volume_snapshot_delete(\%scfg, $storeid, $volname, $snap [, $running])
+
+Deletes the C<$snap>shot of C<$volname>.
+
+C<die>s in case of errors.
+
+Optionally, the guest that owns the given volume may be C<$running> (= C<1>).
+
+B<Deprecated:> The C<$running> parameter is deprecated and will be removed on the
+next C<APIAGE> reset.
+
+=cut
+
sub volume_snapshot_delete {
my ($class, $scfg, $storeid, $volname, $snap, $running) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->volume_snapshot_needs_fsfreeze()
+
+Returns whether filesystems on top of the volume need to flush their journal for
+consistency before a snapshot is taken. See L<fsfreeze(8)>.
+
+This is needed for container mountpoints.
+
+=cut
+
sub volume_snapshot_needs_fsfreeze {
croak "implement me in sub-class\n";
}
+=head3 $plugin->storage_can_replicate(\%scfg, $storeid, $format)
+
+Returns whether volumes in a given C<$format> support replication.
+
+See C<L<< plugindata()|/"$plugin->plugindata()" >>> for all disk formats.
+
+=cut
+
sub storage_can_replicate {
my ($class, $scfg, $storeid, $format) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->volume_has_feature(\%scfg, $feature, $storeid, $volname, $snapname [, $running, \%opts])
+
+=head3 $plugin->volume_has_feature(...)
+
+B<REQUIRED:> Must be implemented in every storage plugin.
+
+Checks whether a volume C<$volname> or its snapshot C<$snapname> supports the
+given C<$feature>, returning C<1> if it does and C<undef> otherwise. The guest
+owning the volume may optionally be C<$running>.
+
+C<$feature> may be one of the following:
+
+ clone # linked clone is possible
+ copy # full clone is possible
+ replicate # replication is possible
+ snapshot # taking a snapshot is possible
+ sparseinit # volume is sparsely initialized
+ template # conversion to base image is possible
+ rename # renaming volumes is possible
+
+Which features are available under which circumstances depends on multiple
+factors, such as the underlying storage implementation, the format used, etc.
+It's best to check out C<L<PVE::Storage::Plugin>> or C<L<PVE::Storage::ZFSPoolPlugin>>
+for examples on how to handle features.
+
+Additional keys are given in C<\%opts>:
+
+=over
+
+=item * C<< valid_target_formats => [...] >>
+
+Listref of formats for the target of a copy/clone operation that the caller
+could work with. The format of the given volume is always considered valid and
+if no list is specified, all formats are considered valid.
+
+=back
+
+=cut
+
sub volume_has_feature {
my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running, $opts) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->map_volume($storeid, \%scfg, $volname [, $snapname])
+
+B<OPTIONAL:> May be implemented in a storage plugin.
+
+Maps the device asscoiated with a volume or a volume's snapshot to a filesystem
+path, returning the path on completion. This method is used by containers.
+
+C<die>s in case of errors.
+
+C<L<< unmap_volume()|/"$plugin->unmap_volume(...)" >>> can be used to declare
+how the device should be unmapped.
+
+=cut
+
sub map_volume {
my ($class, $storeid, $scfg, $volname, $snapname) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->unmap_volume($storeid, \%scfg, $volname [, $snapname])
+
+B<OPTIONAL:> May be implemented in a storage plugin.
+
+Unmaps the device associated to a volume or a volume's snapshot.
+
+C<die>s in case of errors.
+
+=cut
+
sub unmap_volume {
my ($class, $storeid, $scfg, $volname, $snapname) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->activate_volume($storeid, \%scfg, $volname, $snapname [, \%cache])
+
+=head3 $plugin->activate_volume(...)
+
+B<REQUIRED:> Must be implemented in every storage plugin.
+
+Activates a volume or its associated snapshot, making it available to the
+system for further use. For example, this could mean activating an LVM volume,
+mounting a ZFS dataset, checking whether the volume's file path exists, etc.
+
+C<die>s in case of errors or if an operation is not supported.
+
+If this isn't needed, the method should simply be a no-op.
+
+This method may reuse L<< cached information via C<\%cache>|/"CACHING EXPENSIVE OPERATIONS" >>.
+
+=cut
+
sub activate_volume {
my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->deactivate_volume($storeid, \%scfg, $volname, $snapname [, \%cache])
+
+=head3 deactivate_volume(...)
+
+B<REQUIRED:> Must be implemented in every storage plugin.
+
+Deactivates a volume or its associated snapshot, making it unavailable to
+the system. For example, this could mean deactivating an LVM volume,
+unmapping a Ceph/RBD device, etc.
+
+If this isn't needed, the method should simply be a no-op.
+
+This method may reuse L<< cached information via C<\%cache>|/"CACHING EXPENSIVE OPERATIONS" >>.
+
+=cut
+
sub deactivate_volume {
my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->rename_volume(...)
+
+=head3 $plugin->rename_volume(\%scfg, $storeid, $source_volname, $target_vmid, $target_volname)
+
+B<OPTIONAL:> May be implemented in a storage plugin.
+
+Renames the volume given by C<$source_volname> to C<$target_volname> and assigns
+it to the guest C<$target_vmid>. Returns the volume ID of the renamed volume.
+
+This method is needed for the I<Change Owner> feature.
+
+C<die>s if the rename failed.
+
+=cut
+
sub rename_volume {
my ($class, $scfg, $storeid, $source_volname, $target_vmid, $target_volname) = @_;
croak "implement me in sub-class\n";
}
+=head3 $plugin->prune_backups(\%scfg, $storeid [, \%keep, $vmid, $type, $dryrun, \&logfunc])
+
+=head3 $plugin->prune_backups(...)
+
+Export a volume into a file handle as a stream with a desired format.
+
+C<die>s if there are (grave) problems while pruning.
+
+This method may take several optional parameters:
+
+=over
+
+=item * C<< \%keep >>
+
+A hashref containing backup retention policies. It has the following structure:
+
+ {
+ 'keep-all' => 1 # (optional) Whether to keep all backups.
+ # Conflicts with the other options when true.
+ 'keep-last' => N # (optional) Keep the last N backups.
+ 'keep-hourly' => N # (optional) Keep backups for the last N different hours.
+ # If there is more than one backup for a single
+ # hour, only the latest one is kept.
+ 'keep-daily' => N # (optional) Keep backups for the last N different days.
+ # If there is more than one backup for a single
+ # day, only the latest one is kept.
+ 'keep-weekly' => N # (optional) Keep backups for the last N different weeks.
+ # If there is more than one backup for a single
+ # week, only the latest one is kept.
+ 'keep-monthly' => N # (optional) Keep backups for the last N different months.
+ # If there is more than one backup for a single
+ # month, only the latest one is kept.
+ 'keep-yearly' => N # (optional) Keep backups for the last N different years.
+ # If there is more than one backup for a single
+ # year, only the latest one is kept.
+ }
+
+=item * C<< $vmid >>
+
+The guest's ID.
+
+=item * C<< $type >>
+
+The type of guest. When C<defined>, it can be one of C<"qemu"> or C<"lxc">.
+If C<undefined>, both types of backups will be pruned.
+
+=item * C<< $dry_run >>
+
+Whether this is a dry run. If set to C<1> there won't be any change on the
+underlying storage.
+
+=item * C<< \&logfunc >>
+
+A subroutine ref that can be used to log messages with the following signature:
+
+ $logfunc->($severity, $message)
+
+where $severity can be one of C<"info">, C<"err">, or C<"warn">.
+
+=back
+
+=cut
+
sub prune_backups {
my ($class, $scfg, $storeid, $keep, $vmid, $type, $dryrun, $logfunc) = @_;
croak "implement me in sub-class\n";
--
2.39.5
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2025-03-26 14:21 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-26 14:20 [pve-devel] [PATCH v1 pve-storage 0/8] Base Module + Documentation for PVE::Storage::Plugin API Max Carrara
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 1/8] pluginbase: introduce PVE::Storage::PluginBase with doc scaffold Max Carrara
2025-03-31 15:13 ` Fabian Grünbichler
2025-04-02 16:31 ` Max Carrara
2025-04-03 7:12 ` Fabian Grünbichler
2025-04-03 14:05 ` Max Carrara
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 2/8] pluginbase: add high-level plugin API description Max Carrara
2025-03-31 15:13 ` Fabian Grünbichler
2025-04-02 16:31 ` Max Carrara
2025-04-03 7:12 ` Fabian Grünbichler
2025-04-03 14:05 ` Max Carrara
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 3/8] pluginbase: document SectionConfig methods Max Carrara
2025-03-31 15:13 ` Fabian Grünbichler
2025-04-02 16:31 ` Max Carrara
2025-04-11 13:49 ` Wolfgang Bumiller
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 4/8] pluginbase: document general plugin methods Max Carrara
2025-03-28 12:50 ` Maximiliano Sandoval
2025-03-31 15:12 ` Fabian Grünbichler
2025-04-02 16:31 ` Max Carrara
2025-04-11 14:04 ` Wolfgang Bumiller
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 5/8] pluginbase: document hooks Max Carrara
2025-03-28 13:07 ` Maximiliano Sandoval
2025-03-31 15:12 ` Fabian Grünbichler
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 6/8] pluginbase: document image operation methods Max Carrara
2025-03-31 15:12 ` Fabian Grünbichler
2025-04-02 16:32 ` Max Carrara
2025-04-03 7:23 ` Fabian Grünbichler
2025-04-03 14:05 ` Max Carrara
2025-04-11 14:08 ` Wolfgang Bumiller
2025-03-26 14:20 ` Max Carrara [this message]
2025-03-31 15:12 ` [pve-devel] [PATCH v1 pve-storage 7/8] pluginbase: document volume operations Fabian Grünbichler
2025-04-02 16:32 ` Max Carrara
2025-04-14 8:24 ` Wolfgang Bumiller
2025-03-26 14:20 ` [pve-devel] [PATCH v1 pve-storage 8/8] pluginbase: document import and export methods Max Carrara
2025-04-01 8:40 ` Fabian Grünbichler
2025-04-01 9:40 ` Fiona Ebner
2025-04-14 14:35 ` Wolfgang Bumiller
2025-04-02 16:32 ` Max Carrara
2025-04-11 13:27 ` [pve-devel] [PATCH v1 pve-storage 0/8] Base Module + Documentation for PVE::Storage::Plugin API Wolfgang Bumiller
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=20250326142059.261938-8-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal