fix #3307: make it possible to set protection for backups

A protected backup is not removed by free_image and ignored when
pruning.

The protection_file_path function is introduced in Storage.pm, so that
it can also be used by vzdump itself and in archive_remove.

For pruning, renamed backups already behaved similiar to how protected
backups will, but there are a few reasons to not just use that for
implementing the new feature:
1. It wouldn't protect against removal.
2. It would make it necessary to rename notes and log files too.
3. It wouldn't naturally extend to other volumes if that's needed.

Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
This commit is contained in:
Fabian Ebner
2021-09-30 13:42:08 +02:00
committed by Fabian Grünbichler
parent 9a4c0e8471
commit 56897a9203
5 changed files with 87 additions and 9 deletions

View File

@ -5,6 +5,7 @@ use warnings;
use Cwd;
use File::Path;
use IO::File;
use POSIX;
use PVE::Storage::Plugin;
@ -133,6 +134,14 @@ sub get_volume_attribute {
return $class->get_volume_notes($scfg, $storeid, $volname);
}
my ($vtype) = $class->parse_volname($volname);
return if $vtype ne 'backup';
if ($attribute eq 'protected') {
my $path = $class->filesystem_path($scfg, $volname);
return -e PVE::Storage::protection_file_path($path) ? 1 : 0;
}
return;
}
@ -143,6 +152,27 @@ sub update_volume_attribute {
return $class->update_volume_notes($scfg, $storeid, $volname, $value);
}
my ($vtype) = $class->parse_volname($volname);
die "only backups support attribute '$attribute'\n" if $vtype ne 'backup';
if ($attribute eq 'protected') {
my $path = $class->filesystem_path($scfg, $volname);
my $protection_path = PVE::Storage::protection_file_path($path);
return if !((-e $protection_path) xor $value); # protection status already correct
if ($value) {
my $fh = IO::File->new($protection_path, O_CREAT, 0644)
or die "unable to create protection file '$protection_path' - $!\n";
close($fh);
} else {
unlink $protection_path or $! == ENOENT
or die "could not delete protection file '$protection_path' - $!\n";
}
return;
}
die "attribute '$attribute' is not supported for storage type '$scfg->{type}'\n";
}

View 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) {
@ -917,6 +920,7 @@ sub update_volume_notes {
# 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) = @_;
@ -1164,6 +1168,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 = {
@ -1370,6 +1375,8 @@ sub prune_backups {
$prune_entry->{mark} = 'protected';
}
$prune_entry->{mark} = 'protected' if $backup->{protected};
push @{$prune_list}, $prune_entry;
}