X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=PVE%2FStorage%2FPlugin.pm;h=4a10a1fef93ceec3e9409a157bd2a9351cf95d53;hb=9177cc2eda87c9a8f85a5ba73fa5f8e45cdd44de;hp=a04664049a2b4fdab1b8c131822c74a4d7bcc9f7;hpb=2c036838ed1747dabee1d2c79621c7d398d24c50;p=pve-storage.git diff --git a/PVE/Storage/Plugin.pm b/PVE/Storage/Plugin.pm index a046640..4a10a1f 100644 --- a/PVE/Storage/Plugin.pm +++ b/PVE/Storage/Plugin.pm @@ -19,6 +19,8 @@ use base qw(PVE::SectionConfig); use constant COMPRESSOR_RE => 'gz|lzo|zst'; +use constant NOTES_EXT => ".notes"; + our @COMMON_TAR_FLAGS = qw( --one-file-system -p --sparse --numeric-owner --acls @@ -35,7 +37,9 @@ our @SHARED_STORAGE = ( 'iscsidirect', 'glusterfs', 'zfs', - 'drbd'); + 'drbd', + 'pbs', +); our $MAX_VOLUMES_PER_GUEST = 1024; @@ -50,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 backups.', @@ -82,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'}; - return $keep; + 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 $prune_backups; } register_standard_option('prune-backups', { description => "The retention options with shorter intervals are processed first " . @@ -425,6 +439,7 @@ 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) @@ -434,6 +449,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) @@ -445,6 +461,7 @@ sub on_delete_hook { my ($class, $storeid, $scfg) = @_; # do nothing by default + return undef; } sub cluster_lock_storage { @@ -691,7 +708,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); }; @@ -811,6 +828,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); @@ -988,7 +1017,6 @@ my $get_subdir_files = sub { my $res = []; foreach my $fn (<$path/*>) { - my $st = File::stat::stat($fn); next if (!$st || S_ISDIR($st->mode)); @@ -1006,10 +1034,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) } // {}; @@ -1020,6 +1052,12 @@ my $get_subdir_files = sub { $info->{vmid} = $vmid // $1; } + 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') { $info = { @@ -1196,9 +1234,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; @@ -1211,6 +1249,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;