]> git.proxmox.com Git - pve-storage.git/blobdiff - PVE/Storage/Plugin.pm
tree-wide: fix typos with codespell
[pve-storage.git] / PVE / Storage / Plugin.pm
index 00ce9cb3c1230950906b1d358cd7c4fb552ec729..15bf91624724bd136c19f36850431f06c5734013 100644 (file)
@@ -19,7 +19,7 @@ use base qw(PVE::SectionConfig);
 
 use constant COMPRESSOR_RE => 'gz|lzo|zst';
 
-use constant COMMENT_EXT => ".comment";
+use constant NOTES_EXT => ".notes";
 
 our @COMMON_TAR_FLAGS = qw(
     --one-file-system
@@ -37,7 +37,9 @@ our @SHARED_STORAGE = (
     'iscsidirect',
     'glusterfs',
     'zfs',
-    'drbd');
+    'drbd',
+    'pbs',
+);
 
 our $MAX_VOLUMES_PER_GUEST = 1024;
 
@@ -52,6 +54,11 @@ my %prune_option = (
 );
 
 our $prune_backups_format = {
+    'keep-all' => {
+       type => 'boolean',
+       description => 'Keep all backups. Conflicts with the other options when true.',
+       optional => 1,
+    },
     'keep-last' => {
        %prune_option,
        description => 'Keep the last <N> backups.',
@@ -84,12 +91,17 @@ our $prune_backups_format = {
 };
 PVE::JSONSchema::register_format('prune-backups', $prune_backups_format, \&validate_prune_backups);
 sub validate_prune_backups {
-    my ($keep) = @_;
+    my ($prune_backups) = @_;
 
-    die "at least one keep-option must be set and positive\n"
-       if !grep { $_ } values %{$keep};
+    my $keep_all = delete $prune_backups->{'keep-all'};
+
+    if (!scalar(grep {$_ > 0} values %{$prune_backups})) {
+       $prune_backups = { 'keep-all' => 1 };
+    } elsif ($keep_all) {
+       die "keep-all cannot be set together with other options.\n";
+    }
 
-    return $keep;
+    return $prune_backups;
 }
 register_standard_option('prune-backups', {
     description => "The retention options with shorter intervals are processed first " .
@@ -121,7 +133,8 @@ my $defaultData = {
            optional => 1,
        },
        maxfiles => {
-           description => "Maximal number of backup files per VM. Use '0' for unlimted.",
+           description => "Deprecated: use 'prune-backups' instead. " .
+               "Maximal number of backup files per VM. Use '0' for unlimited.",
            type => 'integer',
            minimum => 0,
            optional => 1,
@@ -332,6 +345,10 @@ sub decode_value {
            die "unable to combine 'none' with other content types\n";
        }
 
+       if (scalar(keys $res->%*) == 0 && !$valid_content->{none}) {
+           die "storage does not support content type 'none'\n";
+       }
+
        return $res;
     } elsif ($key eq 'format') {
        my $valid_formats = $def->{format}->[0];
@@ -390,8 +407,15 @@ sub parse_config {
            type => 'dir',
            priority => 0, # force first entry
            path => '/var/lib/vz',
-           maxfiles => 0,
-           content => { images => 1, rootdir => 1, vztmpl => 1, iso => 1, snippets => 1},
+           'prune-backups' => 'keep-all=1',
+           content => {
+               backup => 1,
+               images => 1,
+               iso => 1,
+               rootdir => 1,
+               snippets => 1,
+               vztmpl => 1,
+           },
        };
     }
 
@@ -421,12 +445,13 @@ sub parse_config {
 # Storage implementation
 
 # called during addition of storage (before the new storage config got written)
-# die to abort additon if there are (grave) problems
+# 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) = @_;
 
     # do nothing by default
+    return undef;
 }
 
 # called during storage configuration update (before the updated storage config got written)
@@ -436,6 +461,7 @@ sub on_update_hook {
     my ($class, $storeid, $scfg, %param) = @_;
 
     # do nothing by default
+    return undef;
 }
 
 # called during deletion of storage (before the new storage config got written)
@@ -447,6 +473,7 @@ sub on_delete_hook {
     my ($class, $storeid, $scfg) = @_;
 
     # do nothing by default
+    return undef;
 }
 
 sub cluster_lock_storage {
@@ -526,7 +553,7 @@ sub get_subdir {
 
     my $path = $scfg->{path};
 
-    die "storage definintion has no path\n" if !$path;
+    die "storage definition has no path\n" if !$path;
 
     my $subdir = $vtype_subdirs->{$vtype};
 
@@ -662,7 +689,7 @@ sub clone_image {
     my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_;
 
     # this only works for file based storage types
-    die "storage definintion has no path\n" if !$scfg->{path};
+    die "storage definition has no path\n" if !$scfg->{path};
 
     my ($vtype, $basename, $basevmid, undef, undef, $isBase, $format) =
        $class->parse_volname($volname);
@@ -680,7 +707,7 @@ sub clone_image {
 
     mkpath $imagedir;
 
-    my $name = $class->find_free_diskname($imagedir, $scfg, $vmid, "qcow2", 1);
+    my $name = $class->find_free_diskname($storeid, $scfg, $vmid, "qcow2", 1);
 
     warn "clone $volname: $vtype, $name, $vmid to $name (base=../$basevmid/$basename)\n";
 
@@ -693,7 +720,7 @@ sub clone_image {
        local $CWD = $imagedir;
 
        my $cmd = ['/usr/bin/qemu-img', 'create', '-b', "../$basevmid/$basename",
-                  '-f', 'qcow2', $path];
+                  '-F', $format, '-f', 'qcow2', $path];
 
        run_command($cmd);
     };
@@ -712,7 +739,7 @@ sub alloc_image {
 
     mkpath $imagedir;
 
-    $name = $class->find_free_diskname($imagedir, $scfg, $vmid, $fmt, 1) if !$name;
+    $name = $class->find_free_diskname($storeid, $scfg, $vmid, $fmt, 1) if !$name;
 
     my (undef, $tmpfmt) = parse_name_dir($name);
 
@@ -813,6 +840,18 @@ sub file_size_info {
     return wantarray ? ($size, $format, $used, $parent, $st->ctime) : $size;
 }
 
+sub get_volume_notes {
+    my ($class, $scfg, $storeid, $volname, $timeout) = @_;
+
+    die "volume notes are not supported for $class";
+}
+
+sub update_volume_notes {
+    my ($class, $scfg, $storeid, $volname, $notes, $timeout) = @_;
+
+    die "volume notes are not supported for $class";
+}
+
 sub volume_size_info {
     my ($class, $scfg, $storeid, $volname, $timeout) = @_;
     my $path = $class->filesystem_path($scfg, $volname);
@@ -989,18 +1028,7 @@ my $get_subdir_files = sub {
 
     my $res = [];
 
-    my $has_comment = {};
-
     foreach my $fn (<$path/*>) {
-
-       if (COMMENT_EXT eq substr($fn, -length(COMMENT_EXT))) {
-           my $real_fn = substr($fn, 0, length($fn) -  length(COMMENT_EXT));
-           if (!defined($has_comment->{$real_fn})) {
-               $has_comment->{$real_fn} = (-f $fn);
-           }
-           next; # we do not need to do anything with comments themselves
-       }
-
        my $st = File::stat::stat($fn);
 
        next if (!$st || S_ISDIR($st->mode));
@@ -1018,11 +1046,14 @@ my $get_subdir_files = sub {
            $info = { volid => "$sid:vztmpl/$1", format => "t$2" };
 
        } elsif ($tt eq 'backup') {
-           next if defined($vmid) && $fn !~  m/\S+-$vmid-\S+/;
            next if $fn !~ m!/([^/]+\.(tgz|(?:(?:tar|vma)(?:\.(${\COMPRESSOR_RE}))?)))$!;
            my $original = $fn;
            my $format = $2;
            $fn = $1;
+
+           # only match for VMID now, to avoid false positives (VMID in parent directory name)
+           next if defined($vmid) && $fn !~ m/\S+-$vmid-\S+/;
+
            $info = { volid => "$sid:backup/$fn", format => $format };
 
            my $archive_info = eval { PVE::Storage::archive_info($fn) } // {};
@@ -1033,14 +1064,10 @@ my $get_subdir_files = sub {
                $info->{vmid} = $vmid // $1;
            }
 
-           my $comment_fn = $original.COMMENT_EXT;
-           if (!defined($has_comment->{$original})) {
-               $has_comment->{$original} = (-f $comment_fn);
-           }
-
-           if ($has_comment->{$original}) {
-               my $comment = PVE::Tools::file_read_firstline($comment_fn);
-               $info->{comment} = $comment if defined($comment);
+           my $notes_fn = $original.NOTES_EXT;
+           if (-f $notes_fn) {
+               my $notes = PVE::Tools::file_read_firstline($notes_fn);
+               $info->{notes} = $notes if defined($notes);
            }
 
        } elsif ($tt eq 'snippets') {
@@ -1115,7 +1142,7 @@ sub status {
 
     my $path = $scfg->{path};
 
-    die "storage definintion has no path\n" if !$path;
+    die "storage definition has no path\n" if !$path;
 
     my $timeout = 2;
     my $res = PVE::Tools::df($path, $timeout);
@@ -1139,7 +1166,7 @@ sub activate_storage {
 
     my $path = $scfg->{path};
 
-    die "storage definintion has no path\n" if !$path;
+    die "storage definition has no path\n" if !$path;
 
     # this path test may hang indefinitely on unresponsive mounts
     my $timeout = 2;
@@ -1219,9 +1246,9 @@ sub prune_backups {
 
     foreach my $backup (@{$backups}) {
        my $volid = $backup->{volid};
-       my $backup_vmid = $backup->{vmid};
        my $archive_info = eval { PVE::Storage::archive_info($volid) } // {};
        my $backup_type = $archive_info->{type} // 'unknown';
+       my $backup_vmid = $archive_info->{vmid} // $backup->{vmid};
 
        next if defined($type) && $type ne $backup_type;
 
@@ -1234,6 +1261,10 @@ sub prune_backups {
        $prune_entry->{vmid} = $backup_vmid if defined($backup_vmid);
 
        if ($archive_info->{is_std_name}) {
+           die "internal error - got no VMID\n" if !defined($backup_vmid);
+           die "internal error - got wrong VMID '$backup_vmid' != '$vmid'\n"
+               if defined($vmid) && $backup_vmid ne $vmid;
+
            $prune_entry->{ctime} = $archive_info->{ctime};
            my $group = "$backup_type/$backup_vmid";
            push @{$backup_groups->{$group}}, $prune_entry;