On 06.04.20 11:52, Fabian Grünbichler wrote:
On April 6, 2020 10:46 am, Fabian Ebner wrote:
On 27.03.20 10:09, Fabian Grünbichler wrote:
with a small follow-up for vzdump (see separate mail), and comment below

On March 23, 2020 12:18 pm, Fabian Ebner wrote:
With the option valid_target_formats it's possible
to let the caller specify possible formats for the target
of an operation.
[0]: If the option is not set, assume that every format is valid.

In most cases the format of the the target and the format
of the source will agree (and therefore assumption [0] is
not actually assuming very much and ensures backwards
compatability). But when cloning a volume on a storage
using Plugin.pm's implementation (e.g. directory based
storages), the result is always a qcow2 image.

When cloning containers, the new option can be used to detect
that qcow2 is not valid and hence the clone feature is not
available.

Signed-off-by: Fabian Ebner <f.eb...@proxmox.com>
---

it would be a good follow-up to think which other storage plugins should
also implement this. e.g. plugins supporting subvol and raw/qcow2/vmdk -
can they copy/clone from one to the other? future people might only look
at Plugin.pm, see that such an option exists, and assume it works for all
plugins/features ;)


The copy operations are actually implemented as the non-full clone_disk
for QEMU and as copy_volume in LXC. AFAIU they should always work.

right, those are actually not implemented in the storage layer
(anymore?), so checking there does not make much sense. I wonder whether
we even need the 'copy' feature then? export/import uses it's own format
matching, and the full clone stuff is already in
pve-container/qemu-server with lots of special handling.


[2]: There is a single caller (except for the has_feature API calls) in API2/Qemu.pm's clone_vm.

("allowed" in the next paragraph means has_feature returns 1)
Looking through the individual plugins, copy with "current" is always allowed and whenever the storage (and for Plugin.pm format) supports snapshots respectively base images, then copy with "snap" respectively "base" is allowed. That is, except for ZFS, where copy with "snap" is not allowed.

But this another difference between LXC/QEMU. For containers there is no equivalent check like [2] and making a full clone from a snapshot actually works. When I comment out the check for QEMU, I get:

qemu-img: Could not open '/dev/zvol/myzpool/vm-108-disk-0@adsf': Could not open '/dev/zvol/myzpool/vm-108-disk-0@adsf': No such file or directory

So there is a purpose for checking the copy feature, although not the best one, since copying from a ZFS snapshot isn't impossible in itself as the LXC case shows.
Also, wouldn't removing the copy feature technically also break the API?

If we really want to remove it, we could replace the check in QEMU by an explicit check for "full copy of ZFS from snapshot" or otherwise implement that feature and drop the check entirely.

there's also still some issue/missing check for subvols of size 0 which
can't be moved to a sized volume, but that is unrelated.


For clone operations, there is vdisk_clone in the storage module, but it
doesn't take a format parameter. Except for GlusterfsPlugin.pm (which
doesn't have its own volume_has_feature) and Plugin.pm the format of the
target is the same as the format of the source. Shouldn't that be
considered valid regardless of the valid_target_formats option?

you can't say it's valid per se - since for example raw->raw is not
possible, but raw->qcow2 is.


Yes, raw->raw is not possible, but raw would be a valid target format from the caller's perspective. Since the caller apparently can handle volumes with the format of the source, the storage backend can assume it's fine if the target is in that format as well. That does not mean that the operation will result in that format, just that it would be something the caller could deal with.

But it's true that this is an additional assumption:
[0]: If the option is not set, assume that every format is valid.
[1]: Regardless of whether the option is set, the format of the source is valid.
(valid again means something the caller can deal with).

[0] and [1] together are sufficient to make the current implementation(s) of volume_has_feature correct. If we drop [1], we need additional checks for clone in volume_has_feature (for LvmThin/RBD/ZFS), i.e. check if the format of the source (which will be the format of the target) appears in the list the caller gave us.

Should I add a comment with both assumptions or only the first one and add the additional checks?

Otherwise one needs to add a check whether valid_target_formats includes
the format of the source for other plugins that implement clone_image.

hm. it's all a bit of a mess with a fuzzy boundary between storage and
qemu-server/pve-container, and probably requires more thought to clean
up...

Changes from v2:
      * Use new options parameter instead of adding more
        dependency to PVE::Cluster
      * storage API bump and now there is an inter-package dependency:
        #2 container depends on #1 storage

   PVE/Storage.pm        | 8 ++++----
   PVE/Storage/Plugin.pm | 7 ++++++-
   2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/PVE/Storage.pm b/PVE/Storage.pm
index a46550c..fcfc6af 100755
--- a/PVE/Storage.pm
+++ b/PVE/Storage.pm
@@ -39,11 +39,11 @@ use PVE::Storage::DRBDPlugin;
   use PVE::Storage::PBSPlugin;
# Storage API version. Icrement it on changes in storage API interface.
-use constant APIVER => 3;
+use constant APIVER => 4;
   # Age is the number of versions we're backward compatible with.
   # This is like having 'current=APIVER' and age='APIAGE' in libtool,
   # see 
https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
-use constant APIAGE => 2;
+use constant APIAGE => 3;
# load standard plugins
   PVE::Storage::DirPlugin->register();
@@ -286,13 +286,13 @@ sub volume_snapshot_delete {
   }
sub volume_has_feature {
-    my ($cfg, $feature, $volid, $snap, $running) = @_;
+    my ($cfg, $feature, $volid, $snap, $running, $opts) = @_;
my ($storeid, $volname) = parse_volume_id($volid, 1);
       if ($storeid) {
           my $scfg = storage_config($cfg, $storeid);
           my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
-        return $plugin->volume_has_feature($scfg, $feature, $storeid, 
$volname, $snap, $running);
+        return $plugin->volume_has_feature($scfg, $feature, $storeid, 
$volname, $snap, $running, $opts);
       } elsif ($volid =~ m|^(/.+)$| && -e $volid) {
        return undef;
       } else {
diff --git a/PVE/Storage/Plugin.pm b/PVE/Storage/Plugin.pm
index 2232261..8c0dae1 100644
--- a/PVE/Storage/Plugin.pm
+++ b/PVE/Storage/Plugin.pm
@@ -828,7 +828,7 @@ sub storage_can_replicate {
   }
sub volume_has_feature {
-    my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
+    my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running, 
$opts) = @_;
my $features = {
        snapshot => { current => { qcow2 => 1}, snap => { qcow2 => 1} },
@@ -841,6 +841,11 @@ sub volume_has_feature {
                        current => {qcow2 => 1, raw => 1, vmdk => 1} },
       };
+ # clone_image creates a qcow2 volume
+    return 0 if $feature eq 'clone' &&
+               defined($opts->{valid_target_formats}) &&
+               !(grep { $_ eq 'qcow2' } @{$opts->{valid_target_formats}});
+
       my ($vtype, $name, $vmid, $basename, $basevmid, $isBase, $format) =
        $class->parse_volname($volname);
--
2.20.1


_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel



_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to