* [PATCH test-tools,e2e-tests 0/6] randomly select VMIDs for test
@ 2026-09-17 16:23 Michael Köppl
2026-09-17 16:23 ` [PATCH test-tools 1/6] runner: add vmid-range option for test guest VMIDs Michael Köppl
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Michael Köppl @ 2026-09-17 16:23 UTC (permalink / raw)
To: pve-devel
Instead of using `/cluster/nextid`, VMIDs are randomly selected from a
range (by default from 1000000 to 9999999). This is supposed to make 2
problems that would occur very unlikely:
1) Some tests would fail if multiple guests were created sequentially
because `/cluster/nextid` would return an ID that was already free
after the VM using it had been destroyed, but the cleanup process for
the VM was still running. By randomly selecting, this is vanishingly
unlikely.
2) When multiple test runs run in parallel (e.g. on different nodes of
the same cluster), it could also happen that `/cluster/nextid`
returned the same VMID for both runs, resulting in an error upon
creation of the guest in one of the runs.
The initial plan was to add a lock file in
/etc/pve/priv/proxmox-e2e-tests (or a similarly named dir) for each VMID
currently in use. However, this would not solve the first issue, making
the random selection necessary anyway. In addition, the file lock could
leave behind lock files on a user's test system upon interrupted test
runs.
Thus, the patch series adds a new library function to the test
repository, replaces all uses of `/cluster/nextid` to `random_vmid()` in
the 3 test suites, and adds a runner param for manipulating the range.
proxmox-test-tools:
Michael Köppl (1):
runner: add vmid-range option for test guest VMIDs
README.md | 7 ++-
proxmox-test-runner/src/cli.rs | 28 ++++++++++--
proxmox-test-runner/src/main.rs | 1 +
proxmox-test-runner/src/types.rs | 78 ++++++++++++++++++++++++++++++++
4 files changed, 109 insertions(+), 5 deletions(-)
create mode 100644 proxmox-test-runner/src/types.rs
proxmox-e2e-tests:
Michael Köppl (5):
lib: add function for drawing a random unused VMID
storage-plugin: use random_vmid function for getting VMIDs
hw-validation: use random_vmid function for getting VMIDs
tests: use random_vmid function for getting VMIDs
storage-plugin: README: document the vmid-range option
Proxmox/Test/StorageGuest.pm | 4 +-
Proxmox/Test/Util.pm | 39 ++++++++++++++++++-
hw-validation-tests/tests/kvm_linux.pl | 3 +-
hw-validation-tests/tests/lxc_lifecycle.pl | 3 +-
hw-validation-tests/tests/storage_local.pl | 3 +-
storage-plugin-tests/README | 4 ++
storage-plugin-tests/tests/backup_ct.pl | 4 +-
storage-plugin-tests/tests/backup_restore.pl | 4 +-
storage-plugin-tests/tests/backup_running.pl | 4 +-
storage-plugin-tests/tests/backup_vm.pl | 4 +-
.../tests/cluster_migration.pl | 4 +-
storage-plugin-tests/tests/ct_create.pl | 4 +-
storage-plugin-tests/tests/disk_clone.pl | 6 +--
storage-plugin-tests/tests/disk_migration.pl | 4 +-
storage-plugin-tests/tests/disk_purge.pl | 4 +-
storage-plugin-tests/tests/disk_resize.pl | 4 +-
storage-plugin-tests/tests/disk_snapshot.pl | 6 +--
.../tests/disk_thin_discard.pl | 4 +-
storage-plugin-tests/tests/io_integrity.pl | 4 +-
.../tests/snapshot_volume_chain.pl | 4 +-
.../tests/template_linked_clone.pl | 6 +--
.../tests/vm_additional_disk_vtpm.pl | 4 +-
.../tests/vm_create_default.pl | 4 +-
.../tests/vm_destroy_with_snapshots.pl | 4 +-
storage-plugin-tests/tests/vm_disk_buses.pl | 4 +-
tests/pbs/test_pbs_s3_datastore.pl | 5 ++-
tests/pve_backup_job.pl | 3 +-
tests/pve_create_pool.pl | 3 +-
tests/pve_create_vm.pl | 4 +-
tests/pve_firewall.pl | 4 +-
tests/pve_ha_resource_config.pl | 3 +-
tests/pve_ha_resource_state.pl | 4 +-
tests/pve_ha_rules_config.pl | 5 ++-
tests/pve_ha_status.pl | 3 +-
tests/pve_migration.pl | 4 +-
tests/pve_replication.pl | 3 +-
tests/pve_storage_basic.pl | 3 +-
37 files changed, 116 insertions(+), 66 deletions(-)
Summary over all repositories:
41 files changed, 225 insertions(+), 71 deletions(-)
--
Generated by murpp 0.12.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH test-tools 1/6] runner: add vmid-range option for test guest VMIDs
2026-09-17 16:23 [PATCH test-tools,e2e-tests 0/6] randomly select VMIDs for test Michael Köppl
@ 2026-09-17 16:23 ` Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 2/6] lib: add function for drawing a random unused VMID Michael Köppl
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Michael Köppl @ 2026-09-17 16:23 UTC (permalink / raw)
To: pve-devel
Test cases draw the VMIDs of the guests they create at random from a
large range, which makes it unlikely that two runs against one cluster
pick the same id, or that a just freed id, which a cleanup task may
still hold a lock on, is reused right away.
Expose that range on the command line, so runs that must not collide
can be given disjoint ones instead of relying on chance.
Add it as a global option because every suite draws through the same
helper and any subcommand can end up on a shared cluster. run-local
passes no inventory, so its test cases target the host they run on, and
a run inventory is only a set of addresses, which may name a development
cluster.
Signed-off-by: Michael Köppl <m.koeppl@proxmox.com>
---
README.md | 7 ++-
proxmox-test-runner/src/cli.rs | 28 ++++++++++--
proxmox-test-runner/src/main.rs | 1 +
proxmox-test-runner/src/types.rs | 78 ++++++++++++++++++++++++++++++++
4 files changed, 109 insertions(+), 5 deletions(-)
create mode 100644 proxmox-test-runner/src/types.rs
diff --git a/README.md b/README.md
index 9b2f7bc6..d9bc8aa6 100644
--- a/README.md
+++ b/README.md
@@ -243,8 +243,11 @@ testcase file first and can be started from anywhere.
All subcommands accept the global options `--report <path>` and
`--report-format text|json|junit|markdown` to write a report file, `--suite-version` to record
the suite version in the report for provenance, `--verbose` to print the entire output of each
-test, and `--tags` to select tests: a comma-separated list of tags replaces the suite's default
-selection, while entries prefixed with `+` add to it (e.g. `--tags +storage-plugin-guest`).
+test, `--tags` to select tests: a comma-separated list of tags replaces the suite's default
+selection, while entries prefixed with `+` add to it (e.g. `--tags +storage-plugin-guest`), and
+`--vmid-range <start>:<end>` to confine the VMIDs of the guests a test case creates. Ideally, give
+concurrent runs against one cluster disjoint ranges so they cannot draw the same ID. Without it
+the test cases draw from `1000000-9999999`.
## proxmox-test-scheduler
diff --git a/proxmox-test-runner/src/cli.rs b/proxmox-test-runner/src/cli.rs
index 5e558b8c..ab0d55ab 100644
--- a/proxmox-test-runner/src/cli.rs
+++ b/proxmox-test-runner/src/cli.rs
@@ -14,6 +14,7 @@ use proxmox_test_common::secrets::SecretResolver;
use crate::config::TestcaseConfig;
use crate::report::{ReportFormat, ReportMeta, report_outcomes, write_report_to_file};
use crate::test_runner::{TestOutcomes, TestRunner};
+use crate::types::VmIdRange;
#[api(
properties: {
@@ -43,6 +44,10 @@ use crate::test_runner::{TestOutcomes, TestRunner};
optional: true,
default: false,
},
+ "vmid-range": {
+ type: VmIdRange,
+ optional: true,
+ },
},
)]
/// Options shared by every subcommand. Registered as a global option group so they are accepted at
@@ -55,6 +60,7 @@ pub struct CommonArgs {
pub suite_version: Option<String>,
pub tags: Option<String>,
pub verbose: bool,
+ pub vmid_range: Option<VmIdRange>,
}
/// The shared options, read back from the CLI environment they were parsed into. Defaults to all
@@ -166,6 +172,21 @@ fn resolve_secrets(secrets: Option<PathBuf>) -> Result<(Option<PathBuf>, SecretR
Ok((path, resolver))
}
+/// Map an explicit VMID range onto the env vars the shared `random_vmid` test helper reads. A
+/// suite given no range falls back to the default of the helper.
+fn vmid_range_env(vmid_range: &Option<VmIdRange>) -> Vec<(String, String)> {
+ let Some(range) = vmid_range else {
+ return Vec::new();
+ };
+ vec![
+ (
+ "PROXMOX_TEST_VMID_RANGE_START".into(),
+ range.start.to_string(),
+ ),
+ ("PROXMOX_TEST_VMID_RANGE_END".into(), range.end.to_string()),
+ ]
+}
+
/// Map the storage-plugin options onto the `PLUGIN_*` env vars the perl test scripts read.
fn build_env(
storage_id: &str,
@@ -221,7 +242,7 @@ fn run_local_suite(
&inventory,
&secret_resolver,
common.verbose,
- Vec::new(),
+ vmid_range_env(&common.vmid_range),
);
let meta = ReportMeta::capture(suite_version, None, None)?;
let outcomes = test_runner.run_tests(&PathBuf::new(), &override_secrets_path, false)?;
@@ -275,7 +296,7 @@ pub fn run(
&test_inventory,
&secret_resolver,
common.verbose,
- Vec::new(),
+ vmid_range_env(&common.vmid_range),
);
let meta = ReportMeta::capture(common.suite_version, None, None)?;
let outcomes = test_runner.run_tests(&inventory, &override_secrets_path, start_instances)?;
@@ -442,7 +463,7 @@ pub fn storage_plugin_validation(
log::log_step("Storage", storage_id);
let inventory = TestInventory::default();
- let extra_env = build_env(
+ let mut extra_env = build_env(
storage_id,
&iso_url,
&backup_fallback_storage,
@@ -450,6 +471,7 @@ pub fn storage_plugin_validation(
&migration_target_node,
&qga_image,
);
+ extra_env.extend(vmid_range_env(&common.vmid_range));
let test_runner = TestRunner::new(
&testcase_cfg,
&inventory,
diff --git a/proxmox-test-runner/src/main.rs b/proxmox-test-runner/src/main.rs
index 72d8cec6..eacb72d0 100644
--- a/proxmox-test-runner/src/main.rs
+++ b/proxmox-test-runner/src/main.rs
@@ -9,6 +9,7 @@ mod cli;
mod config;
mod report;
mod test_runner;
+mod types;
fn main() -> Result<(), Error> {
log::init();
diff --git a/proxmox-test-runner/src/types.rs b/proxmox-test-runner/src/types.rs
new file mode 100644
index 00000000..54b52775
--- /dev/null
+++ b/proxmox-test-runner/src/types.rs
@@ -0,0 +1,78 @@
+use std::str::FromStr;
+
+use anyhow::{Context, Error, bail, format_err};
+use proxmox_schema::{ApiStringFormat, ApiType, Schema, StringSchema};
+use serde::{Deserialize, Serialize};
+
+const VMID_MIN: u32 = 100;
+const VMID_MAX: u32 = 999_999_999;
+
+#[derive(Clone)]
+pub struct VmIdRange {
+ pub start: u32,
+ pub end: u32,
+}
+
+impl ApiType for VmIdRange {
+ const API_SCHEMA: Schema = StringSchema::new(
+ "Range of VMIDs to randomly draw from for test guests, as '<start>:<end>' \
+ with start lower than end",
+ )
+ .format(&ApiStringFormat::VerifyFn(|s| {
+ s.parse::<VmIdRange>().map(drop)
+ }))
+ .schema();
+}
+
+impl FromStr for VmIdRange {
+ type Err = Error;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let (start, end) = s
+ .split_once(':')
+ .ok_or_else(|| format_err!("expected '<start>:<end>', got '{s}'"))?;
+
+ let start: u32 = start
+ .parse()
+ .with_context(|| format!("invalid range start '{start}'"))?;
+
+ let end: u32 = end
+ .parse()
+ .with_context(|| format!("invalid range end '{end}'"))?;
+
+ if start >= end {
+ bail!("range start {start} must be lower than its end {end}");
+ }
+
+ if start < VMID_MIN || end > VMID_MAX {
+ bail!("range must be within {VMID_MIN}..={VMID_MAX}");
+ }
+
+ Ok(Self { start, end })
+ }
+}
+
+impl std::fmt::Display for VmIdRange {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}:{}", self.start, self.end)
+ }
+}
+
+impl Serialize for VmIdRange {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ serializer.collect_str(self)
+ }
+}
+
+impl<'d> Deserialize<'d> for VmIdRange {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'d>,
+ {
+ let s = String::deserialize(deserializer)?;
+ s.parse().map_err(serde::de::Error::custom)
+ }
+}
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH e2e-tests 2/6] lib: add function for drawing a random unused VMID
2026-09-17 16:23 [PATCH test-tools,e2e-tests 0/6] randomly select VMIDs for test Michael Köppl
2026-09-17 16:23 ` [PATCH test-tools 1/6] runner: add vmid-range option for test guest VMIDs Michael Köppl
@ 2026-09-17 16:23 ` Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 3/6] storage-plugin: use random_vmid function for getting VMIDs Michael Köppl
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Michael Köppl @ 2026-09-17 16:23 UTC (permalink / raw)
To: pve-devel
`random_vmid` covers 2 problems:
- selecting a random VMID to avoid cases where /cluster/nextid returns
a VMID that is still locked (e.g. from a cleanup process). So this
mostly covers same-node runs.
- selecting the same VMID on parallel runs on different nodes of the
same cluster. Drawing from a range of 9 million makes two runs
picking the same VMID vanishingly unlikely.
PROXMOX_TEST_VMID_RANGE_START and PROXMOX_TEST_VMID_RANGE_END override
the range, so parallel runs can be given disjoint ranges to rule out a
collision entirely.
Signed-off-by: Michael Köppl <m.koeppl@proxmox.com>
---
Proxmox/Test/Util.pm | 39 +++++++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/Proxmox/Test/Util.pm b/Proxmox/Test/Util.pm
index 9b38924..43efd6b 100644
--- a/Proxmox/Test/Util.pm
+++ b/Proxmox/Test/Util.pm
@@ -3,12 +3,47 @@ use strict;
use warnings FATAL => 'all';
use parent 'Exporter';
-our @EXPORT_OK =
- qw(poll_until retry skip_unsupported skip_prerequisite guest_name node_from_upid backup_target);
+our @EXPORT_OK = qw(random_vmid
+ poll_until
+ retry
+ skip_unsupported
+ skip_prerequisite
+ guest_name
+ node_from_upid
+ backup_target);
use Time::HiRes qw(time sleep);
use Test::More ();
+my ($vmid_range_start_default, $vmid_range_end_default) = (1_000_000, 9_999_999);
+
+# An unused VMID for a test guest, drawn at random from a range above the default next-id range.
+#
+# The VMID selection is random because there are cases where the freshly freed VMID cannot be used
+# right away, e.g. if qmeventd runs `qm cleanup`, holding a lock on the VM config for up to 30
+# seconds, making every guest re-created under the freshly freed VMID run into its own lock timeout.
+# This is of course not a strict guarantee that this cannot happen, but makes it highly unlikely.
+sub random_vmid {
+ my ($client) = @_;
+
+ my $vmid_range_start = $ENV{PROXMOX_TEST_VMID_RANGE_START} // $vmid_range_start_default;
+ my $vmid_range_end = $ENV{PROXMOX_TEST_VMID_RANGE_END} // $vmid_range_end_default;
+
+ my $span = $vmid_range_end - $vmid_range_start + 1;
+
+ for (1 .. 100) {
+ my $vmid = $vmid_range_start + int(rand($span));
+
+ if (!eval { $client->get('/cluster/nextid', { vmid => $vmid }) }) {
+ next;
+ }
+
+ return $vmid;
+ }
+
+ die "could not find a free VMID in range [$vmid_range_start, $vmid_range_end]\n";
+}
+
# Poll $cb until it returns a truthy value or $timeout seconds elapse.
#
# Returns the truthy value. Dies on timeout. Exceptions thrown by $cb are treated as "not ready
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH e2e-tests 3/6] storage-plugin: use random_vmid function for getting VMIDs
2026-09-17 16:23 [PATCH test-tools,e2e-tests 0/6] randomly select VMIDs for test Michael Köppl
2026-09-17 16:23 ` [PATCH test-tools 1/6] runner: add vmid-range option for test guest VMIDs Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 2/6] lib: add function for drawing a random unused VMID Michael Köppl
@ 2026-09-17 16:23 ` Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 4/6] hw-validation: " Michael Köppl
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Michael Köppl @ 2026-09-17 16:23 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Michael Köppl <m.koeppl@proxmox.com>
---
Proxmox/Test/StorageGuest.pm | 4 ++--
storage-plugin-tests/tests/backup_ct.pl | 4 ++--
storage-plugin-tests/tests/backup_restore.pl | 4 ++--
storage-plugin-tests/tests/backup_running.pl | 4 ++--
storage-plugin-tests/tests/backup_vm.pl | 4 ++--
storage-plugin-tests/tests/cluster_migration.pl | 4 ++--
storage-plugin-tests/tests/ct_create.pl | 4 ++--
storage-plugin-tests/tests/disk_clone.pl | 6 +++---
storage-plugin-tests/tests/disk_migration.pl | 4 ++--
storage-plugin-tests/tests/disk_purge.pl | 4 ++--
storage-plugin-tests/tests/disk_resize.pl | 4 ++--
storage-plugin-tests/tests/disk_snapshot.pl | 6 +++---
storage-plugin-tests/tests/disk_thin_discard.pl | 4 ++--
storage-plugin-tests/tests/io_integrity.pl | 4 ++--
storage-plugin-tests/tests/snapshot_volume_chain.pl | 4 ++--
storage-plugin-tests/tests/template_linked_clone.pl | 6 +++---
storage-plugin-tests/tests/vm_additional_disk_vtpm.pl | 4 ++--
storage-plugin-tests/tests/vm_create_default.pl | 4 ++--
storage-plugin-tests/tests/vm_destroy_with_snapshots.pl | 4 ++--
storage-plugin-tests/tests/vm_disk_buses.pl | 4 ++--
20 files changed, 43 insertions(+), 43 deletions(-)
diff --git a/Proxmox/Test/StorageGuest.pm b/Proxmox/Test/StorageGuest.pm
index 055fd8b..d04bf67 100644
--- a/Proxmox/Test/StorageGuest.pm
+++ b/Proxmox/Test/StorageGuest.pm
@@ -4,7 +4,7 @@ use warnings FATAL => 'all';
use Test::More ();
-use Proxmox::Test::Util qw(skip_prerequisite);
+use Proxmox::Test::Util qw(random_vmid skip_prerequisite);
use parent 'Exporter';
our @EXPORT_OK = qw(
@@ -106,7 +106,7 @@ sub boot_storage_guest {
my $client = $pve->client();
my $image = prepared_guest_image();
- my $vmid = $client->get('/cluster/nextid');
+ my $vmid = random_vmid($client);
my $config = {
vmid => $vmid,
name => $opts{name} // 'storage-plugin-guest',
diff --git a/storage-plugin-tests/tests/backup_ct.pl b/storage-plugin-tests/tests/backup_ct.pl
index adc3ec5..b8b4316 100755
--- a/storage-plugin-tests/tests/backup_ct.pl
+++ b/storage-plugin-tests/tests/backup_ct.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_prerequisite guest_name backup_target);
+use Proxmox::Test::Util qw(random_vmid skip_prerequisite guest_name backup_target);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -76,7 +76,7 @@ if (!$template) {
skip_prerequisite("No CT template available; cannot test CT backup on '$storage_id'");
}
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = eval {
$pve->client()->post(
"/nodes/$node/lxc",
diff --git a/storage-plugin-tests/tests/backup_restore.pl b/storage-plugin-tests/tests/backup_restore.pl
index 4a7110e..1d135c3 100755
--- a/storage-plugin-tests/tests/backup_restore.pl
+++ b/storage-plugin-tests/tests/backup_restore.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_prerequisite guest_name backup_target);
+use Proxmox::Test::Util qw(random_vmid skip_prerequisite guest_name backup_target);
use Proxmox::Test::StorageGuest qw(boot_storage_guest guest_write_marker guest_read_marker);
# Verifies a backup restores with data intact: a guest writes a marker, is backed up live,
@@ -55,7 +55,7 @@ eval {
# Destroy the original first, so the restored marker can only come from the archive.
ok($pve->destroy_guest(qemu => $vmid), 'original guest destroyed');
- $restored = $client->get('/cluster/nextid');
+ $restored = random_vmid($client);
my $restore = $client->post(
"/nodes/$node/qemu",
{ vmid => $restored, archive => $archive, storage => $storage_id },
diff --git a/storage-plugin-tests/tests/backup_running.pl b/storage-plugin-tests/tests/backup_running.pl
index d5a3cab..e8bdce9 100755
--- a/storage-plugin-tests/tests/backup_running.pl
+++ b/storage-plugin-tests/tests/backup_running.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_prerequisite guest_name backup_target);
+use Proxmox::Test::Util qw(random_vmid skip_prerequisite guest_name backup_target);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -29,7 +29,7 @@ if (!$content{images}) {
my $backup_target = backup_target($pve, $storage_id, \%content);
diag("Backup target: '$backup_target' (source disk on '$storage_id')");
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = eval {
$pve->client()->post(
"/nodes/$node/qemu",
diff --git a/storage-plugin-tests/tests/backup_vm.pl b/storage-plugin-tests/tests/backup_vm.pl
index 808ad12..8b67178 100755
--- a/storage-plugin-tests/tests/backup_vm.pl
+++ b/storage-plugin-tests/tests/backup_vm.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_prerequisite guest_name backup_target);
+use Proxmox::Test::Util qw(random_vmid skip_prerequisite guest_name backup_target);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -30,7 +30,7 @@ my $backup_target = backup_target($pve, $storage_id, \%content);
diag("Backup target: '$backup_target' (source disk on '$storage_id')");
# Create VM on the plugin storage to back up
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = eval {
$pve->client()->post(
"/nodes/$node/qemu",
diff --git a/storage-plugin-tests/tests/cluster_migration.pl b/storage-plugin-tests/tests/cluster_migration.pl
index b62e396..9c4d80d 100755
--- a/storage-plugin-tests/tests/cluster_migration.pl
+++ b/storage-plugin-tests/tests/cluster_migration.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
use Proxmox::Test::StorageValidation::Util qw(resolve_migration_target_node);
# Verifies that a VM whose disk is on the storage under test can be migrated to another cluster node
@@ -31,7 +31,7 @@ my $shared = $scfg->{shared} ? 1 : 0;
my ($target, $auto_selected) = resolve_migration_target_node($pve);
-my $vmid = $client->get('/cluster/nextid');
+my $vmid = random_vmid($client);
my $upid = $client->post(
"/nodes/$node/qemu",
{
diff --git a/storage-plugin-tests/tests/ct_create.pl b/storage-plugin-tests/tests/ct_create.pl
index ba10f28..7177787 100755
--- a/storage-plugin-tests/tests/ct_create.pl
+++ b/storage-plugin-tests/tests/ct_create.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -70,7 +70,7 @@ if (!$template) {
skip_prerequisite("No CT template available; cannot test CT on '$storage_id'");
}
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = eval {
$pve->client()->post(
diff --git a/storage-plugin-tests/tests/disk_clone.pl b/storage-plugin-tests/tests/disk_clone.pl
index 7b0772e..2dd76f4 100755
--- a/storage-plugin-tests/tests/disk_clone.pl
+++ b/storage-plugin-tests/tests/disk_clone.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -25,7 +25,7 @@ if (!$content{images}) {
skip_prerequisite("Storage '$storage_id' does not support content type 'images'");
}
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = eval {
$pve->client()->post(
@@ -49,7 +49,7 @@ ok(defined($upid), "source VM creation task started") or do {
$pve->task_ok($upid, "source VM created");
# Try a full clone onto the same storage.
-my $clone_vmid = $pve->client()->get("/cluster/nextid");
+my $clone_vmid = random_vmid($pve->client());
my $clone_upid = eval {
$pve->client()->post(
"/nodes/$node/qemu/$vmid/clone",
diff --git a/storage-plugin-tests/tests/disk_migration.pl b/storage-plugin-tests/tests/disk_migration.pl
index 8e5a869..7f251a4 100755
--- a/storage-plugin-tests/tests/disk_migration.pl
+++ b/storage-plugin-tests/tests/disk_migration.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
# Verifies that a VM disk can be moved off the storage and back onto it, both offline and while the
# VM is running. This exercises the volume export/import path the plugin must implement for storage
@@ -39,7 +39,7 @@ skip_prerequisite("no second images storage available as a migration target;"
. " pass --migration-target-storage")
if !$target;
-my $vmid = $client->get('/cluster/nextid');
+my $vmid = random_vmid($client);
my $upid = $client->post(
"/nodes/$node/qemu",
{
diff --git a/storage-plugin-tests/tests/disk_purge.pl b/storage-plugin-tests/tests/disk_purge.pl
index a6148e6..b10c329 100755
--- a/storage-plugin-tests/tests/disk_purge.pl
+++ b/storage-plugin-tests/tests/disk_purge.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -25,7 +25,7 @@ if (!$content{images}) {
skip_prerequisite("Storage '$storage_id' does not support content type 'images'");
}
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = eval {
$pve->client()->post(
diff --git a/storage-plugin-tests/tests/disk_resize.pl b/storage-plugin-tests/tests/disk_resize.pl
index 0238942..95ac9a3 100755
--- a/storage-plugin-tests/tests/disk_resize.pl
+++ b/storage-plugin-tests/tests/disk_resize.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
# Verifies that a disk on the storage can be grown, both while the VM is stopped and while it is
# running. A storage that cannot resize raises on the resize call; that is reported as unsupported.
@@ -25,7 +25,7 @@ my %content = map { $_ => 1 } split /,/, ($scfg->{content} // '');
skip_prerequisite("storage '$storage_id' does not support content type 'images'")
if !$content{images};
-my $vmid = $client->get('/cluster/nextid');
+my $vmid = random_vmid($client);
my $upid = $client->post(
"/nodes/$node/qemu",
{
diff --git a/storage-plugin-tests/tests/disk_snapshot.pl b/storage-plugin-tests/tests/disk_snapshot.pl
index 8191069..14c027a 100755
--- a/storage-plugin-tests/tests/disk_snapshot.pl
+++ b/storage-plugin-tests/tests/disk_snapshot.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -25,7 +25,7 @@ if (!$content{images}) {
skip_prerequisite("Storage '$storage_id' does not support content type 'images'");
}
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = eval {
$pve->client()->post(
@@ -193,7 +193,7 @@ ok($names{snap1} && $names{snap2}, "snap1 and snap2 still present after rollback
# Clone from snapshot. Try linked clone first. Some plugins only support full clones from
# snapshots, in that case retry with full => 1.
-my $clone_vmid = $pve->client()->get("/cluster/nextid");
+my $clone_vmid = random_vmid($pve->client());
my $clone = sub {
my (%extra) = @_;
return $pve->client()->post(
diff --git a/storage-plugin-tests/tests/disk_thin_discard.pl b/storage-plugin-tests/tests/disk_thin_discard.pl
index ce9f7e6..6aa9bf2 100755
--- a/storage-plugin-tests/tests/disk_thin_discard.pl
+++ b/storage-plugin-tests/tests/disk_thin_discard.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -28,7 +28,7 @@ if (!$content{images}) {
# Allocate a 4 GiB volume and check the storage's 'used' barely grows: a thin/sparse plugin must
# not commit the full size up front. A plugin that preallocates is reported as unsupported.
my $client = $pve->client();
-my $vmid = $client->get("/cluster/nextid");
+my $vmid = random_vmid($client);
my $used_before = $client->get("/nodes/$node/storage/$storage_id/status", {})->{used} // 0;
diff --git a/storage-plugin-tests/tests/io_integrity.pl b/storage-plugin-tests/tests/io_integrity.pl
index 9eb5538..2548616 100755
--- a/storage-plugin-tests/tests/io_integrity.pl
+++ b/storage-plugin-tests/tests/io_integrity.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite);
# Verifies that data written to a volume is actually persisted and read back unchanged. Operates on
# the volume's host path, so it only applies to path-backed storages; storages without a usable
@@ -25,7 +25,7 @@ my %content = map { $_ => 1 } split /,/, ($scfg->{content} // '');
skip_prerequisite("storage '$storage_id' does not support content type 'images'")
if !$content{images};
-my $vmid = $client->get('/cluster/nextid');
+my $vmid = random_vmid($client);
my $volid = $client->post(
"/nodes/$node/storage/$storage_id/content",
{ vmid => $vmid, filename => "vm-$vmid-disk-0.raw", size => '64M', format => 'raw' },
diff --git a/storage-plugin-tests/tests/snapshot_volume_chain.pl b/storage-plugin-tests/tests/snapshot_volume_chain.pl
index 8074be7..8212d89 100755
--- a/storage-plugin-tests/tests/snapshot_volume_chain.pl
+++ b/storage-plugin-tests/tests/snapshot_volume_chain.pl
@@ -7,7 +7,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
# Verifies storage-vendor-agnostic snapshots via qcow2 backing chains, which a storage opts into
# with the 'snapshot-as-volume-chain' option. Only meaningful when that option is enabled on the
@@ -28,7 +28,7 @@ skip_prerequisite("storage '$storage_id' does not support content type 'images'"
skip_prerequisite("storage '$storage_id' does not have 'snapshot-as-volume-chain' enabled")
if !$scfg->{'snapshot-as-volume-chain'};
-my $vmid = $client->get('/cluster/nextid');
+my $vmid = random_vmid($client);
my $upid = $client->post(
"/nodes/$node/qemu",
{
diff --git a/storage-plugin-tests/tests/template_linked_clone.pl b/storage-plugin-tests/tests/template_linked_clone.pl
index 5ca43ec..84ac2c1 100755
--- a/storage-plugin-tests/tests/template_linked_clone.pl
+++ b/storage-plugin-tests/tests/template_linked_clone.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
# Verifies that a VM can be turned into a template (create_base) and then linked-cloned from it, so
# the clone shares the base image rather than getting a full copy. A storage that cannot provide a
@@ -25,7 +25,7 @@ my %content = map { $_ => 1 } split /,/, ($scfg->{content} // '');
skip_prerequisite("storage '$storage_id' does not support content type 'images'")
if !$content{images};
-my $vmid = $client->get('/cluster/nextid');
+my $vmid = random_vmid($client);
my $clone_vmid;
my $upid = $client->post(
"/nodes/$node/qemu",
@@ -65,7 +65,7 @@ eval {
# Linked clone (full => 0): must reference the base, not copy it. PVE rejects this on the call
# itself when the storage lacks the clone feature, so a raise here is a capability gap too.
- $clone_vmid = $client->get('/cluster/nextid');
+ $clone_vmid = random_vmid($client);
my $cloned = eval {
$pve->wait_for_task(
$client->post(
diff --git a/storage-plugin-tests/tests/vm_additional_disk_vtpm.pl b/storage-plugin-tests/tests/vm_additional_disk_vtpm.pl
index 2e00cd4..76dc163 100755
--- a/storage-plugin-tests/tests/vm_additional_disk_vtpm.pl
+++ b/storage-plugin-tests/tests/vm_additional_disk_vtpm.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -25,7 +25,7 @@ if (!$content{images}) {
skip_prerequisite("Storage '$storage_id' does not support content type 'images'");
}
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = eval {
$pve->client()->post(
diff --git a/storage-plugin-tests/tests/vm_create_default.pl b/storage-plugin-tests/tests/vm_create_default.pl
index 478dad7..7f033f0 100755
--- a/storage-plugin-tests/tests/vm_create_default.pl
+++ b/storage-plugin-tests/tests/vm_create_default.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -25,7 +25,7 @@ if (!$content{images}) {
skip_prerequisite("Storage '$storage_id' does not support content type 'images'");
}
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = eval {
$pve->client()->post(
diff --git a/storage-plugin-tests/tests/vm_destroy_with_snapshots.pl b/storage-plugin-tests/tests/vm_destroy_with_snapshots.pl
index 0e18bb7..87cb7a8 100755
--- a/storage-plugin-tests/tests/vm_destroy_with_snapshots.pl
+++ b/storage-plugin-tests/tests/vm_destroy_with_snapshots.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name poll_until);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name poll_until);
# Verifies that a VM can be destroyed while snapshots still exist, without deleting them one by one
# first.
@@ -30,7 +30,7 @@ if (!$content{images}) {
skip_prerequisite("Storage '$storage_id' does not support content type 'images'");
}
-my $vmid = $client->get('/cluster/nextid');
+my $vmid = random_vmid($client);
my $upid = eval {
$client->post(
diff --git a/storage-plugin-tests/tests/vm_disk_buses.pl b/storage-plugin-tests/tests/vm_disk_buses.pl
index a8816fc..e3c0953 100755
--- a/storage-plugin-tests/tests/vm_disk_buses.pl
+++ b/storage-plugin-tests/tests/vm_disk_buses.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
-use Proxmox::Test::Util qw(skip_unsupported skip_prerequisite guest_name);
+use Proxmox::Test::Util qw(random_vmid skip_unsupported skip_prerequisite guest_name);
my $storage_id = $ENV{PLUGIN_STORAGE_ID};
if (!$storage_id) {
@@ -35,7 +35,7 @@ my @buses = (
for my $bus (@buses) {
subtest "disk bus: $bus->{label}" => sub {
- my $vmid = $pve->client()->get("/cluster/nextid");
+ my $vmid = random_vmid($pve->client());
my %params = (
vmid => $vmid,
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH e2e-tests 4/6] hw-validation: use random_vmid function for getting VMIDs
2026-09-17 16:23 [PATCH test-tools,e2e-tests 0/6] randomly select VMIDs for test Michael Köppl
` (2 preceding siblings ...)
2026-09-17 16:23 ` [PATCH e2e-tests 3/6] storage-plugin: use random_vmid function for getting VMIDs Michael Köppl
@ 2026-09-17 16:23 ` Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 5/6] tests: " Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 6/6] storage-plugin: README: document the vmid-range option Michael Köppl
5 siblings, 0 replies; 7+ messages in thread
From: Michael Köppl @ 2026-09-17 16:23 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Michael Köppl <m.koeppl@proxmox.com>
---
hw-validation-tests/tests/kvm_linux.pl | 3 ++-
hw-validation-tests/tests/lxc_lifecycle.pl | 3 ++-
hw-validation-tests/tests/storage_local.pl | 3 ++-
3 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/hw-validation-tests/tests/kvm_linux.pl b/hw-validation-tests/tests/kvm_linux.pl
index be43da9..a7e93f2 100755
--- a/hw-validation-tests/tests/kvm_linux.pl
+++ b/hw-validation-tests/tests/kvm_linux.pl
@@ -5,11 +5,12 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
+use Proxmox::Test::Util qw(random_vmid);
my $pve = Proxmox::Test::PVEInstance->new_local();
my $node = $pve->get_nodename();
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
# 6.1 Create Linux VM
my $upid = eval {
diff --git a/hw-validation-tests/tests/lxc_lifecycle.pl b/hw-validation-tests/tests/lxc_lifecycle.pl
index 640721c..27f2f7d 100755
--- a/hw-validation-tests/tests/lxc_lifecycle.pl
+++ b/hw-validation-tests/tests/lxc_lifecycle.pl
@@ -5,11 +5,12 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
+use Proxmox::Test::Util qw(random_vmid);
my $pve = Proxmox::Test::PVEInstance->new_local();
my $node = $pve->get_nodename();
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
# First check if we have any CT templates
my $storage_content =
diff --git a/hw-validation-tests/tests/storage_local.pl b/hw-validation-tests/tests/storage_local.pl
index 5490a88..b5800bb 100755
--- a/hw-validation-tests/tests/storage_local.pl
+++ b/hw-validation-tests/tests/storage_local.pl
@@ -5,6 +5,7 @@ use Test::More;
use lib '..';
use Proxmox::Test::PVEInstance;
+use Proxmox::Test::Util qw(random_vmid);
my $pve = Proxmox::Test::PVEInstance->new_local();
my $node = $pve->get_nodename();
@@ -38,7 +39,7 @@ is($config->{path}, '/var/tmp/hw_validation_testdir', "Local storage created cor
# 5.4 Basic I/O Benchmark (Local) - placeholder for actual dd/fio commands
# Proxmox API doesn't have a direct 'run fio benchmark' endpoint, but we can verify
# the storage is writable by uploading a small test ISO or creating a small VM disk.
-my $vmid = eval { $pve->client()->get("/cluster/nextid", {}) };
+my $vmid = eval { random_vmid($pve->client()) };
if ($vmid) {
# Attempt to allocate disk space
my $volid = eval {
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH e2e-tests 5/6] tests: use random_vmid function for getting VMIDs
2026-09-17 16:23 [PATCH test-tools,e2e-tests 0/6] randomly select VMIDs for test Michael Köppl
` (3 preceding siblings ...)
2026-09-17 16:23 ` [PATCH e2e-tests 4/6] hw-validation: " Michael Köppl
@ 2026-09-17 16:23 ` Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 6/6] storage-plugin: README: document the vmid-range option Michael Köppl
5 siblings, 0 replies; 7+ messages in thread
From: Michael Köppl @ 2026-09-17 16:23 UTC (permalink / raw)
To: pve-devel
Signed-off-by: Michael Köppl <m.koeppl@proxmox.com>
---
tests/pbs/test_pbs_s3_datastore.pl | 5 +++--
tests/pve_backup_job.pl | 3 ++-
tests/pve_create_pool.pl | 3 ++-
tests/pve_create_vm.pl | 4 ++--
tests/pve_firewall.pl | 4 ++--
tests/pve_ha_resource_config.pl | 3 ++-
tests/pve_ha_resource_state.pl | 4 ++--
tests/pve_ha_rules_config.pl | 5 +++--
tests/pve_ha_status.pl | 3 ++-
tests/pve_migration.pl | 4 ++--
tests/pve_replication.pl | 3 ++-
tests/pve_storage_basic.pl | 3 ++-
12 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/tests/pbs/test_pbs_s3_datastore.pl b/tests/pbs/test_pbs_s3_datastore.pl
index a35c6e9..8eb6bab 100755
--- a/tests/pbs/test_pbs_s3_datastore.pl
+++ b/tests/pbs/test_pbs_s3_datastore.pl
@@ -28,6 +28,7 @@ use lib '.';
use Proxmox::Test::Helper qw(get_instance get_pbs_instance get_pve_instance);
use Proxmox::Test::ProxmoxInstance;
use Proxmox::Test::Testcase;
+use Proxmox::Test::Util qw(random_vmid);
my $pve = get_pve_instance('pve1');
my $pbs = get_pbs_instance('pbs1');
@@ -122,7 +123,7 @@ Proxmox::Test::Testcase->new('pbs_s3_datastore')->with([{}])->step(
)->step(
'create dummy VM with two 4 GB disks on PVE',
sub {
- $vmid = $pve->client()->get('/cluster/nextid');
+ $vmid = random_vmid($pve->client());
my $upid = $pve->client()->post(
"/nodes/$node/qemu",
{
@@ -182,7 +183,7 @@ Proxmox::Test::Testcase->new('pbs_s3_datastore')->with([{}])->step(
)->step(
'restore VM on PVE from PBS backup',
sub {
- $restore_vmid = $pve->client()->get('/cluster/nextid');
+ $restore_vmid = random_vmid($pve->client());
my $upid = $pve->client()->post(
"/nodes/$node/qemu",
{
diff --git a/tests/pve_backup_job.pl b/tests/pve_backup_job.pl
index 6ba59eb..c3699e2 100755
--- a/tests/pve_backup_job.pl
+++ b/tests/pve_backup_job.pl
@@ -6,6 +6,7 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
+use Proxmox::Test::Util qw(random_vmid);
# Tests scheduled backup job CRUD and an immediate vzdump run.
#
@@ -23,7 +24,7 @@ my $pve = get_pve_instance('pve1');
my $node = $pve->get_nodename();
# Create a test VM to target with the backup job and the immediate vzdump run.
-my $vmid = $pve->client()->get('/cluster/nextid');
+my $vmid = random_vmid($pve->client());
my $upid = $pve->client()->post(
"/nodes/$node/qemu",
{
diff --git a/tests/pve_create_pool.pl b/tests/pve_create_pool.pl
index fa8b351..e54bf8d 100755
--- a/tests/pve_create_pool.pl
+++ b/tests/pve_create_pool.pl
@@ -6,6 +6,7 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
+use Proxmox::Test::Util qw(random_vmid);
# Tests resource pools end to end: a pool is not just a named config entry, it actually groups
# guests and is reflected in the cluster resource view. Beyond create/update/delete this adds a
@@ -27,7 +28,7 @@ my $res = $client->get("/pools/$pool_id", {});
is($res->{comment}, 'Created by automated test', 'pool created with the given comment');
# Create a VM and actually put it into the pool.
-my $vmid = $client->get('/cluster/nextid');
+my $vmid = random_vmid($client);
my $upid = $client->post("/nodes/$node/qemu", { vmid => $vmid, name => 'e2e-pool-test' });
is($pve->wait_for_task($upid), 'OK', 'test VM created');
diff --git a/tests/pve_create_vm.pl b/tests/pve_create_vm.pl
index 9954b09..3d0ced1 100755
--- a/tests/pve_create_vm.pl
+++ b/tests/pve_create_vm.pl
@@ -6,12 +6,12 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
-use Proxmox::Test::Util qw(poll_until);
+use Proxmox::Test::Util qw(random_vmid poll_until);
use Data::Dumper;
my $instance = get_pve_instance("pve1");
-my $vmid = $instance->client()->get("/cluster/nextid");
+my $vmid = random_vmid($instance->client());
my $upid;
diff --git a/tests/pve_firewall.pl b/tests/pve_firewall.pl
index e1f6ec2..ed4e2fc 100755
--- a/tests/pve_firewall.pl
+++ b/tests/pve_firewall.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
-use Proxmox::Test::Util qw(poll_until);
+use Proxmox::Test::Util qw(random_vmid poll_until);
use Proxmox::Test::SDN qw(CONTAINER_TEMPLATE);
# End-to-end test of the PVE firewall: verifies a rule actually affects the dataplane, rather than
@@ -31,7 +31,7 @@ my $pve = get_pve_instance('pve1');
my $node = $pve->get_nodename();
my $client = $pve->client();
-my $vmid = $client->get('/cluster/nextid');
+my $vmid = random_vmid($client);
my $ct_ip = '10.250.250.10';
my $node_ip = '10.250.250.1';
diff --git a/tests/pve_ha_resource_config.pl b/tests/pve_ha_resource_config.pl
index ffadc64..6bd9348 100755
--- a/tests/pve_ha_resource_config.pl
+++ b/tests/pve_ha_resource_config.pl
@@ -6,6 +6,7 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
+use Proxmox::Test::Util qw(random_vmid);
# Tests HA resource configuration CRUD operations.
#
@@ -19,7 +20,7 @@ my $pve = get_pve_instance('pve1-cluster');
my $node = $pve->get_nodename();
# We need a VM to register as an HA resource. Create a minimal one first.
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = $pve->client()->post("/nodes/localhost/qemu", {
vmid => $vmid,
diff --git a/tests/pve_ha_resource_state.pl b/tests/pve_ha_resource_state.pl
index dddfb79..ab63ca0 100755
--- a/tests/pve_ha_resource_state.pl
+++ b/tests/pve_ha_resource_state.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
-use Proxmox::Test::Util qw(poll_until);
+use Proxmox::Test::Util qw(random_vmid poll_until);
# End-to-end test of HA resource state: verifies the HA stack actually acts on the requested state
# (the CRM/LRM start and stop the managed guest), rather than only checking that the requested
@@ -20,7 +20,7 @@ my $client = $pve->client();
# Create a small VM to be HA-managed. It needs no disk: HA only has to bring the QEMU process up
# for the service to be 'running'.
-my $vmid = $client->get('/cluster/nextid');
+my $vmid = random_vmid($client);
my $upid =
$client->post("/nodes/$node/qemu", { vmid => $vmid, memory => 256, name => 'e2e-ha-test' });
is($pve->wait_for_task($upid), 'OK', 'test VM created');
diff --git a/tests/pve_ha_rules_config.pl b/tests/pve_ha_rules_config.pl
index 88ec3cc..328d55b 100755
--- a/tests/pve_ha_rules_config.pl
+++ b/tests/pve_ha_rules_config.pl
@@ -6,6 +6,7 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
+use Proxmox::Test::Util qw(random_vmid);
# Based on the following simulation test scenarios:
# test-node-affinity-strict1/2: node-affinity with strict=1
@@ -18,11 +19,11 @@ my $pve = get_pve_instance('pve1-cluster');
my $node = $pve->get_nodename();
# Create two test VMs to use as HA resources
-my $vmid1 = $pve->client()->get("/cluster/nextid");
+my $vmid1 = random_vmid($pve->client());
my $upid = $pve->client()->post("/nodes/localhost/qemu", { vmid => $vmid1 });
is($pve->wait_for_task($upid), "OK", "VM created successfully");
-my $vmid2 = $pve->client()->get("/cluster/nextid");
+my $vmid2 = random_vmid($pve->client());
$upid = $pve->client()->post("/nodes/localhost/qemu", { vmid => $vmid2 });
is($pve->wait_for_task($upid), "OK", "VM created successfully");
diff --git a/tests/pve_ha_status.pl b/tests/pve_ha_status.pl
index f4b4444..8e789e5 100755
--- a/tests/pve_ha_status.pl
+++ b/tests/pve_ha_status.pl
@@ -6,6 +6,7 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
+use Proxmox::Test::Util qw(random_vmid);
# Tests the HA status API endpoints.
#
@@ -59,7 +60,7 @@ if ($lrm_entry) {
# Service appears in status after registration
-my $vmid = $pve->client()->get("/cluster/nextid");
+my $vmid = random_vmid($pve->client());
my $upid = $pve->client()->post("/nodes/localhost/qemu", { vmid => $vmid });
is($pve->wait_for_task($upid), "OK", "test VM created");
diff --git a/tests/pve_migration.pl b/tests/pve_migration.pl
index 5e0fe60..3997eda 100755
--- a/tests/pve_migration.pl
+++ b/tests/pve_migration.pl
@@ -6,7 +6,7 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
-use Proxmox::Test::Util qw(poll_until);
+use Proxmox::Test::Util qw(random_vmid poll_until);
# Tests offline and online (live) migration of a guest between two cluster nodes.
#
@@ -43,7 +43,7 @@ my $on_node = sub {
return scalar(grep { $_->{vmid} == $vmid } @$list) > 0;
};
-my $vmid = $a->client()->get('/cluster/nextid');
+my $vmid = random_vmid($a->client());
# Create a small VM on node A. No disks on shared storage, so the offline migration moves the
# guest config; an online migration of a diskless VM exercises the live-migration code path.
diff --git a/tests/pve_replication.pl b/tests/pve_replication.pl
index 158828d..0021dac 100755
--- a/tests/pve_replication.pl
+++ b/tests/pve_replication.pl
@@ -7,6 +7,7 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
use Proxmox::Test::Testcase;
+use Proxmox::Test::Util qw(random_vmid);
# Tests storage replication job CRUD between two cluster nodes.
#
@@ -52,7 +53,7 @@ my $job_id;
Proxmox::Test::Testcase->new('pve_replication')->with([{}])->step(
'create ZFS-backed VM on node A',
sub {
- $vmid = $a->client()->get('/cluster/nextid');
+ $vmid = random_vmid($a->client());
my $upid = $a->client()->post(
"/nodes/$node_a/qemu",
{
diff --git a/tests/pve_storage_basic.pl b/tests/pve_storage_basic.pl
index 6c17e28..50a7d9d 100755
--- a/tests/pve_storage_basic.pl
+++ b/tests/pve_storage_basic.pl
@@ -6,6 +6,7 @@ use Test::More;
use lib '.';
use Proxmox::Test::Helper qw(get_pve_instance);
+use Proxmox::Test::Util qw(random_vmid);
# Tests storage end to end: a newly defined storage must actually be usable, so this allocates a
# real volume on it and verifies the volume shows up in (and can be freed from) the storage
@@ -40,7 +41,7 @@ is($client->get("/storage/$storage_id", {})->{path}, '/var/tmp/testdir1', 'stora
eval {
# Allocate a real disk image on the new storage.
- my $vmid = $client->get('/cluster/nextid');
+ my $vmid = random_vmid($client);
my $volid = $client->post(
"/nodes/$node/storage/$storage_id/content",
{
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH e2e-tests 6/6] storage-plugin: README: document the vmid-range option
2026-09-17 16:23 [PATCH test-tools,e2e-tests 0/6] randomly select VMIDs for test Michael Köppl
` (4 preceding siblings ...)
2026-09-17 16:23 ` [PATCH e2e-tests 5/6] tests: " Michael Köppl
@ 2026-09-17 16:23 ` Michael Köppl
5 siblings, 0 replies; 7+ messages in thread
From: Michael Köppl @ 2026-09-17 16:23 UTC (permalink / raw)
To: pve-devel
proxmox-test-runner exposes the range the tests draw their guest VMIDs
from, so list it with the other options a run may need. Concurrent runs
against one cluster can entirely avoid collisions through disjoint
ranges.
Signed-off-by: Michael Köppl <m.koeppl@proxmox.com>
---
storage-plugin-tests/README | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/storage-plugin-tests/README b/storage-plugin-tests/README
index 5f486a4..fe6972d 100644
--- a/storage-plugin-tests/README
+++ b/storage-plugin-tests/README
@@ -36,6 +36,10 @@ Options you may need
from the cluster status when omitted. The tests
are skipped on a node that is not clustered.
--iso-url URL An ISO image URL for the content-download test.
+ --vmid-range START:END Confine the VMIDs of the guests the tests
+ create to this range. Give concurrent runs on
+ one cluster disjoint ranges so they cannot
+ draw the same id. Defaults to 1000000:9999999.
--tags +storage-plugin-guest Also run the guest-based tests (see below).
Guest-based tests
--
2.47.3
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-17 16:24 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-17 16:23 [PATCH test-tools,e2e-tests 0/6] randomly select VMIDs for test Michael Köppl
2026-09-17 16:23 ` [PATCH test-tools 1/6] runner: add vmid-range option for test guest VMIDs Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 2/6] lib: add function for drawing a random unused VMID Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 3/6] storage-plugin: use random_vmid function for getting VMIDs Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 4/6] hw-validation: " Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 5/6] tests: " Michael Köppl
2026-09-17 16:23 ` [PATCH e2e-tests 6/6] storage-plugin: README: document the vmid-range option Michael Köppl
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.