Compare commits

...

10 Commits

Author SHA1 Message Date
7fcf6e29bf add pmem support 2025-12-14 18:13:32 +02:00
6f49432acc bump version to 9.1.0
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-11-20 14:59:46 +01:00
28268eabaa pbs: move api-token detection into own local sub method
for better encapsulation.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-11-20 14:55:54 +01:00
d11122d7f9 pbs: reduce line-bloat, improve variable names
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-11-20 14:48:28 +01:00
80770ef49e fix #6900: correctly detect PBS API tokens in storage plugin
The PBS storage plugin used PVE code to detect if an API token was
entered in the username field. This lead to bad requests for some
valid PBS tokens which are not valid PVE tokens. Examples are
"root@pam!1234" and "root@pam!_-".

Relax the token pattern to allow token names and realms that start
with numbers or underscores. Also allow single character token names,
which are allowed on the backend even though they can't be created
through the PBS Web UI.

Signed-off-by: Robert Obkircher <r.obkircher@proxmox.com>
Link: https://lore.proxmox.com/20251120131149.147981-1-r.obkircher@proxmox.com
2025-11-20 14:42:24 +01:00
5001f03269 lvm plugin: fix locking for rollback when using CLI
Doing a rollback via CLI on an LVM storage with 'saferemove' and
'snapshot-as-volume-chain' would run into a locking issue, because
the forked zero-out worker would try to acquire the lock while the
main CLI task is still inside the locked section for
volume_snapshot_rollback_locked(). The same issue does not happen when
the rollback is done via UI. The reason for this can be found in the
note regarding fork_worker():

> we simulate running in foreground if ($self->{type} eq 'cli')

So the worker will be awaited synchronously in CLI context, resulting
in the deadlock, while via API/UI, the main task would move on and
release the lock allowing the zero-out worker to acquire it.

Avoid doing fork_cleanup_worker() inside the locked section to avoid
the issue.

Fixes: 8eabcc7 ("lvm plugin: snapshot-as-volume-chain: use locking for snapshot operations")
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Reviewed-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Link: https://lore.proxmox.com/20251120101742.24843-1-f.ebner@proxmox.com
2025-11-20 14:41:57 +01:00
bb958344ec plugin: import/export formats: fix regression to unbreak import/export of 'images' content
In particular, this affects offline migration of guest volumes.

Reported in the community forum:
https://forum.proxmox.com/threads/176352/

Fixes: 0ba0739 ("plugin: allow volume import of iso, snippets, vztmpl and import")
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Link: https://lore.proxmox.com/all/20251120121304.67944-1-f.ebner@proxmox.com
2025-11-20 14:03:50 +01:00
a52a1ef526 test: add missing test case for .tar container template
Signed-off-by: Filip Schauer <f.schauer@proxmox.com>
Link: https://lore.proxmox.com/20251118114900.62955-1-f.schauer@proxmox.com
2025-11-18 13:00:39 +01:00
035a734463 bump version to 9.0.18
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-11-17 21:54:37 +01:00
c45b9b430a api: oci image pull: unconditionally unlink temporary file on interrupt
It's more robust and cheaper to just always unlink (always one
syscall) and ignore ENOENT compared to stat and optional unlink (two
syscalls worst case).

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
2025-11-17 21:54:37 +01:00
7 changed files with 83 additions and 25 deletions

25
debian/changelog vendored
View File

@ -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
* api: add endpoint to pull OCI images from a OCI registry directly to a

View File

@ -977,8 +977,8 @@ __PACKAGE__->register_method({
local $SIG{INT} = sub {
unlink "$path/$tmp_filename"
or warn "could not cleanup temporary file: $!"
if -e "$path/$tmp_filename";
or $!{ENOENT}
or warn "could not cleanup temporary file: $!";
die "got interrupted by signal\n";
};

View File

@ -561,10 +561,12 @@ sub get_disks {
# - vdX virtIO block device
# - xvdX: xen virtual block device
# - nvmeXnY: nvme devices
# - pmemXsY: pmem devices
# - cciss!cXnY cciss devices
return
if $dev !~ m/^(h|s|x?v)d[a-z]+$/
&& $dev !~ m/^nvme\d+n\d+$/
&& $dev !~ m/^pmem\d+s\d+$/
&& $dev !~ m/^cciss\!c\d+d\d+$/;
my $data = get_udev_info("/sys/block/$dev") // return;

View File

@ -1117,23 +1117,17 @@ sub volume_rollback_is_possible {
}
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];
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 $@;
eval { alloc_snap_image($class, $storeid, $scfg, $volname, $snap) };
my $alloc_err = $@;
fork_cleanup_worker($cleanup_worker);
if ($alloc_err) {
die "can't allocate new volume $volname: $alloc_err\n";
}
die "can't allocate new volume $volname: $@\n" if $@;
return undef;
}
@ -1141,14 +1135,29 @@ my sub volume_snapshot_rollback_locked {
sub volume_snapshot_rollback {
my ($class, $scfg, $storeid, $volname, $snap) = @_;
return $class->cluster_lock_storage(
my $cleanup_worker;
eval {
$class->cluster_lock_storage(
$storeid,
$scfg->{shared},
undef,
sub {
return volume_snapshot_rollback_locked($class, $scfg, $storeid, $volname, $snap);
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 {

View File

@ -701,6 +701,20 @@ my sub snapshot_files_encrypted {
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
# API schema checks and types
my sub pbs_api_connect {
@ -708,13 +722,13 @@ my sub pbs_api_connect {
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)) {
$params->{apitoken} = "PBSAPIToken=${tokenid}:${password}";
if (auth_id_is_api_token($auth_id)) {
$params->{apitoken} = "PBSAPIToken=${auth_id}:${password}";
} else {
$params->{password} = $password;
$params->{username} = $user;
$params->{username} = $auth_id;
}
if (my $fp = $scfg->{fingerprint}) {

View File

@ -2164,7 +2164,7 @@ sub volume_export_formats {
return ();
}
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 ();
}
@ -2277,7 +2277,7 @@ sub volume_import_formats {
return ();
}
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 ();
}

View File

@ -48,6 +48,14 @@ my $tests = [
#
# 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',
volname => 'vztmpl/debian-10.0-standard_10.0-1_amd64.tar.gz',