]> git.proxmox.com Git - qemu-server.git/blob - test/run_qemu_migrate_tests.pl
schema: fix description of migrate_downtime parameter
[qemu-server.git] / test / run_qemu_migrate_tests.pl
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use JSON;
7 use Test::More;
8 use Test::MockModule;
9
10 use PVE::JSONSchema;
11 use PVE::Tools qw(file_set_contents file_get_contents run_command);
12
13 my $QM_LIB_PATH = '..';
14 my $MIGRATE_LIB_PATH = '..';
15 my $RUN_DIR_PATH = './MigrationTest/run/';
16
17 # test configuration shared by all tests
18
19 my $replication_config = {
20 'ids' => {
21 '105-0' => {
22 'guest' => '105',
23 'id' => '105-0',
24 'jobnum' => '0',
25 'source' => 'pve0',
26 'target' => 'pve2',
27 'type' => 'local'
28 },
29 },
30 'order' => {
31 '105-0' => 1,
32 }
33 };
34
35 my $storage_config = {
36 ids => {
37 local => {
38 content => {
39 images => 1,
40 },
41 path => "/var/lib/vz",
42 type => "dir",
43 shared => 0,
44 },
45 "local-lvm" => {
46 content => {
47 images => 1,
48 },
49 nodes => {
50 pve0 => 1,
51 pve1 => 1,
52 },
53 type => "lvmthin",
54 thinpool => "data",
55 vgname => "pve",
56 },
57 "local-zfs" => {
58 content => {
59 images => 1,
60 rootdir => 1,
61 },
62 pool => "rpool/data",
63 sparse => 1,
64 type => "zfspool",
65 },
66 "rbd-store" => {
67 monhost => "127.0.0.42,127.0.0.21,::1",
68 fsid => 'fc4181a6-56eb-4f68-b452-8ba1f381ca2a',
69 content => {
70 images => 1,
71 },
72 type => "rbd",
73 pool => "cpool",
74 username => "admin",
75 shared => 1,
76 },
77 "local-dir" => {
78 content => {
79 images => 1,
80 },
81 path => "/some/dir/",
82 type => "dir",
83 },
84 "other-dir" => {
85 content => {
86 images => 1,
87 },
88 path => "/some/other/dir/",
89 type => "dir",
90 },
91 "zfs-alias-1" => {
92 content => {
93 images => 1,
94 rootdir => 1,
95 },
96 pool => "aliaspool",
97 sparse => 1,
98 type => "zfspool",
99 },
100 "zfs-alias-2" => {
101 content => {
102 images => 1,
103 rootdir => 1,
104 },
105 pool => "aliaspool",
106 sparse => 1,
107 type => "zfspool",
108 },
109 },
110 };
111
112 my $vm_configs = {
113 105 => {
114 'bootdisk' => 'scsi0',
115 'cores' => 1,
116 'ide0' => 'local-zfs:vm-105-disk-1,size=103M',
117 'ide2' => 'none,media=cdrom',
118 'memory' => 512,
119 'name' => 'Copy-of-VM-newapache',
120 'net0' => 'virtio=4A:A3:E4:4C:CF:F0,bridge=vmbr0,firewall=1',
121 'numa' => 0,
122 'ostype' => 'l26',
123 'parent' => 'ohsnap',
124 'pending' => {},
125 'scsi0' => 'local-zfs:vm-105-disk-0,size=4G',
126 'scsihw' => 'virtio-scsi-pci',
127 'smbios1' => 'uuid=1ddfe18b-77e0-47f6-a4bd-f1761bf6d763',
128 'snapshots' => {
129 'ohsnap' => {
130 'bootdisk' => 'scsi0',
131 'cores' => 1,
132 'ide2' => 'none,media=cdrom',
133 'memory' => 512,
134 'name' => 'Copy-of-VM-newapache',
135 'net0' => 'virtio=4A:A3:E4:4C:CF:F0,bridge=vmbr0,firewall=1',
136 'numa' => 0,
137 'ostype' => 'l26',
138 'scsi0' => 'local-zfs:vm-105-disk-0,size=4G',
139 'scsihw' => 'virtio-scsi-pci',
140 'smbios1' => 'uuid=1ddfe18b-77e0-47f6-a4bd-f1761bf6d763',
141 'snaptime' => 1580976924,
142 'sockets' => 1,
143 'startup' => 'order=2',
144 'vmgenid' => '4eb1d535-9381-4ddc-a8aa-af50c4d9177b'
145 },
146 },
147 'sockets' => 1,
148 'startup' => 'order=2',
149 'vmgenid' => '4eb1d535-9381-4ddc-a8aa-af50c4d9177b',
150 },
151 111 => {
152 'bootdisk' => 'scsi0',
153 'cores' => 1,
154 'ide0' => 'local-lvm:vm-111-disk-0,size=4096M',
155 'ide2' => 'none,media=cdrom',
156 'memory' => 512,
157 'name' => 'pending-test',
158 'net0' => 'virtio=4A:A3:E4:4C:CF:F0,bridge=vmbr0,firewall=1',
159 'numa' => 0,
160 'ostype' => 'l26',
161 'pending' => {
162 'scsi0' => 'local-zfs:vm-111-disk-0,size=103M',
163 },
164 'scsihw' => 'virtio-scsi-pci',
165 'snapshots' => {},
166 'smbios1' => 'uuid=5ad71d4d-8f73-4377-853e-2d22c10c96a5',
167 'sockets' => 1,
168 'vmgenid' => '2c00c030-0b5b-4988-a371-6ab259893f22',
169 },
170 123 => {
171 'bootdisk' => 'scsi0',
172 'cores' => 1,
173 'scsi0' => 'zfs-alias-1:vm-123-disk-0,size=4096M',
174 'scsi1' => 'zfs-alias-2:vm-123-disk-0,size=4096M',
175 'ide2' => 'none,media=cdrom',
176 'memory' => 512,
177 'name' => 'alias-test',
178 'net0' => 'virtio=4A:A3:E4:4C:CF:F0,bridge=vmbr0,firewall=1',
179 'numa' => 0,
180 'ostype' => 'l26',
181 'pending' => {},
182 'scsihw' => 'virtio-scsi-pci',
183 'snapshots' => {},
184 'smbios1' => 'uuid=5ad71d4d-8f73-4377-853e-2d22c10c96a5',
185 'sockets' => 1,
186 'vmgenid' => '2c00c030-0b5b-4988-a371-6ab259893f22',
187 },
188 149 => {
189 'agent' => '0',
190 'bootdisk' => 'scsi0',
191 'cores' => 1,
192 'hotplug' => 'disk,network,usb,memory,cpu',
193 'ide2' => 'none,media=cdrom',
194 'memory' => 4096,
195 'name' => 'asdf',
196 'net0' => 'virtio=52:5D:7E:62:85:97,bridge=vmbr1',
197 'numa' => 1,
198 'ostype' => 'l26',
199 'scsi0' => 'local-lvm:vm-149-disk-0,format=raw,size=4G',
200 'scsi1' => 'local-dir:149/vm-149-disk-0.qcow2,format=qcow2,size=1G',
201 'scsihw' => 'virtio-scsi-pci',
202 'snapshots' => {},
203 'smbios1' => 'uuid=e980bd43-a405-42e2-b5f4-31efe6517460',
204 'sockets' => 1,
205 'startup' => 'order=2',
206 'vmgenid' => '36c6c50c-6ef5-4adc-9b6f-6ba9c8071db0',
207 },
208 341 => {
209 'arch' => 'aarch64',
210 'bootdisk' => 'scsi0',
211 'cores' => 1,
212 'efidisk0' => 'local-lvm:vm-341-disk-0',
213 'ide2' => 'none,media=cdrom',
214 'ipconfig0' => 'ip=103.214.69.10/25,gw=103.214.69.1',
215 'memory' => 4096,
216 'name' => 'VM1033',
217 'net0' => 'virtio=4E:F1:82:6D:D7:4B,bridge=vmbr0,firewall=1,rate=10',
218 'numa' => 0,
219 'ostype' => 'l26',
220 'scsi0' => 'rbd-store:vm-341-disk-0,size=1G',
221 'scsihw' => 'virtio-scsi-pci',
222 'snapshots' => {},
223 'smbios1' => 'uuid=e01e4c73-46f1-47c8-af79-288fdf6b7462',
224 'sockets' => 2,
225 'vmgenid' => 'af47c000-eb0c-48e8-8991-ca4593cd6916',
226 },
227 1033 => {
228 'bootdisk' => 'scsi0',
229 'cores' => 1,
230 'ide0' => 'rbd-store:vm-1033-cloudinit,media=cdrom,size=4M',
231 'ide2' => 'none,media=cdrom',
232 'ipconfig0' => 'ip=103.214.69.10/25,gw=103.214.69.1',
233 'memory' => 4096,
234 'name' => 'VM1033',
235 'net0' => 'virtio=4E:F1:82:6D:D7:4B,bridge=vmbr0,firewall=1,rate=10',
236 'numa' => 0,
237 'ostype' => 'l26',
238 'scsi0' => 'rbd-store:vm-1033-disk-1,size=1G',
239 'scsihw' => 'virtio-scsi-pci',
240 'snapshots' => {},
241 'smbios1' => 'uuid=e01e4c73-46f1-47c8-af79-288fdf6b7462',
242 'sockets' => 2,
243 'vmgenid' => 'af47c000-eb0c-48e8-8991-ca4593cd6916',
244 },
245 4567 => {
246 'bootdisk' => 'scsi0',
247 'cores' => 1,
248 'ide2' => 'none,media=cdrom',
249 'memory' => 512,
250 'name' => 'snapme',
251 'net0' => 'virtio=A6:D1:F1:EB:7B:C2,bridge=vmbr0,firewall=1',
252 'numa' => 0,
253 'ostype' => 'l26',
254 'parent' => 'snap1',
255 'pending' => {},
256 'scsi0' => 'local-dir:4567/vm-4567-disk-0.qcow2,size=4G',
257 'scsihw' => 'virtio-scsi-pci',
258 'smbios1' => 'uuid=2925fdec-a066-4228-b46b-eef8662f5e74',
259 'snapshots' => {
260 'snap1' => {
261 'bootdisk' => 'scsi0',
262 'cores' => 1,
263 'ide2' => 'none,media=cdrom',
264 'memory' => 512,
265 'name' => 'snapme',
266 'net0' => 'virtio=A6:D1:F1:EB:7B:C2,bridge=vmbr0,firewall=1',
267 'numa' => 0,
268 'ostype' => 'l26',
269 'runningcpu' => 'kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep',
270 'runningmachine' => 'pc-i440fx-5.0+pve0',
271 'scsi0' => 'local-dir:4567/vm-4567-disk-0.qcow2,size=4G',
272 'scsihw' => 'virtio-scsi-pci',
273 'smbios1' => 'uuid=2925fdec-a066-4228-b46b-eef8662f5e74',
274 'snaptime' => 1595928799,
275 'sockets' => 1,
276 'startup' => 'order=2',
277 'vmgenid' => '932b227a-8a39-4ede-955a-dbd4bc4385ed',
278 'vmstate' => 'local-dir:4567/vm-4567-state-snap1.raw',
279 },
280 'snap2' => {
281 'bootdisk' => 'scsi0',
282 'cores' => 1,
283 'ide2' => 'none,media=cdrom',
284 'memory' => 512,
285 'name' => 'snapme',
286 'net0' => 'virtio=A6:D1:F1:EB:7B:C2,bridge=vmbr0,firewall=1',
287 'numa' => 0,
288 'ostype' => 'l26',
289 'parent' => 'snap1',
290 'runningcpu' => 'kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep',
291 'runningmachine' => 'pc-i440fx-5.0+pve0',
292 'scsi0' => 'local-dir:4567/vm-4567-disk-0.qcow2,size=4G',
293 'scsi1' => 'local-zfs:vm-4567-disk-0,size=1G',
294 'scsihw' => 'virtio-scsi-pci',
295 'smbios1' => 'uuid=2925fdec-a066-4228-b46b-eef8662f5e74',
296 'snaptime' => 1595928871,
297 'sockets' => 1,
298 'startup' => 'order=2',
299 'vmgenid' => '932b227a-8a39-4ede-955a-dbd4bc4385ed',
300 'vmstate' => 'local-dir:4567/vm-4567-state-snap2.raw',
301 },
302 },
303 'sockets' => 1,
304 'startup' => 'order=2',
305 'unused0' => 'local-zfs:vm-4567-disk-0',
306 'vmgenid' => 'e698e60c-9278-4dd9-941f-416075383f2a',
307 },
308 };
309
310 my $source_vdisks = {
311 'local-dir' => [
312 {
313 'ctime' => 1589439681,
314 'format' => 'qcow2',
315 'parent' => undef,
316 'size' => 1073741824,
317 'used' => 335872,
318 'vmid' => '149',
319 'volid' => 'local-dir:149/vm-149-disk-0.qcow2',
320 },
321 {
322 'ctime' => 1595928898,
323 'format' => 'qcow2',
324 'parent' => undef,
325 'size' => 4294967296,
326 'used' => 1811664896,
327 'vmid' => '4567',
328 'volid' => 'local-dir:4567/vm-4567-disk-0.qcow2',
329 },
330 {
331 'ctime' => 1595928800,
332 'format' => 'raw',
333 'parent' => undef,
334 'size' => 274666496,
335 'used' => 274669568,
336 'vmid' => '4567',
337 'volid' => 'local-dir:4567/vm-4567-state-snap1.raw',
338 },
339 {
340 'ctime' => 1595928872,
341 'format' => 'raw',
342 'parent' => undef,
343 'size' => 273258496,
344 'used' => 273260544,
345 'vmid' => '4567',
346 'volid' => 'local-dir:4567/vm-4567-state-snap2.raw',
347 },
348 ],
349 'local-lvm' => [
350 {
351 'ctime' => '1589277334',
352 'format' => 'raw',
353 'size' => 4294967296,
354 'vmid' => '149',
355 'volid' => 'local-lvm:vm-149-disk-0',
356 },
357 {
358 'ctime' => '1589277334',
359 'format' => 'raw',
360 'size' => 4194304,
361 'vmid' => '341',
362 'volid' => 'local-lvm:vm-341-disk-0',
363 },
364 {
365 'ctime' => '1589277334',
366 'format' => 'raw',
367 'size' => 4294967296,
368 'vmid' => '111',
369 'volid' => 'local-lvm:vm-111-disk-0',
370 },
371 ],
372 'local-zfs' => [
373 {
374 'ctime' => '1589277334',
375 'format' => 'raw',
376 'size' => 4294967296,
377 'vmid' => '105',
378 'volid' => 'local-zfs:vm-105-disk-0',
379 },
380 {
381 'ctime' => '1589277334',
382 'format' => 'raw',
383 'size' => 108003328,
384 'vmid' => '105',
385 'volid' => 'local-zfs:vm-105-disk-1',
386 },
387 {
388 'ctime' => '1589277334',
389 'format' => 'raw',
390 'size' => 108003328,
391 'vmid' => '111',
392 'volid' => 'local-zfs:vm-111-disk-0',
393 },
394 {
395 'format' => 'raw',
396 'name' => 'vm-4567-disk-0',
397 'parent' => undef,
398 'size' => 1073741824,
399 'vmid' => '4567',
400 'volid' => 'local-zfs:vm-4567-disk-0',
401 },
402 ],
403 'rbd-store' => [
404 {
405 'ctime' => '1589277334',
406 'format' => 'raw',
407 'size' => 1073741824,
408 'vmid' => '1033',
409 'volid' => 'rbd-store:vm-1033-disk-1',
410 },
411 {
412 'ctime' => '1589277334',
413 'format' => 'raw',
414 'size' => 1073741824,
415 'vmid' => '1033',
416 'volid' => 'rbd-store:vm-1033-cloudinit',
417 },
418 ],
419 'zfs-alias-1' => [
420 {
421 'ctime' => '1589277334',
422 'format' => 'raw',
423 'size' => 4294967296,
424 'vmid' => '123',
425 'volid' => 'zfs-alias-1:vm-123-disk-0',
426 },
427 ],
428 'zfs-alias-2' => [
429 {
430 'ctime' => '1589277334',
431 'format' => 'raw',
432 'size' => 4294967296,
433 'vmid' => '123',
434 'volid' => 'zfs-alias-2:vm-123-disk-0',
435 },
436 ],
437 };
438
439 my $default_expected_calls_online = {
440 move_config_to_node => 1,
441 ssh_qm_start => 1,
442 vm_stop => 1,
443 };
444
445 my $default_expected_calls_offline = {
446 move_config_to_node => 1,
447 };
448
449 my $replicated_expected_calls_online = {
450 %{$default_expected_calls_online},
451 transfer_replication_state => 1,
452 switch_replication_job_target => 1,
453 };
454
455 my $replicated_expected_calls_offline = {
456 %{$default_expected_calls_offline},
457 transfer_replication_state => 1,
458 switch_replication_job_target => 1,
459 };
460
461 # helpers
462
463 sub get_patched_config {
464 my ($vmid, $patch) = @_;
465
466 my $new_config = { %{$vm_configs->{$vmid}} };
467 patch_config($new_config, $patch) if defined($patch);
468
469 return $new_config;
470 }
471
472 sub patch_config {
473 my ($config, $patch) = @_;
474
475 foreach my $key (keys %{$patch}) {
476 if ($key eq 'snapshots' && defined($patch->{$key})) {
477 my $new_snapshot_configs = {};
478 foreach my $snap (keys %{$patch->{snapshots}}) {
479 my $new_snapshot_config = { %{$config->{snapshots}->{$snap}} };
480 patch_config($new_snapshot_config, $patch->{snapshots}->{$snap});
481 $new_snapshot_configs->{$snap} = $new_snapshot_config;
482 }
483 $config->{snapshots} = $new_snapshot_configs;
484 } elsif (defined($patch->{$key})) {
485 $config->{$key} = $patch->{$key};
486 } else { # use undef value for deletion
487 delete $config->{$key};
488 }
489 }
490 }
491
492 sub local_volids_for_vm {
493 my ($vmid) = @_;
494
495 my $res = {};
496 foreach my $storeid (keys %{$source_vdisks}) {
497 next if $storage_config->{ids}->{$storeid}->{shared};
498 $res = {
499 %{$res},
500 map { $_->{vmid} eq $vmid ? ($_->{volid} => 1) : () } @{$source_vdisks->{$storeid}}
501 };
502 }
503 return $res;
504 }
505
506 my $tests = [
507 # each test consists of the following:
508 # name - unique name for the test which also serves as a dir name.
509 # NOTE: gets passed to make, so don't use whitespace or slash
510 # and adapt buildsys (regex) on code structure changes
511 # target - hostname of target node
512 # vmid - ID of the VM to migrate
513 # opts - options for the migrate() call
514 # target_volids - hash of volids on the target at the beginning
515 # vm_status - hash with running, runningmachine and optionally runningcpu
516 # expected_calls - hash whose keys are calls which are required
517 # to be made if the migration gets far enough
518 # expect_die - expect the migration call to fail, and an error message
519 # matching the specified text in the log
520 # expected - hash consisting of:
521 # source_volids - hash of volids expected on the source
522 # target_volids - hash of volids expected on the target
523 # vm_config - vm configuration hash
524 # vm_status - hash with running, runningmachine and optionally runningcpu
525 {
526 # NOTE get_efivars_size is mocked and returns 128K
527 name => '341_running_efidisk_targetstorage_dir',
528 target => 'pve1',
529 vmid => 341,
530 vm_status => {
531 running => 1,
532 runningmachine => 'pc-q35-5.0+pve0',
533 },
534 opts => {
535 online => 1,
536 'with-local-disks' => 1,
537 targetstorage => 'local-dir',
538 },
539 expected_calls => $default_expected_calls_online,
540 expected => {
541 source_volids => {},
542 target_volids => {
543 'local-dir:341/vm-341-disk-10.raw' => 1,
544 },
545 vm_config => get_patched_config(341, {
546 efidisk0 => 'local-dir:341/vm-341-disk-10.raw,format=raw,size=128K',
547 }),
548 vm_status => {
549 running => 1,
550 runningmachine => 'pc-q35-5.0+pve0',
551 },
552 },
553 },
554 {
555 # NOTE get_efivars_size is mocked and returns 128K
556 name => '341_running_efidisk',
557 target => 'pve1',
558 vmid => 341,
559 vm_status => {
560 running => 1,
561 runningmachine => 'pc-q35-5.0+pve0',
562 },
563 opts => {
564 online => 1,
565 'with-local-disks' => 1,
566 },
567 expected_calls => $default_expected_calls_online,
568 expected => {
569 source_volids => {},
570 target_volids => {
571 'local-lvm:vm-341-disk-10' => 1,
572 },
573 vm_config => get_patched_config(341, {
574 efidisk0 => 'local-lvm:vm-341-disk-10,format=raw,size=128K',
575 }),
576 vm_status => {
577 running => 1,
578 runningmachine => 'pc-q35-5.0+pve0',
579 },
580 },
581 },
582 {
583 name => '149_running_vdisk_alloc_and_pvesm_free_fail',
584 target => 'pve1',
585 vmid => 149,
586 vm_status => {
587 running => 1,
588 runningmachine => 'pc-q35-5.0+pve0',
589 },
590 opts => {
591 online => 1,
592 'with-local-disks' => 1,
593 },
594 fail_config => {
595 vdisk_alloc => 'local-dir:149/vm-149-disk-11.qcow2',
596 pvesm_free => 'local-lvm:vm-149-disk-10',
597 },
598 expected_calls => {},
599 expect_die => "remote command failed with exit code",
600 expected => {
601 source_volids => local_volids_for_vm(149),
602 target_volids => {
603 'local-lvm:vm-149-disk-10' => 1,
604 },
605 vm_config => $vm_configs->{149},
606 vm_status => {
607 running => 1,
608 runningmachine => 'pc-q35-5.0+pve0',
609 },
610 },
611 },
612 {
613 name => '149_running_vdisk_alloc_fail',
614 target => 'pve1',
615 vmid => 149,
616 vm_status => {
617 running => 1,
618 runningmachine => 'pc-q35-5.0+pve0',
619 },
620 opts => {
621 online => 1,
622 'with-local-disks' => 1,
623 },
624 fail_config => {
625 vdisk_alloc => 'local-lvm:vm-149-disk-10',
626 },
627 expected_calls => {},
628 expect_die => "remote command failed with exit code",
629 expected => {
630 source_volids => local_volids_for_vm(149),
631 target_volids => {},
632 vm_config => $vm_configs->{149},
633 vm_status => {
634 running => 1,
635 runningmachine => 'pc-q35-5.0+pve0',
636 },
637 },
638 },
639 {
640 name => '149_vdisk_free_fail',
641 target => 'pve1',
642 vmid => 149,
643 vm_status => {
644 running => 0,
645 },
646 opts => {
647 'with-local-disks' => 1,
648 },
649 fail_config => {
650 'vdisk_free' => 'local-lvm:vm-149-disk-0',
651 },
652 expected_calls => $default_expected_calls_offline,
653 expect_die => "vdisk_free 'local-lvm:vm-149-disk-0' error",
654 expected => {
655 source_volids => {
656 'local-lvm:vm-149-disk-0' => 1,
657 },
658 target_volids => local_volids_for_vm(149),
659 vm_config => $vm_configs->{149},
660 vm_status => {
661 running => 0,
662 },
663 },
664 },
665 {
666 name => '105_replicated_run_replication_fail',
667 target => 'pve2',
668 vmid => 105,
669 vm_status => {
670 running => 0,
671 },
672 target_volids => local_volids_for_vm(105),
673 fail_config => {
674 run_replication => 1,
675 },
676 expected_calls => {},
677 expect_die => 'run_replication error',
678 expected => {
679 source_volids => local_volids_for_vm(105),
680 target_volids => local_volids_for_vm(105),
681 vm_config => $vm_configs->{105},
682 vm_status => {
683 running => 0,
684 },
685 },
686 },
687 {
688 name => '1033_running_query_migrate_fail',
689 target => 'pve2',
690 vmid => 1033,
691 vm_status => {
692 running => 1,
693 runningmachine => 'pc-q35-5.0+pve0',
694 },
695 opts => {
696 online => 1,
697 },
698 fail_config => {
699 'query-migrate' => 1,
700 },
701 expected_calls => {},
702 expect_die => 'online migrate failure - aborting',
703 expected => {
704 source_volids => {},
705 target_volids => {},
706 vm_config => $vm_configs->{1033},
707 vm_status => {
708 running => 1,
709 runningmachine => 'pc-q35-5.0+pve0',
710 },
711 },
712 },
713 {
714 name => '4567_targetstorage_dirotherdir',
715 target => 'pve1',
716 vmid => 4567,
717 vm_status => {
718 running => 0,
719 },
720 opts => {
721 targetstorage => 'local-dir:other-dir,local-zfs:local-zfs',
722 },
723 storage_migrate_map => {
724 'local-dir:4567/vm-4567-disk-0.qcow2' => '4567/vm-4567-disk-0.qcow2',
725 'local-dir:4567/vm-4567-state-snap1.raw' => '4567/vm-4567-state-snap1.raw',
726 'local-dir:4567/vm-4567-state-snap2.raw' => '4567/vm-4567-state-snap2.raw',
727 },
728 expected_calls => $default_expected_calls_offline,
729 expected => {
730 source_volids => {},
731 target_volids => {
732 'other-dir:4567/vm-4567-disk-0.qcow2' => 1,
733 'other-dir:4567/vm-4567-state-snap1.raw' => 1,
734 'other-dir:4567/vm-4567-state-snap2.raw' => 1,
735 'local-zfs:vm-4567-disk-0' => 1,
736 },
737 vm_config => get_patched_config(4567, {
738 'scsi0' => 'other-dir:4567/vm-4567-disk-0.qcow2,size=4G',
739 snapshots => {
740 snap1 => {
741 'scsi0' => 'other-dir:4567/vm-4567-disk-0.qcow2,size=4G',
742 'vmstate' => 'other-dir:4567/vm-4567-state-snap1.raw',
743 },
744 snap2 => {
745 'scsi0' => 'other-dir:4567/vm-4567-disk-0.qcow2,size=4G',
746 'scsi1' => 'local-zfs:vm-4567-disk-0,size=1G',
747 'vmstate' => 'other-dir:4567/vm-4567-state-snap2.raw',
748 },
749 },
750 }),
751 vm_status => {
752 running => 0,
753 },
754 },
755 },
756 {
757 name => '4567_running',
758 target => 'pve1',
759 vmid => 4567,
760 vm_status => {
761 running => 1,
762 runningmachine => 'pc-i440fx-5.0+pve0',
763 },
764 opts => {
765 online => 1,
766 'with-local-disks' => 1,
767 },
768 expected_calls => {},
769 expect_die => 'online storage migration not possible if non-replicated snapshot exists',
770 expected => {
771 source_volids => local_volids_for_vm(4567),
772 target_volids => {},
773 vm_config => $vm_configs->{4567},
774 vm_status => {
775 running => 1,
776 runningmachine => 'pc-i440fx-5.0+pve0',
777 },
778 },
779 },
780 {
781 name => '4567_offline',
782 target => 'pve1',
783 vmid => 4567,
784 vm_status => {
785 running => 0,
786 },
787 expected_calls => $default_expected_calls_offline,
788 expected => {
789 source_volids => {},
790 target_volids => local_volids_for_vm(4567),
791 vm_config => $vm_configs->{4567},
792 vm_status => {
793 running => 0,
794 },
795 },
796 },
797 {
798 name => '149_running_orphaned_disk_targetstorage_zfs',
799 target => 'pve1',
800 vmid => 149,
801 vm_status => {
802 running => 1,
803 runningmachine => 'pc-q35-5.0+pve0',
804 },
805 opts => {
806 online => 1,
807 'with-local-disks' => 1,
808 targetstorage => 'local-zfs',
809 },
810 config_patch => {
811 scsi1 => undef,
812 },
813 storage_migrate_map => {
814 'local-dir:149/vm-149-disk-0.qcow2' => 'vm-149-disk-0',
815 },
816 expected_calls => $default_expected_calls_online,
817 expected => {
818 source_volids => {
819 'local-dir:149/vm-149-disk-0.qcow2' => 1,
820 },
821 target_volids => {
822 'local-zfs:vm-149-disk-10' => 1,
823 },
824 vm_config => get_patched_config(149, {
825 scsi0 => 'local-zfs:vm-149-disk-10,format=raw,size=4G',
826 scsi1 => undef,
827 }),
828 vm_status => {
829 running => 1,
830 runningmachine => 'pc-q35-5.0+pve0',
831 },
832 },
833 },
834 {
835 name => '149_running_orphaned_disk',
836 target => 'pve1',
837 vmid => 149,
838 vm_status => {
839 running => 1,
840 runningmachine => 'pc-q35-5.0+pve0',
841 },
842 opts => {
843 online => 1,
844 'with-local-disks' => 1,
845 },
846 config_patch => {
847 scsi1 => undef,
848 },
849 storage_migrate_map => {
850 'local-dir:149/vm-149-disk-0.qcow2' => '149/vm-149-disk-0.qcow2',
851 },
852 expected_calls => $default_expected_calls_online,
853 expected => {
854 source_volids => {
855 'local-dir:149/vm-149-disk-0.qcow2' => 1,
856 },
857 target_volids => {
858 'local-lvm:vm-149-disk-10' => 1,
859 },
860 vm_config => get_patched_config(149, {
861 scsi0 => 'local-lvm:vm-149-disk-10,format=raw,size=4G',
862 scsi1 => undef,
863 }),
864 vm_status => {
865 running => 1,
866 runningmachine => 'pc-q35-5.0+pve0',
867 },
868 },
869 },
870 {
871 # FIXME: This test is not (yet) a realistic situation, because
872 # storage_migrate currently never changes the format (AFAICT)
873 # But if such migrations become possible, we need to either update
874 # the 'format' property or simply remove it for drives migrated
875 # with storage_migrate (the property is optional, so it shouldn't be a problem)
876 name => '149_targetstorage_map_lvmzfs_defaultlvm',
877 target => 'pve1',
878 vmid => 149,
879 vm_status => {
880 running => 0,
881 },
882 opts => {
883 targetstorage => 'local-lvm:local-zfs,local-lvm',
884 },
885 storage_migrate_map => {
886 'local-lvm:vm-149-disk-0' => 'vm-149-disk-0',
887 'local-dir:149/vm-149-disk-0.qcow2' => 'vm-149-disk-0',
888 },
889 expected_calls => $default_expected_calls_offline,
890 expected => {
891 source_volids => {},
892 target_volids => {
893 'local-zfs:vm-149-disk-0' => 1,
894 'local-lvm:vm-149-disk-0' => 1,
895 },
896 vm_config => get_patched_config(149, {
897 scsi0 => 'local-zfs:vm-149-disk-0,format=raw,size=4G',
898 scsi1 => 'local-lvm:vm-149-disk-0,format=qcow2,size=1G',
899 }),
900 vm_status => {
901 running => 0,
902 },
903 },
904 },
905 {
906 # FIXME same as for the previous test
907 name => '149_targetstorage_map_dirzfs_lvmdir',
908 target => 'pve1',
909 vmid => 149,
910 vm_status => {
911 running => 0,
912 },
913 opts => {
914 online => 1,
915 'with-local-disks' => 1,
916 targetstorage => 'local-dir:local-zfs,local-lvm:local-dir',
917 },
918 storage_migrate_map => {
919 'local-lvm:vm-149-disk-0' => '149/vm-149-disk-0.raw',
920 'local-dir:149/vm-149-disk-0.qcow2' => 'vm-149-disk-0',
921 },
922 expected_calls => $default_expected_calls_offline,
923 expected => {
924 source_volids => {},
925 target_volids => {
926 'local-dir:149/vm-149-disk-0.raw' => 1,
927 'local-zfs:vm-149-disk-0' => 1,
928 },
929 vm_config => get_patched_config(149, {
930 scsi0 => 'local-dir:149/vm-149-disk-0.raw,format=raw,size=4G',
931 scsi1 => 'local-zfs:vm-149-disk-0,format=qcow2,size=1G',
932 }),
933 vm_status => {
934 running => 0,
935 },
936 },
937 },
938 {
939 name => '149_running_targetstorage_map_lvmzfs_defaultlvm',
940 target => 'pve1',
941 vmid => 149,
942 vm_status => {
943 running => 1,
944 runningmachine => 'pc-q35-5.0+pve0',
945 },
946 opts => {
947 online => 1,
948 'with-local-disks' => 1,
949 targetstorage => 'local-lvm:local-zfs,local-lvm',
950 },
951 expected_calls => $default_expected_calls_online,
952 expected => {
953 source_volids => {},
954 target_volids => {
955 'local-zfs:vm-149-disk-10' => 1,
956 'local-lvm:vm-149-disk-11' => 1,
957 },
958 vm_config => get_patched_config(149, {
959 scsi0 => 'local-zfs:vm-149-disk-10,format=raw,size=4G',
960 scsi1 => 'local-lvm:vm-149-disk-11,format=raw,size=1G',
961 }),
962 vm_status => {
963 running => 1,
964 runningmachine => 'pc-q35-5.0+pve0',
965 },
966 },
967 },
968 {
969 name => '149_running_targetstorage_map_lvmzfs_dirdir',
970 target => 'pve1',
971 vmid => 149,
972 vm_status => {
973 running => 1,
974 runningmachine => 'pc-q35-5.0+pve0',
975 },
976 opts => {
977 online => 1,
978 'with-local-disks' => 1,
979 targetstorage => 'local-lvm:local-zfs,local-dir:local-dir',
980 },
981 expected_calls => $default_expected_calls_online,
982 expected => {
983 source_volids => {},
984 target_volids => {
985 'local-zfs:vm-149-disk-10' => 1,
986 'local-dir:149/vm-149-disk-11.qcow2' => 1,
987 },
988 vm_config => get_patched_config(149, {
989 scsi0 => 'local-zfs:vm-149-disk-10,format=raw,size=4G',
990 scsi1 => 'local-dir:149/vm-149-disk-11.qcow2,format=qcow2,size=1G',
991 }),
992 vm_status => {
993 running => 1,
994 runningmachine => 'pc-q35-5.0+pve0',
995 },
996 },
997 },
998 {
999 name => '149_running_targetstorage_zfs',
1000 target => 'pve1',
1001 vmid => 149,
1002 vm_status => {
1003 running => 1,
1004 runningmachine => 'pc-q35-5.0+pve0',
1005 },
1006 opts => {
1007 online => 1,
1008 'with-local-disks' => 1,
1009 targetstorage => 'local-zfs',
1010 },
1011 expected_calls => $default_expected_calls_online,
1012 expected => {
1013 source_volids => {},
1014 target_volids => {
1015 'local-zfs:vm-149-disk-10' => 1,
1016 'local-zfs:vm-149-disk-11' => 1,
1017 },
1018 vm_config => get_patched_config(149, {
1019 scsi0 => 'local-zfs:vm-149-disk-10,format=raw,size=4G',
1020 scsi1 => 'local-zfs:vm-149-disk-11,format=raw,size=1G',
1021 }),
1022 vm_status => {
1023 running => 1,
1024 runningmachine => 'pc-q35-5.0+pve0',
1025 },
1026 },
1027 },
1028 {
1029 name => '149_running_wrong_size',
1030 target => 'pve1',
1031 vmid => 149,
1032 vm_status => {
1033 running => 1,
1034 runningmachine => 'pc-q35-5.0+pve0',
1035 },
1036 opts => {
1037 online => 1,
1038 'with-local-disks' => 1,
1039 },
1040 config_patch => {
1041 scsi0 => 'local-lvm:vm-149-disk-0,size=123T',
1042 },
1043 expected_calls => $default_expected_calls_online,
1044 expected => {
1045 source_volids => {},
1046 target_volids => {
1047 'local-lvm:vm-149-disk-10' => 1,
1048 'local-dir:149/vm-149-disk-11.qcow2' => 1,
1049 },
1050 vm_config => get_patched_config(149, {
1051 scsi0 => 'local-lvm:vm-149-disk-10,format=raw,size=4G',
1052 scsi1 => 'local-dir:149/vm-149-disk-11.qcow2,format=qcow2,size=1G',
1053 }),
1054 vm_status => {
1055 running => 1,
1056 runningmachine => 'pc-q35-5.0+pve0',
1057 },
1058 },
1059 },
1060 {
1061 name => '149_running_missing_size',
1062 target => 'pve1',
1063 vmid => 149,
1064 vm_status => {
1065 running => 1,
1066 runningmachine => 'pc-q35-5.0+pve0',
1067 },
1068 opts => {
1069 online => 1,
1070 'with-local-disks' => 1,
1071 },
1072 config_patch => {
1073 scsi0 => 'local-lvm:vm-149-disk-0',
1074 },
1075 expected_calls => $default_expected_calls_online,
1076 expected => {
1077 source_volids => {},
1078 target_volids => {
1079 'local-lvm:vm-149-disk-10' => 1,
1080 'local-dir:149/vm-149-disk-11.qcow2' => 1,
1081 },
1082 vm_config => get_patched_config(149, {
1083 scsi0 => 'local-lvm:vm-149-disk-10,format=raw,size=4G',
1084 scsi1 => 'local-dir:149/vm-149-disk-11.qcow2,format=qcow2,size=1G',
1085 }),
1086 vm_status => {
1087 running => 1,
1088 runningmachine => 'pc-q35-5.0+pve0',
1089 },
1090 },
1091 },
1092 {
1093 name => '105_local_device_shared',
1094 target => 'pve1',
1095 vmid => 105,
1096 vm_status => {
1097 running => 0,
1098 },
1099 config_patch => {
1100 ide2 => '/dev/sde,shared=1',
1101 },
1102 expected_calls => $default_expected_calls_offline,
1103 expected => {
1104 source_volids => {},
1105 target_volids => local_volids_for_vm(105),
1106 vm_config => get_patched_config(105, {
1107 ide2 => '/dev/sde,shared=1',
1108 }),
1109 vm_status => {
1110 running => 0,
1111 },
1112 },
1113 },
1114 {
1115 name => '105_local_device_in_snapshot',
1116 target => 'pve1',
1117 vmid => 105,
1118 vm_status => {
1119 running => 0,
1120 },
1121 config_patch => {
1122 snapshots => {
1123 ohsnap => {
1124 ide2 => '/dev/sde',
1125 },
1126 },
1127 },
1128 expected_calls => {},
1129 expect_die => "can't migrate local disk '/dev/sde': local file/device",
1130 expected => {
1131 source_volids => local_volids_for_vm(105),
1132 target_volids => {},
1133 vm_config => get_patched_config(105, {
1134 snapshots => {
1135 ohsnap => {
1136 ide2 => '/dev/sde',
1137 },
1138 },
1139 }),
1140 vm_status => {
1141 running => 0,
1142 },
1143 },
1144 },
1145 {
1146 name => '105_local_device',
1147 target => 'pve1',
1148 vmid => 105,
1149 vm_status => {
1150 running => 0,
1151 },
1152 config_patch => {
1153 ide2 => '/dev/sde',
1154 },
1155 expected_calls => {},
1156 expect_die => "can't migrate local disk '/dev/sde': local file/device",
1157 expected => {
1158 source_volids => local_volids_for_vm(105),
1159 target_volids => {},
1160 vm_config => get_patched_config(105, {
1161 ide2 => '/dev/sde',
1162 }),
1163 vm_status => {
1164 running => 0,
1165 },
1166 },
1167 },
1168 {
1169 name => '105_cdrom_in_snapshot',
1170 target => 'pve1',
1171 vmid => 105,
1172 vm_status => {
1173 running => 0,
1174 },
1175 config_patch => {
1176 snapshots => {
1177 ohsnap => {
1178 ide2 => 'cdrom,media=cdrom',
1179 },
1180 },
1181 },
1182 expected_calls => {},
1183 expect_die => "can't migrate local cdrom drive (referenced in snapshot - ohsnap",
1184 expected => {
1185 source_volids => local_volids_for_vm(105),
1186 target_volids => {},
1187 vm_config => get_patched_config(105, {
1188 snapshots => {
1189 ohsnap => {
1190 ide2 => 'cdrom,media=cdrom',
1191 },
1192 },
1193 }),
1194 vm_status => {
1195 running => 0,
1196 },
1197 },
1198 },
1199 {
1200 name => '105_cdrom',
1201 target => 'pve1',
1202 vmid => 105,
1203 vm_status => {
1204 running => 0,
1205 },
1206 config_patch => {
1207 ide2 => 'cdrom,media=cdrom',
1208 },
1209 expected_calls => {},
1210 expect_die => "can't migrate local cdrom drive",
1211 expected => {
1212 source_volids => local_volids_for_vm(105),
1213 target_volids => {},
1214 vm_config => get_patched_config(105, {
1215 ide2 => 'cdrom,media=cdrom',
1216 }),
1217 vm_status => {
1218 running => 0,
1219 },
1220 },
1221 },
1222 {
1223 name => '149_running_missing_option_withlocaldisks',
1224 target => 'pve1',
1225 vmid => 149,
1226 vm_status => {
1227 running => 1,
1228 runningmachine => 'pc-q35-5.0+pve0',
1229 },
1230 opts => {
1231 online => 1,
1232 },
1233 expected_calls => {},
1234 expect_die => "can't live migrate attached local disks without with-local-disks option",
1235 expected => {
1236 source_volids => local_volids_for_vm(149),
1237 target_volids => {},
1238 vm_config => $vm_configs->{149},
1239 vm_status => {
1240 running => 1,
1241 runningmachine => 'pc-q35-5.0+pve0',
1242 },
1243 },
1244 },
1245 {
1246 name => '149_running_missing_option_online',
1247 target => 'pve1',
1248 vmid => 149,
1249 vm_status => {
1250 running => 1,
1251 runningmachine => 'pc-q35-5.0+pve0',
1252 },
1253 opts => {
1254 'with-local-disks' => 1,
1255 },
1256 expected_calls => {},
1257 expect_die => "can't migrate running VM without --online",
1258 expected => {
1259 source_volids => local_volids_for_vm(149),
1260 target_volids => {},
1261 vm_config => $vm_configs->{149},
1262 vm_status => {
1263 running => 1,
1264 runningmachine => 'pc-q35-5.0+pve0',
1265 },
1266 },
1267 },
1268 {
1269 name => '1033_running_customcpu',
1270 target => 'pve1',
1271 vmid => 1033,
1272 vm_status => {
1273 running => 1,
1274 runningmachine => 'pc-q35-5.0+pve0',
1275 runningcpu => 'host,+kvm_pv_eoi,+kvm_pv_unhalt',
1276 },
1277 opts => {
1278 online => 1,
1279 },
1280 config_patch => {
1281 cpu => 'custom-mycpu',
1282 },
1283 expected_calls => $default_expected_calls_online,
1284 expected => {
1285 source_volids => {},
1286 target_volids => {},
1287 vm_config => get_patched_config(1033, {
1288 cpu => 'custom-mycpu',
1289 }),
1290 vm_status => {
1291 running => 1,
1292 runningmachine => 'pc-q35-5.0+pve0',
1293 runningcpu => 'host,+kvm_pv_eoi,+kvm_pv_unhalt',
1294 },
1295 },
1296 },
1297 {
1298 name => '105_replicated_to_non_replication_target',
1299 target => 'pve1',
1300 vmid => 105,
1301 vm_status => {
1302 running => 0,
1303 },
1304 target_volids => {},
1305 expected_calls => $replicated_expected_calls_offline,
1306 expected => {
1307 source_volids => {},
1308 target_volids => local_volids_for_vm(105),
1309 vm_config => $vm_configs->{105},
1310 vm_status => {
1311 running => 0,
1312 },
1313 },
1314 },
1315 {
1316 name => '105_running_replicated',
1317 target => 'pve2',
1318 vmid => 105,
1319 vm_status => {
1320 running => 1,
1321 runningmachine => 'pc-i440fx-5.0+pve0',
1322 },
1323 opts => {
1324 online => 1,
1325 'with-local-disks' => 1,
1326 },
1327 target_volids => local_volids_for_vm(105),
1328 expected_calls => {
1329 %{$replicated_expected_calls_online},
1330 'block-dirty-bitmap-add-drive-scsi0' => 1,
1331 'block-dirty-bitmap-add-drive-ide0' => 1,
1332 },
1333 expected => {
1334 source_volids => local_volids_for_vm(105),
1335 target_volids => local_volids_for_vm(105),
1336 vm_config => $vm_configs->{105},
1337 vm_status => {
1338 running => 1,
1339 runningmachine => 'pc-i440fx-5.0+pve0',
1340 },
1341 },
1342 },
1343 {
1344 name => '105_replicated',
1345 target => 'pve2',
1346 vmid => 105,
1347 vm_status => {
1348 running => 0,
1349 },
1350 target_volids => local_volids_for_vm(105),
1351 expected_calls => $replicated_expected_calls_offline,
1352 expected => {
1353 source_volids => local_volids_for_vm(105),
1354 target_volids => local_volids_for_vm(105),
1355 vm_config => $vm_configs->{105},
1356 vm_status => {
1357 running => 0,
1358 },
1359 },
1360 },
1361 {
1362 name => '105_running_replicated_without_snapshot',
1363 target => 'pve2',
1364 vmid => 105,
1365 vm_status => {
1366 running => 1,
1367 runningmachine => 'pc-i440fx-5.0+pve0',
1368 },
1369 config_patch => {
1370 snapshots => undef,
1371 },
1372 opts => {
1373 online => 1,
1374 'with-local-disks' => 1,
1375 },
1376 target_volids => local_volids_for_vm(105),
1377 expected_calls => {
1378 %{$replicated_expected_calls_online},
1379 'block-dirty-bitmap-add-drive-scsi0' => 1,
1380 'block-dirty-bitmap-add-drive-ide0' => 1,
1381 },
1382 expected => {
1383 source_volids => local_volids_for_vm(105),
1384 target_volids => local_volids_for_vm(105),
1385 vm_config => get_patched_config(105, {
1386 snapshots => {},
1387 }),
1388 vm_status => {
1389 running => 1,
1390 runningmachine => 'pc-i440fx-5.0+pve0',
1391 },
1392 },
1393 },
1394 {
1395 name => '105_replicated_without_snapshot',
1396 target => 'pve2',
1397 vmid => 105,
1398 vm_status => {
1399 running => 0,
1400 },
1401 config_patch => {
1402 snapshots => undef,
1403 },
1404 opts => {
1405 online => 1,
1406 },
1407 target_volids => local_volids_for_vm(105),
1408 expected_calls => $replicated_expected_calls_offline,
1409 expected => {
1410 source_volids => local_volids_for_vm(105),
1411 target_volids => local_volids_for_vm(105),
1412 vm_config => get_patched_config(105, {
1413 snapshots => {},
1414 }),
1415 vm_status => {
1416 running => 0,
1417 },
1418 },
1419 },
1420 {
1421 name => '1033_running',
1422 target => 'pve2',
1423 vmid => 1033,
1424 vm_status => {
1425 running => 1,
1426 runningmachine => 'pc-q35-5.0+pve0',
1427 },
1428 opts => {
1429 online => 1,
1430 },
1431 expected_calls => $default_expected_calls_online,
1432 expected => {
1433 source_volids => {},
1434 target_volids => {},
1435 vm_config => $vm_configs->{1033},
1436 vm_status => {
1437 running => 1,
1438 runningmachine => 'pc-q35-5.0+pve0',
1439 },
1440 },
1441 },
1442 {
1443 name => '149_locked',
1444 target => 'pve2',
1445 vmid => 149,
1446 vm_status => {
1447 running => 0,
1448 },
1449 config_patch => {
1450 lock => 'locked',
1451 },
1452 expected_calls => {},
1453 expect_die => "VM is locked",
1454 expected => {
1455 source_volids => local_volids_for_vm(149),
1456 target_volids => {},
1457 vm_config => get_patched_config(149, {
1458 lock => 'locked',
1459 }),
1460 vm_status => {
1461 running => 0,
1462 },
1463 },
1464 },
1465 {
1466 name => '149_storage_not_available',
1467 target => 'pve2',
1468 vmid => 149,
1469 vm_status => {
1470 running => 0,
1471 },
1472 expected_calls => {},
1473 expect_die => "storage 'local-lvm' is not available on node 'pve2'",
1474 expected => {
1475 source_volids => local_volids_for_vm(149),
1476 target_volids => {},
1477 vm_config => $vm_configs->{149},
1478 vm_status => {
1479 running => 0,
1480 },
1481 },
1482 },
1483 {
1484 name => '149_running',
1485 target => 'pve1',
1486 vmid => 149,
1487 vm_status => {
1488 running => 1,
1489 runningmachine => 'pc-q35-5.0+pve0',
1490 },
1491 opts => {
1492 online => 1,
1493 'with-local-disks' => 1,
1494 },
1495 expected_calls => $default_expected_calls_online,
1496 expected => {
1497 source_volids => {},
1498 target_volids => {
1499 'local-lvm:vm-149-disk-10' => 1,
1500 'local-dir:149/vm-149-disk-11.qcow2' => 1,
1501 },
1502 vm_config => get_patched_config(149, {
1503 scsi0 => 'local-lvm:vm-149-disk-10,format=raw,size=4G',
1504 scsi1 => 'local-dir:149/vm-149-disk-11.qcow2,format=qcow2,size=1G',
1505 }),
1506 vm_status => {
1507 running => 1,
1508 runningmachine => 'pc-q35-5.0+pve0',
1509 },
1510 },
1511 },
1512 {
1513 name => '149_running_drive_mirror_fail',
1514 target => 'pve1',
1515 vmid => 149,
1516 vm_status => {
1517 running => 1,
1518 runningmachine => 'pc-q35-5.0+pve0',
1519 },
1520 opts => {
1521 online => 1,
1522 'with-local-disks' => 1,
1523 },
1524 expected_calls => {},
1525 expect_die => "qemu_drive_mirror 'scsi1' error",
1526 fail_config => {
1527 'qemu_drive_mirror' => 'scsi1',
1528 },
1529 expected => {
1530 source_volids => local_volids_for_vm(149),
1531 target_volids => {},
1532 vm_config => $vm_configs->{149},
1533 vm_status => {
1534 running => 1,
1535 runningmachine => 'pc-q35-5.0+pve0',
1536 },
1537 },
1538 },
1539 {
1540 name => '149_running_unused_block_job_cancel_fail',
1541 target => 'pve1',
1542 vmid => 149,
1543 vm_status => {
1544 running => 1,
1545 runningmachine => 'pc-q35-5.0+pve0',
1546 },
1547 opts => {
1548 online => 1,
1549 'with-local-disks' => 1,
1550 },
1551 config_patch => {
1552 scsi1 => undef,
1553 unused0 => 'local-dir:149/vm-149-disk-0.qcow2',
1554 },
1555 expected_calls => {},
1556 expect_die => "qemu_drive_mirror_monitor 'cancel' error",
1557 # note that 'cancel' is also used to finish and that's what this test is about
1558 fail_config => {
1559 'qemu_drive_mirror_monitor' => 'cancel',
1560 },
1561 expected => {
1562 source_volids => local_volids_for_vm(149),
1563 target_volids => {},
1564 vm_config => get_patched_config(149, {
1565 scsi1 => undef,
1566 unused0 => 'local-dir:149/vm-149-disk-0.qcow2',
1567 }),
1568 vm_status => {
1569 running => 1,
1570 runningmachine => 'pc-q35-5.0+pve0',
1571 },
1572 },
1573 },
1574 {
1575 name => '149_offline',
1576 target => 'pve1',
1577 vmid => 149,
1578 vm_status => {
1579 running => 0,
1580 },
1581 opts => {
1582 'with-local-disks' => 1,
1583 },
1584 expected_calls => $default_expected_calls_offline,
1585 expected => {
1586 source_volids => {},
1587 target_volids => local_volids_for_vm(149),
1588 vm_config => $vm_configs->{149},
1589 vm_status => {
1590 running => 0,
1591 },
1592 },
1593 },
1594 {
1595 name => '149_storage_migrate_fail',
1596 target => 'pve1',
1597 vmid => 149,
1598 vm_status => {
1599 running => 0,
1600 },
1601 opts => {
1602 'with-local-disks' => 1,
1603 },
1604 fail_config => {
1605 'storage_migrate' => 'local-lvm:vm-149-disk-0',
1606 },
1607 expected_calls => {},
1608 expect_die => "storage_migrate 'local-lvm:vm-149-disk-0' error",
1609 expected => {
1610 source_volids => local_volids_for_vm(149),
1611 target_volids => {},
1612 vm_config => $vm_configs->{149},
1613 vm_status => {
1614 running => 0,
1615 },
1616 },
1617 },
1618 {
1619 name => '111_running_pending',
1620 target => 'pve1',
1621 vmid => 111,
1622 vm_status => {
1623 running => 1,
1624 runningmachine => 'pc-q35-5.0+pve0',
1625 },
1626 opts => {
1627 online => 1,
1628 'with-local-disks' => 1,
1629 },
1630 expected_calls => $default_expected_calls_online,
1631 expected => {
1632 source_volids => {},
1633 target_volids => {
1634 'local-zfs:vm-111-disk-0' => 1,
1635 'local-lvm:vm-111-disk-10' => 1,
1636 },
1637 vm_config => get_patched_config(111, {
1638 ide0 => 'local-lvm:vm-111-disk-10,format=raw,size=4G',
1639 pending => {
1640 scsi0 => 'local-zfs:vm-111-disk-0,size=103M',
1641 },
1642 }),
1643 vm_status => {
1644 running => 1,
1645 runningmachine => 'pc-q35-5.0+pve0',
1646 },
1647 },
1648 },
1649 {
1650 name => '123_alias_fail',
1651 target => 'pve1',
1652 vmid => 123,
1653 vm_status => {
1654 running => 0,
1655 },
1656 opts => {
1657 'with-local-disks' => 1,
1658 },
1659 expected_calls => {},
1660 expect_die => "detected not supported aliased volumes",
1661 expected => {
1662 source_volids => local_volids_for_vm(123),
1663 target_volids => {},
1664 vm_config => $vm_configs->{123},
1665 vm_status => {
1666 running => 0,
1667 },
1668 },
1669 },
1670 ];
1671
1672 my $single_test_name = shift;
1673
1674 mkdir $RUN_DIR_PATH;
1675
1676 foreach my $test (@{$tests}) {
1677 my $name = $test->{name};
1678 next if defined($single_test_name) && $name ne $single_test_name;
1679
1680 my $run_dir = "${RUN_DIR_PATH}/${name}";
1681
1682 mkdir $run_dir;
1683 file_set_contents("${run_dir}/replication_config", to_json($replication_config));
1684 file_set_contents("${run_dir}/storage_config", to_json($storage_config));
1685 file_set_contents("${run_dir}/source_vdisks", to_json($source_vdisks));
1686
1687 my $expect_die = $test->{expect_die};
1688 my $expected = $test->{expected};
1689
1690 my $source_volids = local_volids_for_vm($test->{vmid});
1691 my $target_volids = $test->{target_volids} // {};
1692
1693 my $config_patch = $test->{config_patch};
1694 my $vm_config = get_patched_config($test->{vmid}, $test->{config_patch});
1695
1696 my $fail_config = $test->{fail_config} // {};
1697 my $storage_migrate_map = $test->{storage_migrate_map} // {};
1698
1699 if (my $targetstorage = $test->{opts}->{targetstorage}) {
1700 $test->{opts}->{storagemap} = PVE::JSONSchema::parse_idmap($targetstorage, 'pve-storage-id');
1701 }
1702
1703 my $migrate_params = {
1704 target => $test->{target},
1705 vmid => $test->{vmid},
1706 opts => $test->{opts},
1707 };
1708
1709 file_set_contents("${run_dir}/nbd_info", to_json({}));
1710 file_set_contents("${run_dir}/source_volids", to_json($source_volids));
1711 file_set_contents("${run_dir}/target_volids", to_json($target_volids));
1712 file_set_contents("${run_dir}/vm_config", to_json($vm_config));
1713 file_set_contents("${run_dir}/vm_status", to_json($test->{vm_status}));
1714 file_set_contents("${run_dir}/expected_calls", to_json($test->{expected_calls}));
1715 file_set_contents("${run_dir}/fail_config", to_json($fail_config));
1716 file_set_contents("${run_dir}/storage_migrate_map", to_json($storage_migrate_map));
1717 file_set_contents("${run_dir}/migrate_params", to_json($migrate_params));
1718
1719 $ENV{QM_LIB_PATH} = $QM_LIB_PATH;
1720 $ENV{RUN_DIR_PATH} = $run_dir;
1721 my $exitcode = run_command([
1722 '/usr/bin/perl',
1723 "-I${MIGRATE_LIB_PATH}",
1724 "-I${MIGRATE_LIB_PATH}/test",
1725 "${MIGRATE_LIB_PATH}/test/MigrationTest/QemuMigrateMock.pm",
1726 ], noerr => 1, errfunc => sub {print "#$name - $_[0]\n"} );
1727
1728 if (defined($expect_die) && $exitcode) {
1729 my $log = file_get_contents("${run_dir}/log");
1730 my @lines = split /\n/, $log;
1731
1732 my $matched = 0;
1733 foreach my $line (@lines) {
1734 $matched = 1 if $line =~ m/^err:.*\Q${expect_die}\E/;
1735 $matched = 1 if $line =~ m/^warn:.*\Q${expect_die}\E/;
1736 }
1737 if (!$matched) {
1738 fail($name);
1739 note("expected error message is not present in log");
1740 }
1741 } elsif (defined($expect_die) && !$exitcode) {
1742 fail($name);
1743 note("mocked migrate call didn't fail, but it was expected to - check log");
1744 } elsif (!defined($expect_die) && $exitcode) {
1745 fail($name);
1746 note("mocked migrate call failed, but it was not expected - check log");
1747 }
1748
1749 my $expected_calls = decode_json(file_get_contents("${run_dir}/expected_calls"));
1750 foreach my $call (keys %{$expected_calls}) {
1751 fail($name);
1752 note("expected call '$call' was not made");
1753 }
1754
1755 if (!defined($expect_die)) {
1756 my $nbd_info = decode_json(file_get_contents("${run_dir}/nbd_info"));
1757 foreach my $drive (keys %{$nbd_info}) {
1758 fail($name);
1759 note("drive '$drive' was not mirrored");
1760 }
1761 }
1762
1763 my $actual = {
1764 source_volids => decode_json(file_get_contents("${run_dir}/source_volids")),
1765 target_volids => decode_json(file_get_contents("${run_dir}/target_volids")),
1766 vm_config => decode_json(file_get_contents("${run_dir}/vm_config")),
1767 vm_status => decode_json(file_get_contents("${run_dir}/vm_status")),
1768 };
1769
1770 is_deeply($actual, $expected, $name);
1771 }
1772
1773 done_testing();