diff --git a/PVE/Storage/PBSPlugin.pm b/PVE/Storage/PBSPlugin.pm index 76699e6..06ebfa7 100644 --- a/PVE/Storage/PBSPlugin.pm +++ b/PVE/Storage/PBSPlugin.pm @@ -9,7 +9,8 @@ use Fcntl qw(F_GETFD F_SETFD FD_CLOEXEC); use IO::File; use JSON; use MIME::Base64 qw(decode_base64); -use POSIX qw(strftime ENOENT); +use POSIX qw(mktime strftime ENOENT); +use POSIX::strptime; use PVE::APIClient::LWP; use PVE::JSONSchema qw(get_standard_option); @@ -218,6 +219,36 @@ sub print_volid { return "${storeid}:${volname}"; } +# essentially the inverse of print_volid +sub api_param_from_volname { + my ($class, $volname) = @_; + + my $name = ($class->parse_volname($volname))[1]; + + my ($btype, $bid, $timestr) = split('/', $name); + + my @tm = (POSIX::strptime($timestr, "%FT%TZ")); + # expect sec, min, hour, mday, mon, year + die "error parsing time from '$volname'" if grep { !defined($_) } @tm[0..5]; + + my $btime; + { + local $ENV{TZ} = 'UTC'; # $timestr is UTC + + # Fill in isdst to avoid undef warning. No daylight saving time for UTC. + $tm[8] //= 0; + + my $since_epoch = mktime(@tm) or die "error converting time from '$volname'\n"; + $btime = int($since_epoch); + } + + return { + 'backup-type' => $btype, + 'backup-id' => $bid, + 'backup-time' => $btime, + }; +} + my $USE_CRYPT_PARAMS = { backup => 1, restore => 1, @@ -403,9 +434,12 @@ sub prune_backups { my $vmid = $backup->{'backup-id'}; my $volid = print_volid($storeid, $type, $vmid, $ctime); + my $mark = $backup->{keep} ? 'keep' : 'remove'; + $mark = 'protected' if $backup->{protected}; + push @{$prune_list}, { ctime => $ctime, - mark => $backup->{keep} ? 'keep' : 'remove', + mark => $mark, type => $type eq 'vm' ? 'qemu' : 'lxc', vmid => $vmid, volid => $volid, @@ -658,6 +692,7 @@ sub list_volumes { $info->{verification} = $item->{verification} if defined($item->{verification}); $info->{notes} = $item->{comment} if defined($item->{comment}); + $info->{protected} = 1 if $item->{protected}; if (defined($item->{fingerprint})) { $info->{encrypted} = $item->{fingerprint}; } elsif (snapshot_files_encrypted($item->{files})) { @@ -813,6 +848,21 @@ sub get_volume_attribute { return $class->get_volume_notes($scfg, $storeid, $volname); } + if ($attribute eq 'protected') { + my $param = $class->api_param_from_volname($volname); + + my $password = pbs_get_password($scfg, $storeid); + my $conn = pbs_api_connect($scfg, $password); + my $datastore = $scfg->{datastore}; + + my $res = eval { $conn->get("/api2/json/admin/datastore/$datastore/$attribute", $param); }; + if (my $err = $@) { + return if $err->{code} == 404; # not supported + die $err; + } + return $res; + } + return; } @@ -823,6 +873,18 @@ sub update_volume_attribute { return $class->update_volume_notes($scfg, $storeid, $volname, $value); } + if ($attribute eq 'protected') { + my $param = $class->api_param_from_volname($volname); + $param->{$attribute} = $value; + + my $password = pbs_get_password($scfg, $storeid); + my $conn = pbs_api_connect($scfg, $password); + my $datastore = $scfg->{datastore}; + + $conn->put("/api2/json/admin/datastore/$datastore/$attribute", $param); + return; + } + die "attribute '$attribute' is not supported for storage type '$scfg->{type}'\n"; } diff --git a/debian/control b/debian/control index c39a5ab..a1a8c57 100644 --- a/debian/control +++ b/debian/control @@ -4,6 +4,7 @@ Priority: optional Maintainer: Proxmox Support Team Build-Depends: debhelper (>= 12~), libfile-chdir-perl, + libposix-strptime-perl, libpve-cluster-perl, libpve-common-perl (>= 6.3-2), librados2-perl, @@ -30,6 +31,7 @@ Depends: ceph-common (>= 12.2~), cstream, glusterfs-client (>= 3.4.0-2), libfile-chdir-perl, + libposix-strptime-perl, libpve-apiclient-perl (>= 3.1-1), libpve-cluster-perl, libpve-common-perl (>= 6.4-1),