From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 185DD1FF0C0 for ; Wed, 04 Nov 2026 20:08:01 +0100 (CET) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id BC0B421949; Wed, 04 Nov 2026 20:05:27 +0100 (CET) From: =?UTF-8?q?Michael=20K=C3=B6ppl?= To: pve-devel@lists.proxmox.com Subject: [PATCH e2e-tests 38/38] tests: migration: verify migrating guests in bulk Date: Wed, 4 Nov 2026 20:03:45 +0100 Message-ID: <20261104190345.2573464-39-m.koeppl@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261104190345.2573464-1-m.koeppl@proxmox.com> References: <20261104190345.2573464-1-m.koeppl@proxmox.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1793819037061 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.223 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: Q5HTGVYVVCT2RBM7CBCJEYWNNVHTFBXH X-Message-ID-Hash: Q5HTGVYVVCT2RBM7CBCJEYWNNVHTFBXH X-MailFrom: m.koeppl@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Start a VM and a container that are not Ha-managed on one node and migrate both to another node with a single bulk migration. Check that both run on the target node afterwards. Signed-off-by: Michael Köppl --- tests/pve_bulk_migration.pl | 111 ++++++++++++++++++++++++++++++++++++ tests/testcases.ron | 11 ++++ 2 files changed, 122 insertions(+) create mode 100755 tests/pve_bulk_migration.pl diff --git a/tests/pve_bulk_migration.pl b/tests/pve_bulk_migration.pl new file mode 100755 index 0000000..3b5c493 --- /dev/null +++ b/tests/pve_bulk_migration.pl @@ -0,0 +1,111 @@ +#!/usr/bin/perl + +=head1 NAME + +C - Test migrating several guests between cluster nodes at once. + +=head1 DESCRIPTION + +This testcase starts a VM and a container that are not HA-managed on the first +cluster node and migrates both to the second node in bulk. Afterwards, both must +run on the second node. + +=cut + +use strict; +use warnings; + +use Test::More; + +use lib '.'; +use Proxmox::Test::Helper qw(CONTAINER_TEMPLATE get_pve_instance); +use Proxmox::Test::Testcase; +use Proxmox::Test::Util qw(poll_until); + +my $pve_a = get_pve_instance('pve1-cluster'); +my $pve_b = get_pve_instance('pve2-cluster'); +my $node_a = $pve_a->get_nodename(); +my $node_b = $pve_b->get_nodename(); +my $client = $pve_a->client(); + +my $vmid; +my $ctid; + +# The node and status of a guest according to the cluster resources. +my $resource = sub { + my ($id) = @_; + my $resources = $client->get('/cluster/resources', { type => 'vm' }); + my ($entry) = grep { ($_->{vmid} // 0) == $id } $resources->@*; + return $entry // {}; +}; + +my $wait_for_guest = sub { + my ($id, $node, $timeout) = @_; + poll_until( + sub { + my $entry = $resource->($id); + return ($entry->{node} // '') eq $node && ($entry->{status} // '') eq 'running'; + }, + timeout => $timeout, + interval => 5, + description => "guest $id to run on node $node", + ); +}; + +my $destroy = sub { + my ($type, $id) = @_; + my $node = $resource->($id)->{node}; + $pve_a->destroy_guest_on($node, $type, $id) if defined($node); +}; + +Proxmox::Test::Testcase->new('pve_bulk_migration')->with([{}])->step( + 'start VM and container', + sub { + $vmid = $client->get('/cluster/nextid'); + my $upid = $client->post( + "/nodes/$node_a/qemu", + { vmid => $vmid, name => 'vm-bulk-migrate', memory => 256 }, + ); + $pve_a->task_ok($upid, "created VM $vmid on node $node_a") + or die "creating VM $vmid failed\n"; + $pve_a->start_guest('qemu', $vmid); + + $ctid = $client->get('/cluster/nextid'); + $upid = $client->post( + "/nodes/$node_a/lxc", + { + vmid => $ctid, + ostemplate => CONTAINER_TEMPLATE, + rootfs => 'local-lvm:2', + memory => 256, + unprivileged => 1, + features => 'nesting=1', + hostname => 'ct-bulk-migrate', + }, + ); + $pve_a->task_ok($upid, "created container $ctid on node $node_a") + or die "creating container $ctid failed\n"; + $pve_a->start_guest('lxc', $ctid); + }, + sub { + $destroy->('lxc', $ctid) if defined($ctid); + $destroy->('qemu', $vmid) if defined($vmid); + }, +)->step( + 'migrate guests in bulk', + sub { + my $upid = $client->post( + "/nodes/$node_a/migrateall", + { target => $node_b, vms => "$vmid,$ctid", maxworkers => 2 }, + ); + $pve_a->task_ok($upid, "migrated guests from node $node_a to node $node_b") + or die "bulk migration failed\n"; + + $wait_for_guest->($vmid, $node_b, 60); + pass("VM $vmid runs on node $node_b"); + $wait_for_guest->($ctid, $node_b, 60); + pass("container $ctid runs on node $node_b"); + }, +)->run(); + +done_testing(); diff --git a/tests/testcases.ron b/tests/testcases.ron index 0e4cea0..7522ef2 100644 --- a/tests/testcases.ron +++ b/tests/testcases.ron @@ -304,6 +304,17 @@ TestcaseConfig( ], tag: "ha", ), + Testcase( + name: "pve_bulk_migration", + run: "./tests/pve_bulk_migration.pl", + timeout: 600, + instances: [ + "pve1-cluster", + "pve2-cluster", + "pve3-cluster", + ], + tag: "extended", + ), Testcase( name: "pbs_s3_datastore", run: "./tests/pbs/test_pbs_s3_datastore.pl", -- 2.47.3