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