11 use PVE
::Tools
qw(file_set_contents file_get_contents run_command);
13 my $QM_LIB_PATH = '..';
14 my $MIGRATE_LIB_PATH = '..';
15 my $RUN_DIR_PATH = './MigrationTest/run/';
17 # test configuration shared by all tests
19 my $replication_config = {
35 my $storage_config = {
41 path
=> "/var/lib/vz",
67 monhost
=> "127.0.0.42,127.0.0.21,::1",
68 fsid
=> 'fc4181a6-56eb-4f68-b452-8ba1f381ca2a',
88 path
=> "/some/other/dir/",
96 'bootdisk' => 'scsi0',
98 'ide0' => 'local-zfs:vm-105-disk-1,size=103M',
99 'ide2' => 'none,media=cdrom',
101 'name' => 'Copy-of-VM-newapache',
102 'net0' => 'virtio=4A:A3:E4:4C:CF:F0,bridge=vmbr0,firewall=1',
105 'parent' => 'ohsnap',
107 'scsi0' => 'local-zfs:vm-105-disk-0,size=4G',
108 'scsihw' => 'virtio-scsi-pci',
109 'smbios1' => 'uuid=1ddfe18b-77e0-47f6-a4bd-f1761bf6d763',
112 'bootdisk' => 'scsi0',
114 'ide2' => 'none,media=cdrom',
116 'name' => 'Copy-of-VM-newapache',
117 'net0' => 'virtio=4A:A3:E4:4C:CF:F0,bridge=vmbr0,firewall=1',
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,
125 'startup' => 'order=2',
126 'vmgenid' => '4eb1d535-9381-4ddc-a8aa-af50c4d9177b'
130 'startup' => 'order=2',
131 'vmgenid' => '4eb1d535-9381-4ddc-a8aa-af50c4d9177b',
135 'bootdisk' => 'scsi0',
137 'hotplug' => 'disk,network,usb,memory,cpu',
138 'ide2' => 'none,media=cdrom',
141 'net0' => 'virtio=52:5D:7E:62:85:97,bridge=vmbr1',
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',
148 'smbios1' => 'uuid=e980bd43-a405-42e2-b5f4-31efe6517460',
150 'startup' => 'order=2',
151 'vmgenid' => '36c6c50c-6ef5-4adc-9b6f-6ba9c8071db0',
155 'bootdisk' => 'scsi0',
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',
162 'net0' => 'virtio=4E:F1:82:6D:D7:4B,bridge=vmbr0,firewall=1,rate=10',
165 'scsi0' => 'rbd-store:vm-341-disk-0,size=1G',
166 'scsihw' => 'virtio-scsi-pci',
168 'smbios1' => 'uuid=e01e4c73-46f1-47c8-af79-288fdf6b7462',
170 'vmgenid' => 'af47c000-eb0c-48e8-8991-ca4593cd6916',
173 'bootdisk' => 'scsi0',
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',
180 'net0' => 'virtio=4E:F1:82:6D:D7:4B,bridge=vmbr0,firewall=1,rate=10',
183 'scsi0' => 'rbd-store:vm-1033-disk-1,size=1G',
184 'scsihw' => 'virtio-scsi-pci',
186 'smbios1' => 'uuid=e01e4c73-46f1-47c8-af79-288fdf6b7462',
188 'vmgenid' => 'af47c000-eb0c-48e8-8991-ca4593cd6916',
191 'bootdisk' => 'scsi0',
193 'ide2' => 'none,media=cdrom',
196 'net0' => 'virtio=A6:D1:F1:EB:7B:C2,bridge=vmbr0,firewall=1',
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',
206 'bootdisk' => 'scsi0',
208 'ide2' => 'none,media=cdrom',
211 'net0' => 'virtio=A6:D1:F1:EB:7B:C2,bridge=vmbr0,firewall=1',
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,
221 'startup' => 'order=2',
222 'vmgenid' => '932b227a-8a39-4ede-955a-dbd4bc4385ed',
223 'vmstate' => 'local-dir:4567/vm-4567-state-snap1.raw',
226 'bootdisk' => 'scsi0',
228 'ide2' => 'none,media=cdrom',
231 'net0' => 'virtio=A6:D1:F1:EB:7B:C2,bridge=vmbr0,firewall=1',
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,
243 'startup' => 'order=2',
244 'vmgenid' => '932b227a-8a39-4ede-955a-dbd4bc4385ed',
245 'vmstate' => 'local-dir:4567/vm-4567-state-snap2.raw',
249 'startup' => 'order=2',
250 'unused0' => 'local-zfs:vm-4567-disk-0',
251 'vmgenid' => 'e698e60c-9278-4dd9-941f-416075383f2a',
255 my $source_vdisks = {
258 'ctime' => 1589439681,
261 'size' => 1073741824,
264 'volid' => 'local-dir:149/vm-149-disk-0.qcow2',
267 'ctime' => 1595928898,
270 'size' => 4294967296,
271 'used' => 1811664896,
273 'volid' => 'local-dir:4567/vm-4567-disk-0.qcow2',
276 'ctime' => 1595928800,
282 'volid' => 'local-dir:4567/vm-4567-state-snap1.raw',
285 'ctime' => 1595928872,
291 'volid' => 'local-dir:4567/vm-4567-state-snap2.raw',
296 'ctime' => '1589277334',
298 'size' => 4294967296,
300 'volid' => 'local-lvm:vm-149-disk-0',
303 'ctime' => '1589277334',
307 'volid' => 'local-lvm:vm-341-disk-0',
312 'ctime' => '1589277334',
314 'size' => 4294967296,
316 'volid' => 'local-zfs:vm-105-disk-0',
319 'ctime' => '1589277334',
323 'volid' => 'local-zfs:vm-105-disk-1',
327 'name' => 'vm-4567-disk-0',
329 'size' => 1073741824,
331 'volid' => 'local-zfs:vm-4567-disk-0',
336 'ctime' => '1589277334',
338 'size' => 1073741824,
340 'volid' => 'rbd-store:vm-1033-disk-1',
343 'ctime' => '1589277334',
345 'size' => 1073741824,
347 'volid' => 'rbd-store:vm-1033-cloudinit',
352 my $default_expected_calls_online = {
353 move_config_to_node
=> 1,
358 my $default_expected_calls_offline = {
359 move_config_to_node
=> 1,
362 my $replicated_expected_calls_online = {
363 %{$default_expected_calls_online},
364 transfer_replication_state
=> 1,
365 switch_replication_job_target
=> 1,
368 my $replicated_expected_calls_offline = {
369 %{$default_expected_calls_offline},
370 transfer_replication_state
=> 1,
371 switch_replication_job_target
=> 1,
376 sub get_patched_config
{
377 my ($vmid, $patch) = @_;
379 my $new_config = { %{$vm_configs->{$vmid}} };
380 patch_config
($new_config, $patch) if defined($patch);
386 my ($config, $patch) = @_;
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;
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};
405 sub local_volids_for_vm
{
409 foreach my $storeid (keys %{$source_vdisks}) {
410 next if $storage_config->{ids
}->{$storeid}->{shared
};
413 map { $_->{vmid
} eq $vmid ?
($_->{volid
} => 1) : () } @{$source_vdisks->{$storeid}}
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
439 # NOTE get_efivars_size is mocked and returns 128K
440 name
=> '341_running_efidisk_targetstorage_dir',
445 runningmachine
=> 'pc-q35-5.0+pve0',
449 'with-local-disks' => 1,
450 targetstorage
=> 'local-dir',
452 expected_calls
=> $default_expected_calls_online,
456 'local-dir:341/vm-341-disk-10.raw' => 1,
458 vm_config
=> get_patched_config
(341, {
459 efidisk0
=> 'local-dir:341/vm-341-disk-10.raw,format=raw,size=128K',
463 runningmachine
=> 'pc-q35-5.0+pve0',
468 # NOTE get_efivars_size is mocked and returns 128K
469 name
=> '341_running_efidisk',
474 runningmachine
=> 'pc-q35-5.0+pve0',
478 'with-local-disks' => 1,
480 expected_calls
=> $default_expected_calls_online,
484 'local-lvm:vm-341-disk-10' => 1,
486 vm_config
=> get_patched_config
(341, {
487 efidisk0
=> 'local-lvm:vm-341-disk-10,format=raw,size=128K',
491 runningmachine
=> 'pc-q35-5.0+pve0',
496 name
=> '149_running_vdisk_alloc_and_pvesm_free_fail',
501 runningmachine
=> 'pc-q35-5.0+pve0',
505 'with-local-disks' => 1,
508 vdisk_alloc
=> 'local-dir:149/vm-149-disk-11.qcow2',
509 pvesm_free
=> 'local-lvm:vm-149-disk-10',
511 expected_calls
=> {},
512 expect_die
=> "remote command failed with exit code",
514 source_volids
=> local_volids_for_vm
(149),
516 'local-lvm:vm-149-disk-10' => 1,
518 vm_config
=> $vm_configs->{149},
521 runningmachine
=> 'pc-q35-5.0+pve0',
526 name
=> '149_running_vdisk_alloc_fail',
531 runningmachine
=> 'pc-q35-5.0+pve0',
535 'with-local-disks' => 1,
538 vdisk_alloc
=> 'local-lvm:vm-149-disk-10',
540 expected_calls
=> {},
541 expect_die
=> "remote command failed with exit code",
543 source_volids
=> local_volids_for_vm
(149),
545 vm_config
=> $vm_configs->{149},
548 runningmachine
=> 'pc-q35-5.0+pve0',
553 name
=> '149_vdisk_free_fail',
560 'with-local-disks' => 1,
563 'vdisk_free' => 'local-lvm:vm-149-disk-0',
565 expected_calls
=> $default_expected_calls_offline,
566 expect_die
=> "vdisk_free 'local-lvm:vm-149-disk-0' error",
569 'local-lvm:vm-149-disk-0' => 1,
571 target_volids
=> local_volids_for_vm
(149),
572 vm_config
=> $vm_configs->{149},
579 name
=> '105_replicated_run_replication_fail',
585 target_volids
=> local_volids_for_vm
(105),
587 run_replication
=> 1,
589 expected_calls
=> {},
590 expect_die
=> 'run_replication error',
592 source_volids
=> local_volids_for_vm
(105),
593 target_volids
=> local_volids_for_vm
(105),
594 vm_config
=> $vm_configs->{105},
601 name
=> '1033_running_query_migrate_fail',
606 runningmachine
=> 'pc-q35-5.0+pve0',
612 'query-migrate' => 1,
614 expected_calls
=> {},
615 expect_die
=> 'online migrate failure - aborting',
619 vm_config
=> $vm_configs->{1033},
622 runningmachine
=> 'pc-q35-5.0+pve0',
627 name
=> '4567_targetstorage_dirotherdir',
634 targetstorage
=> 'local-dir:other-dir,local-zfs:local-zfs',
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',
641 expected_calls
=> $default_expected_calls_offline,
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,
650 vm_config
=> get_patched_config
(4567, {
651 'scsi0' => 'other-dir:4567/vm-4567-disk-0.qcow2,size=4G',
654 'scsi0' => 'other-dir:4567/vm-4567-disk-0.qcow2,size=4G',
655 'vmstate' => 'other-dir:4567/vm-4567-state-snap1.raw',
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',
670 name
=> '4567_running',
675 runningmachine
=> 'pc-i440fx-5.0+pve0',
679 'with-local-disks' => 1,
681 expected_calls
=> {},
682 expect_die
=> 'online storage migration not possible if non-replicated snapshot exists',
684 source_volids
=> local_volids_for_vm
(4567),
686 vm_config
=> $vm_configs->{4567},
689 runningmachine
=> 'pc-i440fx-5.0+pve0',
694 name
=> '4567_offline',
700 expected_calls
=> $default_expected_calls_offline,
703 target_volids
=> local_volids_for_vm
(4567),
704 vm_config
=> $vm_configs->{4567},
711 # FIXME: Maybe add orphaned drives as unused?
712 name
=> '149_running_orphaned_disk_targetstorage_zfs',
717 runningmachine
=> 'pc-q35-5.0+pve0',
721 'with-local-disks' => 1,
722 targetstorage
=> 'local-zfs',
727 storage_migrate_map
=> {
728 'local-dir:149/vm-149-disk-0.qcow2' => 'vm-149-disk-0',
730 expected_calls
=> $default_expected_calls_online,
734 'local-zfs:vm-149-disk-10' => 1,
735 'local-zfs:vm-149-disk-0' => 1,
737 vm_config
=> get_patched_config
(149, {
738 scsi0
=> 'local-zfs:vm-149-disk-10,format=raw,size=4G',
743 runningmachine
=> 'pc-q35-5.0+pve0',
748 # FIXME: Maybe add orphaned drives as unused?
749 name
=> '149_running_orphaned_disk',
754 runningmachine
=> 'pc-q35-5.0+pve0',
758 'with-local-disks' => 1,
763 storage_migrate_map
=> {
764 'local-dir:149/vm-149-disk-0.qcow2' => '149/vm-149-disk-0.qcow2',
766 expected_calls
=> $default_expected_calls_online,
770 'local-lvm:vm-149-disk-10' => 1,
771 'local-dir:149/vm-149-disk-0.qcow2' => 1,
773 vm_config
=> get_patched_config
(149, {
774 scsi0
=> 'local-lvm:vm-149-disk-10,format=raw,size=4G',
779 runningmachine
=> 'pc-q35-5.0+pve0',
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',
796 targetstorage
=> 'local-lvm:local-zfs,local-lvm',
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',
802 expected_calls
=> $default_expected_calls_offline,
806 'local-zfs:vm-149-disk-0' => 1,
807 'local-lvm:vm-149-disk-0' => 1,
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',
819 # FIXME same as for the previous test
820 name
=> '149_targetstorage_map_dirzfs_lvmdir',
828 'with-local-disks' => 1,
829 targetstorage
=> 'local-dir:local-zfs,local-lvm:local-dir',
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',
835 expected_calls
=> $default_expected_calls_offline,
839 'local-dir:149/vm-149-disk-0.raw' => 1,
840 'local-zfs:vm-149-disk-0' => 1,
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',
852 name
=> '149_running_targetstorage_map_lvmzfs_defaultlvm',
857 runningmachine
=> 'pc-q35-5.0+pve0',
861 'with-local-disks' => 1,
862 targetstorage
=> 'local-lvm:local-zfs,local-lvm',
864 expected_calls
=> $default_expected_calls_online,
868 'local-zfs:vm-149-disk-10' => 1,
869 'local-lvm:vm-149-disk-11' => 1,
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',
877 runningmachine
=> 'pc-q35-5.0+pve0',
882 name
=> '149_running_targetstorage_map_lvmzfs_dirdir',
887 runningmachine
=> 'pc-q35-5.0+pve0',
891 'with-local-disks' => 1,
892 targetstorage
=> 'local-lvm:local-zfs,local-dir:local-dir',
894 expected_calls
=> $default_expected_calls_online,
898 'local-zfs:vm-149-disk-10' => 1,
899 'local-dir:149/vm-149-disk-11.qcow2' => 1,
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',
907 runningmachine
=> 'pc-q35-5.0+pve0',
912 name
=> '149_running_targetstorage_zfs',
917 runningmachine
=> 'pc-q35-5.0+pve0',
921 'with-local-disks' => 1,
922 targetstorage
=> 'local-zfs',
924 expected_calls
=> $default_expected_calls_online,
928 'local-zfs:vm-149-disk-10' => 1,
929 'local-zfs:vm-149-disk-11' => 1,
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',
937 runningmachine
=> 'pc-q35-5.0+pve0',
942 name
=> '149_running_wrong_size',
947 runningmachine
=> 'pc-q35-5.0+pve0',
951 'with-local-disks' => 1,
954 scsi0
=> 'local-lvm:vm-149-disk-0,size=123T',
956 expected_calls
=> $default_expected_calls_online,
960 'local-lvm:vm-149-disk-10' => 1,
961 'local-dir:149/vm-149-disk-11.qcow2' => 1,
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',
969 runningmachine
=> 'pc-q35-5.0+pve0',
974 name
=> '149_running_missing_size',
979 runningmachine
=> 'pc-q35-5.0+pve0',
983 'with-local-disks' => 1,
986 scsi0
=> 'local-lvm:vm-149-disk-0',
988 expected_calls
=> $default_expected_calls_online,
992 'local-lvm:vm-149-disk-10' => 1,
993 'local-dir:149/vm-149-disk-11.qcow2' => 1,
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',
1001 runningmachine
=> 'pc-q35-5.0+pve0',
1006 name
=> '105_local_device_shared',
1013 ide2
=> '/dev/sde,shared=1',
1015 expected_calls
=> $default_expected_calls_offline,
1017 source_volids
=> {},
1018 target_volids
=> local_volids_for_vm
(105),
1019 vm_config
=> get_patched_config
(105, {
1020 ide2
=> '/dev/sde,shared=1',
1028 name
=> '105_local_device_in_snapshot',
1041 expected_calls
=> {},
1042 expect_die
=> "can't migrate local disk '/dev/sde': local file/device",
1044 source_volids
=> local_volids_for_vm
(105),
1045 target_volids
=> {},
1046 vm_config
=> get_patched_config
(105, {
1059 name
=> '105_local_device',
1068 expected_calls
=> {},
1069 expect_die
=> "can't migrate local disk '/dev/sde': local file/device",
1071 source_volids
=> local_volids_for_vm
(105),
1072 target_volids
=> {},
1073 vm_config
=> get_patched_config
(105, {
1082 name
=> '105_cdrom_in_snapshot',
1091 ide2
=> 'cdrom,media=cdrom',
1095 expected_calls
=> {},
1096 expect_die
=> "can't migrate local cdrom drive (referenced in snapshot - ohsnap",
1098 source_volids
=> local_volids_for_vm
(105),
1099 target_volids
=> {},
1100 vm_config
=> get_patched_config
(105, {
1103 ide2
=> 'cdrom,media=cdrom',
1113 name
=> '105_cdrom',
1120 ide2
=> 'cdrom,media=cdrom',
1122 expected_calls
=> {},
1123 expect_die
=> "can't migrate local cdrom drive",
1125 source_volids
=> local_volids_for_vm
(105),
1126 target_volids
=> {},
1127 vm_config
=> get_patched_config
(105, {
1128 ide2
=> 'cdrom,media=cdrom',
1136 name
=> '149_running_missing_option_withlocaldisks',
1141 runningmachine
=> 'pc-q35-5.0+pve0',
1146 expected_calls
=> {},
1147 expect_die
=> "can't live migrate attached local disks without with-local-disks option",
1149 source_volids
=> local_volids_for_vm
(149),
1150 target_volids
=> {},
1151 vm_config
=> $vm_configs->{149},
1154 runningmachine
=> 'pc-q35-5.0+pve0',
1159 name
=> '149_running_missing_option_online',
1164 runningmachine
=> 'pc-q35-5.0+pve0',
1167 'with-local-disks' => 1,
1169 expected_calls
=> {},
1170 expect_die
=> "can't migrate running VM without --online",
1172 source_volids
=> local_volids_for_vm
(149),
1173 target_volids
=> {},
1174 vm_config
=> $vm_configs->{149},
1177 runningmachine
=> 'pc-q35-5.0+pve0',
1182 name
=> '1033_running_customcpu',
1187 runningmachine
=> 'pc-q35-5.0+pve0',
1188 runningcpu
=> 'host,+kvm_pv_eoi,+kvm_pv_unhalt',
1194 cpu
=> 'custom-mycpu',
1196 expected_calls
=> $default_expected_calls_online,
1198 source_volids
=> {},
1199 target_volids
=> {},
1200 vm_config
=> get_patched_config
(1033, {
1201 cpu
=> 'custom-mycpu',
1205 runningmachine
=> 'pc-q35-5.0+pve0',
1206 runningcpu
=> 'host,+kvm_pv_eoi,+kvm_pv_unhalt',
1211 name
=> '105_replicated_to_non_replication_target',
1217 target_volids
=> {},
1218 expected_calls
=> $replicated_expected_calls_offline,
1220 source_volids
=> {},
1221 target_volids
=> local_volids_for_vm
(105),
1222 vm_config
=> $vm_configs->{105},
1229 name
=> '105_running_replicated',
1234 runningmachine
=> 'pc-i440fx-5.0+pve0',
1238 'with-local-disks' => 1,
1240 target_volids
=> local_volids_for_vm
(105),
1242 %{$replicated_expected_calls_online},
1243 'block-dirty-bitmap-add-drive-scsi0' => 1,
1244 'block-dirty-bitmap-add-drive-ide0' => 1,
1247 source_volids
=> local_volids_for_vm
(105),
1248 target_volids
=> local_volids_for_vm
(105),
1249 vm_config
=> $vm_configs->{105},
1252 runningmachine
=> 'pc-i440fx-5.0+pve0',
1257 name
=> '105_replicated',
1263 target_volids
=> local_volids_for_vm
(105),
1264 expected_calls
=> $replicated_expected_calls_offline,
1266 source_volids
=> local_volids_for_vm
(105),
1267 target_volids
=> local_volids_for_vm
(105),
1268 vm_config
=> $vm_configs->{105},
1275 name
=> '105_running_replicated_without_snapshot',
1280 runningmachine
=> 'pc-i440fx-5.0+pve0',
1287 'with-local-disks' => 1,
1289 target_volids
=> local_volids_for_vm
(105),
1291 %{$replicated_expected_calls_online},
1292 'block-dirty-bitmap-add-drive-scsi0' => 1,
1293 'block-dirty-bitmap-add-drive-ide0' => 1,
1296 source_volids
=> local_volids_for_vm
(105),
1297 target_volids
=> local_volids_for_vm
(105),
1298 vm_config
=> get_patched_config
(105, {
1303 runningmachine
=> 'pc-i440fx-5.0+pve0',
1308 name
=> '105_replicated_without_snapshot',
1320 target_volids
=> local_volids_for_vm
(105),
1321 expected_calls
=> $replicated_expected_calls_offline,
1323 source_volids
=> local_volids_for_vm
(105),
1324 target_volids
=> local_volids_for_vm
(105),
1325 vm_config
=> get_patched_config
(105, {
1334 name
=> '1033_running',
1339 runningmachine
=> 'pc-q35-5.0+pve0',
1344 expected_calls
=> $default_expected_calls_online,
1346 source_volids
=> {},
1347 target_volids
=> {},
1348 vm_config
=> $vm_configs->{1033},
1351 runningmachine
=> 'pc-q35-5.0+pve0',
1356 name
=> '149_locked',
1365 expected_calls
=> {},
1366 expect_die
=> "VM is locked",
1368 source_volids
=> local_volids_for_vm
(149),
1369 target_volids
=> {},
1370 vm_config
=> get_patched_config
(149, {
1379 name
=> '149_storage_not_available',
1385 expected_calls
=> {},
1386 expect_die
=> "storage 'local-lvm' is not available on node 'pve2'",
1388 source_volids
=> local_volids_for_vm
(149),
1389 target_volids
=> {},
1390 vm_config
=> $vm_configs->{149},
1397 name
=> '149_running',
1402 runningmachine
=> 'pc-q35-5.0+pve0',
1406 'with-local-disks' => 1,
1408 expected_calls
=> $default_expected_calls_online,
1410 source_volids
=> {},
1412 'local-lvm:vm-149-disk-10' => 1,
1413 'local-dir:149/vm-149-disk-11.qcow2' => 1,
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',
1421 runningmachine
=> 'pc-q35-5.0+pve0',
1426 name
=> '149_running_drive_mirror_fail',
1431 runningmachine
=> 'pc-q35-5.0+pve0',
1435 'with-local-disks' => 1,
1437 expected_calls
=> {},
1438 expect_die
=> "qemu_drive_mirror 'scsi1' error",
1440 'qemu_drive_mirror' => 'scsi1',
1443 source_volids
=> local_volids_for_vm
(149),
1444 target_volids
=> {},
1445 vm_config
=> $vm_configs->{149},
1448 runningmachine
=> 'pc-q35-5.0+pve0',
1453 name
=> '149_running_unused_block_job_cancel_fail',
1458 runningmachine
=> 'pc-q35-5.0+pve0',
1462 'with-local-disks' => 1,
1466 unused0
=> 'local-dir:149/vm-149-disk-0.qcow2',
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
1472 'qemu_drive_mirror_monitor' => 'cancel',
1475 source_volids
=> local_volids_for_vm
(149),
1476 target_volids
=> {},
1477 vm_config
=> get_patched_config
(149, {
1479 unused0
=> 'local-dir:149/vm-149-disk-0.qcow2',
1483 runningmachine
=> 'pc-q35-5.0+pve0',
1488 name
=> '149_offline',
1495 'with-local-disks' => 1,
1497 expected_calls
=> $default_expected_calls_offline,
1499 source_volids
=> {},
1500 target_volids
=> local_volids_for_vm
(149),
1501 vm_config
=> $vm_configs->{149},
1508 name
=> '149_storage_migrate_fail',
1515 'with-local-disks' => 1,
1518 'storage_migrate' => 'local-lvm:vm-149-disk-0',
1520 expected_calls
=> {},
1521 expect_die
=> "storage_migrate 'local-lvm:vm-149-disk-0' error",
1523 source_volids
=> local_volids_for_vm
(149),
1524 target_volids
=> {},
1525 vm_config
=> $vm_configs->{149},
1533 my $single_test_name = shift;
1535 mkdir $RUN_DIR_PATH;
1537 foreach my $test (@{$tests}) {
1538 my $name = $test->{name
};
1539 next if defined($single_test_name) && $name ne $single_test_name;
1541 my $run_dir = "${RUN_DIR_PATH}/${name}";
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));
1548 my $expect_die = $test->{expect_die
};
1549 my $expected = $test->{expected
};
1551 my $source_volids = local_volids_for_vm
($test->{vmid
});
1552 my $target_volids = $test->{target_volids
} // {};
1554 my $config_patch = $test->{config_patch
};
1555 my $vm_config = get_patched_config
($test->{vmid
}, $test->{config_patch
});
1557 my $fail_config = $test->{fail_config
} // {};
1558 my $storage_migrate_map = $test->{storage_migrate_map
} // {};
1560 if (my $targetstorage = $test->{opts
}->{targetstorage
}) {
1561 $test->{opts
}->{storagemap
} = PVE
::JSONSchema
::parse_idmap
($targetstorage, 'pve-storage-id');
1564 my $migrate_params = {
1565 target
=> $test->{target
},
1566 vmid
=> $test->{vmid
},
1567 opts
=> $test->{opts
},
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));
1580 $ENV{QM_LIB_PATH
} = $QM_LIB_PATH;
1581 $ENV{RUN_DIR_PATH
} = $run_dir;
1582 my $exitcode = run_command
([
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"} );
1589 if (defined($expect_die) && $exitcode) {
1590 my $log = file_get_contents
("${run_dir}/log");
1591 my @lines = split /\n/, $log;
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/;
1600 note
("expected error message is not present in log");
1602 } elsif (defined($expect_die) && !$exitcode) {
1604 note
("mocked migrate call didn't fail, but it was expected to - check log");
1605 } elsif (!defined($expect_die) && $exitcode) {
1607 note
("mocked migrate call failed, but it was not expected - check log");
1610 my $expected_calls = decode_json
(file_get_contents
("${run_dir}/expected_calls"));
1611 foreach my $call (keys %{$expected_calls}) {
1613 note
("expected call '$call' was not made");
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}) {
1620 note
("drive '$drive' was not mirrored");
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")),
1631 is_deeply
($actual, $expected, $name);