]> git.proxmox.com Git - pve-storage.git/blobdiff - PVE/Storage/Plugin.pm
fix #1816: rbd: add support for erasure coded ec pools
[pve-storage.git] / PVE / Storage / Plugin.pm
index aeb4fff3eb67c81b175b81e59ad2e6993523d742..12f1b4bb8336db350cda6dd38b0fac6dee2b1ab1 100644 (file)
@@ -828,6 +828,9 @@ sub alloc_image {
 sub free_image {
     my ($class, $storeid, $scfg, $volname, $isBase, $format) = @_;
 
+    die "cannot remove protected volume '$volname' on '$storeid'\n"
+       if $class->get_volume_attribute($scfg, $storeid, $volname, 'protected');
+
     my $path = $class->filesystem_path($scfg, $volname);
 
     if ($isBase) {
@@ -897,18 +900,53 @@ sub file_size_info {
     return wantarray ? ($size, $format, $used, $parent, $st->ctime) : $size;
 }
 
+# FIXME remove on the next APIAGE reset.
+# Deprecated, use get_volume_attribute instead.
 sub get_volume_notes {
     my ($class, $scfg, $storeid, $volname, $timeout) = @_;
 
     die "volume notes are not supported for $class";
 }
 
+# FIXME remove on the next APIAGE reset.
+# Deprecated, use update_volume_attribute instead.
 sub update_volume_notes {
     my ($class, $scfg, $storeid, $volname, $notes, $timeout) = @_;
 
     die "volume notes are not supported for $class";
 }
 
+# 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) = @_;
+
+    if ($attribute eq 'notes') {
+        my $notes = eval { $class->get_volume_notes($scfg, $storeid, $volname); };
+        if (my $err = $@) {
+            return if $err =~ m/^volume notes are not supported/;
+            die $err;
+        }
+        return $notes;
+    }
+
+    return;
+}
+
+# Dies if the attribute is not supported for the volume.
+sub update_volume_attribute {
+    my ($class, $scfg, $storeid, $volname, $attribute, $value) = @_;
+
+    if ($attribute eq 'notes') {
+       $class->update_volume_notes($scfg, $storeid, $volname, $value);
+    }
+
+    die "attribute '$attribute' is not supported for storage type '$scfg->{type}'\n";
+}
+
 sub volume_size_info {
     my ($class, $scfg, $storeid, $volname, $timeout) = @_;
     my $path = $class->filesystem_path($scfg, $volname);
@@ -948,8 +986,11 @@ sub volume_snapshot {
     return undef;
 }
 
+# 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) = @_;
+    my ($class, $scfg, $storeid, $volname, $snap, $blockers) = @_;
 
     return 1;
 }
@@ -1008,6 +1049,7 @@ sub volume_has_feature {
                  snap => {qcow2 => 1} },
        sparseinit => { base => {qcow2 => 1, raw => 1, vmdk => 1},
                        current => {qcow2 => 1, raw => 1, vmdk => 1} },
+       rename => { current => {qcow2 => 1, raw => 1, vmdk => 1} },
     };
 
     # clone_image creates a qcow2 volume
@@ -1015,6 +1057,8 @@ sub volume_has_feature {
                defined($opts->{valid_target_formats}) &&
                !(grep { $_ eq 'qcow2' } @{$opts->{valid_target_formats}});
 
+    return 0 if $feature eq 'rename' && $class->can('api') && $class->api() < 10;
+
     my ($vtype, $name, $vmid, $basename, $basevmid, $isBase, $format) =
        $class->parse_volname($volname);
 
@@ -1127,6 +1171,7 @@ my $get_subdir_files = sub {
                $info->{notes} = $notes if defined($notes);
            }
 
+           $info->{protected} = 1 if -e PVE::Storage::protection_file_path($original);
        } elsif ($tt eq 'snippets') {
 
            $info = {
@@ -1144,6 +1189,8 @@ my $get_subdir_files = sub {
     return $res;
 };
 
+# If attributes are set on a volume, they should be included in the result.
+# See get_volume_attribute for a list of possible attributes.
 sub list_volumes {
     my ($class, $storeid, $scfg, $vmid, $content_types) = @_;
 
@@ -1209,13 +1256,14 @@ sub status {
     return ($res->{total}, $res->{avail}, $res->{used}, 1);
 }
 
-sub volume_snapshot_list {
+# 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) = @_;
 
-    # implement in subclass
-    die "Volume_snapshot_list is not implemented for $class";
-
-    # return an empty array if dataset does not exist.
+    die "volume_snapshot_info is not implemented for $class";
 }
 
 sub activate_storage {
@@ -1327,9 +1375,11 @@ sub prune_backups {
            push @{$backup_groups->{$group}}, $prune_entry;
        } else {
            # ignore backups that don't use the standard naming scheme
-           $prune_entry->{mark} = 'protected';
+           $prune_entry->{mark} = 'renamed';
        }
 
+       $prune_entry->{mark} = 'protected' if $backup->{protected};
+
        push @{$prune_list}, $prune_entry;
     }
 
@@ -1531,4 +1581,39 @@ sub volume_import_formats {
     return ();
 }
 
+sub rename_volume {
+    my ($class, $scfg, $storeid, $source_volname, $target_vmid, $target_volname) = @_;
+    die "not implemented in storage plugin '$class'\n" if $class->can('api') && $class->api() < 10;
+    die "no path found\n" if !$scfg->{path};
+
+    my (
+       undef,
+       $source_image,
+       $source_vmid,
+       $base_name,
+       $base_vmid,
+       undef,
+       $format
+    ) = $class->parse_volname($source_volname);
+
+    $target_volname = $class->find_free_diskname($storeid, $scfg, $target_vmid, $format, 1)
+       if !$target_volname;
+
+    my $basedir = $class->get_subdir($scfg, 'images');
+
+    mkpath "${basedir}/${target_vmid}";
+
+    my $old_path = "${basedir}/${source_vmid}/${source_image}";
+    my $new_path = "${basedir}/${target_vmid}/${target_volname}";
+
+    die "target volume '${target_volname}' already exists\n" if -e $new_path;
+
+    my $base = $base_name ? "${base_vmid}/${base_name}/" : '';
+
+    rename($old_path, $new_path) ||
+       die "rename '$old_path' to '$new_path' failed - $!\n";
+
+    return "${storeid}:${base}${target_vmid}/${target_volname}";
+}
+
 1;