Compare commits
16 Commits
8ce79d86bb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 9260195baf | |||
| b7e245cecc | |||
| 5a0e5f1b4f | |||
| b328fb1529 | |||
| dcf3cc267a | |||
| 7f5aaac51c | |||
| 7fcf6e29bf | |||
| 6f49432acc | |||
| 28268eabaa | |||
| d11122d7f9 | |||
| 80770ef49e | |||
| 5001f03269 | |||
| bb958344ec | |||
| a52a1ef526 | |||
| 035a734463 | |||
| c45b9b430a |
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
install deps: `apt install build-essential debhelper-compat libtest-mockmodule-perl lintian pve-doc-generator`
|
||||||
|
|
||||||
|
clone repo -> cd repo -> make dinstall
|
||||||
25
debian/changelog
vendored
25
debian/changelog
vendored
@ -1,3 +1,28 @@
|
|||||||
|
libpve-storage-perl (9.1.0) trixie; urgency=medium
|
||||||
|
|
||||||
|
* import/export formats: fix regression for import/export of 'images'
|
||||||
|
content. This affected offline migration of guest volumes.
|
||||||
|
|
||||||
|
* lvm plugin: fix hanging on the storage lock when doing a snapshot rollback
|
||||||
|
through the CLI.
|
||||||
|
|
||||||
|
* fix #6900: accept all API tokens that are valid for Proxmox Backup Server,
|
||||||
|
which is slightly more flexible than the implementation in Proxmox VE.
|
||||||
|
|
||||||
|
-- Proxmox Support Team <support@proxmox.com> Thu, 20 Nov 2025 14:59:42 +0100
|
||||||
|
|
||||||
|
libpve-storage-perl (9.0.18) trixie; urgency=medium
|
||||||
|
|
||||||
|
* api: OCI image download improvements:
|
||||||
|
- use temporary file and only rename to real one if pulling the image
|
||||||
|
finished successfully.
|
||||||
|
- forbid to override existing files.
|
||||||
|
- improve reference regex to allow more safe characters, like e.g. '-',
|
||||||
|
in the image name.
|
||||||
|
- allow one to override the target filename for the image.
|
||||||
|
|
||||||
|
-- Proxmox Support Team <support@proxmox.com> Mon, 17 Nov 2025 21:53:43 +0100
|
||||||
|
|
||||||
libpve-storage-perl (9.0.17) trixie; urgency=medium
|
libpve-storage-perl (9.0.17) trixie; urgency=medium
|
||||||
|
|
||||||
* api: add endpoint to pull OCI images from a OCI registry directly to a
|
* api: add endpoint to pull OCI images from a OCI registry directly to a
|
||||||
|
|||||||
@ -977,8 +977,8 @@ __PACKAGE__->register_method({
|
|||||||
|
|
||||||
local $SIG{INT} = sub {
|
local $SIG{INT} = sub {
|
||||||
unlink "$path/$tmp_filename"
|
unlink "$path/$tmp_filename"
|
||||||
or warn "could not cleanup temporary file: $!"
|
or $!{ENOENT}
|
||||||
if -e "$path/$tmp_filename";
|
or warn "could not cleanup temporary file: $!";
|
||||||
die "got interrupted by signal\n";
|
die "got interrupted by signal\n";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -561,10 +561,13 @@ sub get_disks {
|
|||||||
# - vdX virtIO block device
|
# - vdX virtIO block device
|
||||||
# - xvdX: xen virtual block device
|
# - xvdX: xen virtual block device
|
||||||
# - nvmeXnY: nvme devices
|
# - nvmeXnY: nvme devices
|
||||||
|
# - pmemXsY: pmem devices
|
||||||
# - cciss!cXnY cciss devices
|
# - cciss!cXnY cciss devices
|
||||||
return
|
return
|
||||||
if $dev !~ m/^(h|s|x?v)d[a-z]+$/
|
if $dev !~ m/^(h|s|x?v)d[a-z]+$/
|
||||||
&& $dev !~ m/^nvme\d+n\d+$/
|
&& $dev !~ m/^nvme\d+n\d+$/
|
||||||
|
&& $dev !~ m/^pmem\d+s$/
|
||||||
|
&& $dev !~ m/^pmem\d+$/
|
||||||
&& $dev !~ m/^cciss\!c\d+d\d+$/;
|
&& $dev !~ m/^cciss\!c\d+d\d+$/;
|
||||||
|
|
||||||
my $data = get_udev_info("/sys/block/$dev") // return;
|
my $data = get_udev_info("/sys/block/$dev") // return;
|
||||||
@ -583,6 +586,8 @@ sub get_disks {
|
|||||||
if ($sysdata->{rotational} == 0) {
|
if ($sysdata->{rotational} == 0) {
|
||||||
$type = 'ssd';
|
$type = 'ssd';
|
||||||
$type = 'nvme' if $dev =~ m/^nvme\d+n\d+$/;
|
$type = 'nvme' if $dev =~ m/^nvme\d+n\d+$/;
|
||||||
|
$type = 'PMEM' if $dev =~ m/^pmem\d+s$/;
|
||||||
|
$type = 'PMEM' if $dev =~ m/^pmem\d+$/;
|
||||||
$data->{rpm} = 0;
|
$data->{rpm} = 0;
|
||||||
} elsif ($sysdata->{rotational} == 1) {
|
} elsif ($sysdata->{rotational} == 1) {
|
||||||
if ($data->{rpm} != -1) {
|
if ($data->{rpm} != -1) {
|
||||||
|
|||||||
@ -1117,23 +1117,17 @@ sub volume_rollback_is_possible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
my sub volume_snapshot_rollback_locked {
|
my sub volume_snapshot_rollback_locked {
|
||||||
my ($class, $scfg, $storeid, $volname, $snap) = @_;
|
my ($class, $scfg, $storeid, $volname, $snap, $cleanup_worker) = @_;
|
||||||
|
|
||||||
my $format = ($class->parse_volname($volname))[6];
|
my $format = ($class->parse_volname($volname))[6];
|
||||||
|
|
||||||
die "can't rollback snapshot for '$format' volume\n" if $format ne 'qcow2';
|
die "can't rollback snapshot for '$format' volume\n" if $format ne 'qcow2';
|
||||||
|
|
||||||
my $cleanup_worker = eval { free_snap_image($class, $storeid, $scfg, $volname, 'current'); };
|
$cleanup_worker->$* = eval { free_snap_image($class, $storeid, $scfg, $volname, 'current'); };
|
||||||
die "error deleting snapshot $snap $@\n" if $@;
|
die "error deleting snapshot $snap $@\n" if $@;
|
||||||
|
|
||||||
eval { alloc_snap_image($class, $storeid, $scfg, $volname, $snap) };
|
eval { alloc_snap_image($class, $storeid, $scfg, $volname, $snap) };
|
||||||
my $alloc_err = $@;
|
die "can't allocate new volume $volname: $@\n" if $@;
|
||||||
|
|
||||||
fork_cleanup_worker($cleanup_worker);
|
|
||||||
|
|
||||||
if ($alloc_err) {
|
|
||||||
die "can't allocate new volume $volname: $alloc_err\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
@ -1141,14 +1135,29 @@ my sub volume_snapshot_rollback_locked {
|
|||||||
sub volume_snapshot_rollback {
|
sub volume_snapshot_rollback {
|
||||||
my ($class, $scfg, $storeid, $volname, $snap) = @_;
|
my ($class, $scfg, $storeid, $volname, $snap) = @_;
|
||||||
|
|
||||||
return $class->cluster_lock_storage(
|
my $cleanup_worker;
|
||||||
$storeid,
|
|
||||||
$scfg->{shared},
|
eval {
|
||||||
undef,
|
$class->cluster_lock_storage(
|
||||||
sub {
|
$storeid,
|
||||||
return volume_snapshot_rollback_locked($class, $scfg, $storeid, $volname, $snap);
|
$scfg->{shared},
|
||||||
},
|
undef,
|
||||||
);
|
sub {
|
||||||
|
volume_snapshot_rollback_locked(
|
||||||
|
$class, $scfg, $storeid, $volname, $snap, \$cleanup_worker,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
my $err = $@;
|
||||||
|
|
||||||
|
# Spawn outside of the locked section, because with 'saferemove', the cleanup worker also needs
|
||||||
|
# to obtain the lock, and in CLI context, it will be awaited synchronously, see fork_worker().
|
||||||
|
fork_cleanup_worker($cleanup_worker);
|
||||||
|
|
||||||
|
die $err if $err;
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub volume_snapshot_delete {
|
sub volume_snapshot_delete {
|
||||||
|
|||||||
@ -701,6 +701,20 @@ my sub snapshot_files_encrypted {
|
|||||||
return $any && $all;
|
return $any && $all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my sub auth_id_is_api_token {
|
||||||
|
my ($auth_id) = @_;
|
||||||
|
|
||||||
|
# NOTE: We cannot use the PVE token regexes as we're stricter in PVE, so some tokens that would
|
||||||
|
# be valid for PBS would get rejected. Adapt over the PBS ones from proxmox-auth-api types
|
||||||
|
my $pbs_safe_id_regex = qr/(?:[A-Za-z0-9_][A-Za-z0-9\._\-]*)/;
|
||||||
|
my $pbs_token_name_regex = $pbs_safe_id_regex;
|
||||||
|
my $pbs_user_name_regex = qr/(?:[^\s:\/\p{PosixCntrl}]+)/;
|
||||||
|
my $pbs_user_id_regex = qr/${pbs_user_name_regex}\@${pbs_safe_id_regex}/;
|
||||||
|
my $pbs_apitoken_id_regex = qr/${pbs_user_id_regex}\!${pbs_token_name_regex}/;
|
||||||
|
|
||||||
|
return $auth_id =~ qr/^${pbs_apitoken_id_regex}$/;
|
||||||
|
}
|
||||||
|
|
||||||
# TODO: use a client with native rust/proxmox-backup bindings to profit from
|
# TODO: use a client with native rust/proxmox-backup bindings to profit from
|
||||||
# API schema checks and types
|
# API schema checks and types
|
||||||
my sub pbs_api_connect {
|
my sub pbs_api_connect {
|
||||||
@ -708,13 +722,13 @@ my sub pbs_api_connect {
|
|||||||
|
|
||||||
my $params = {};
|
my $params = {};
|
||||||
|
|
||||||
my $user = $scfg->{username} // 'root@pam';
|
my $auth_id = $scfg->{username} // 'root@pam';
|
||||||
|
|
||||||
if (my $tokenid = PVE::AccessControl::pve_verify_tokenid($user, 1)) {
|
if (auth_id_is_api_token($auth_id)) {
|
||||||
$params->{apitoken} = "PBSAPIToken=${tokenid}:${password}";
|
$params->{apitoken} = "PBSAPIToken=${auth_id}:${password}";
|
||||||
} else {
|
} else {
|
||||||
$params->{password} = $password;
|
$params->{password} = $password;
|
||||||
$params->{username} = $user;
|
$params->{username} = $auth_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (my $fp = $scfg->{fingerprint}) {
|
if (my $fp = $scfg->{fingerprint}) {
|
||||||
|
|||||||
@ -2164,7 +2164,7 @@ sub volume_export_formats {
|
|||||||
return ();
|
return ();
|
||||||
}
|
}
|
||||||
return ('tar+size') if $format eq 'subvol';
|
return ('tar+size') if $format eq 'subvol';
|
||||||
return ('raw+size') if $vtype =~ /^(iso|snippets|vztmpl|import)$/;
|
return ('raw+size') if $vtype =~ /^(images|iso|snippets|vztmpl|import)$/;
|
||||||
}
|
}
|
||||||
return ();
|
return ();
|
||||||
}
|
}
|
||||||
@ -2277,7 +2277,7 @@ sub volume_import_formats {
|
|||||||
return ();
|
return ();
|
||||||
}
|
}
|
||||||
return ('tar+size') if $format eq 'subvol';
|
return ('tar+size') if $format eq 'subvol';
|
||||||
return ('raw+size') if $vtype =~ /^(iso|snippets|vztmpl|import)$/;
|
return ('raw+size') if $vtype =~ /^(images|iso|snippets|vztmpl|import)$/;
|
||||||
}
|
}
|
||||||
return ();
|
return ();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,14 @@ my $tests = [
|
|||||||
#
|
#
|
||||||
# container templates
|
# container templates
|
||||||
#
|
#
|
||||||
|
{
|
||||||
|
description => 'Container template tar',
|
||||||
|
volname => 'vztmpl/debian-10.0-standard_10.0-1_amd64.tar',
|
||||||
|
expected => [
|
||||||
|
'vztmpl', 'debian-10.0-standard_10.0-1_amd64.tar', undef, undef, undef, undef,
|
||||||
|
'raw',
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description => 'Container template tar.gz',
|
description => 'Container template tar.gz',
|
||||||
volname => 'vztmpl/debian-10.0-standard_10.0-1_amd64.tar.gz',
|
volname => 'vztmpl/debian-10.0-standard_10.0-1_amd64.tar.gz',
|
||||||
|
|||||||
Reference in New Issue
Block a user